Problem with unlinking file in case sensitive system - c++

I have a function that i'm running on my windows against case sensitive remote server (SMB).
The function creates two files: "fileA", "FILEa".
When i'm trying to unlink the file "fileA" both of my files disappear from the folder.
Right after that i'm calling for unlink file "FILEa",and get error that the file does not exist.
My code:
void my_function(Path path)
{
Path filename1 = path;
filename1 + "_fileA";
Path filename2 = path;
filename2 +"_FILEa";
close(open(filename1, O_CREAT | O_EXCL, S_IREAD | S_IWRITE));
try
{
close(open(filename2, O_CREAT | O_EXCL, S_IREAD | S_IWRITE));
}
catch (Exception e)
{
unlink(filename1);
return;
}
unlink(filename1);
unlink(filename2);
}
On wireshark , after Client's unlink , the Client send SMB Find request to query the content of the folder and the server return FILEa in the list.
wireshark capture
It seems that windows has internal caching that handles Opens and fileA and FILEa are mapped to the same entry.
Edit:
View of my folder after creating the two files:
I'm using Windows and the code is in cpp.
Somebody knows why is this happening to me?
Or if there is other function beside unlink that could remove only the chosen file and not both of them?
Thank you.

Related

Opening a file in home directory

Say you have a program you run, and it has the following lines of code:
#include <fstream>
using std::fstream;
int main() {
fstream someFile;
someFile.open("~/someFile");
if(!someFile.is_open()) {
// Make the file
}
}
I'm trying to open a file in the home directory (i.e. "~" on Unix devices). How could this be done? What I'm doing right now doesn't seem to work. Additionally, how can I make the file if it doesn't exist yet?
Note that this program can run from anywhere; not just home, but I need it to look for a file in the home directory.
open has a second parameter: openmode, so you may want something like
someFile.open ("somefile", std::fstream::out | std::fstream::app);
if you want to append.
For the home directory you can check HOME environment variable and getpwuid:
const char *homedir;
if ((homedir = getenv("HOME")) == NULL) {
homedir = getpwuid(getuid())->pw_dir;
}

_open fails with O_TRUNC when file exists and is synced with onedrive

I have found the following behaviour and would like to find out why the function call fails and if there is a fix or workaround.
I have isolated the behaviour with the following minimal C/C++ code snippet
#include<io.h>
int main()
{
char path[] = "C:\\Users\\<my_username>\\OneDrive - <my_employer>\\Documents\\file.bin";
int fh = _open(path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, _S_IREAD | _S_IWRITE);
if (fh >= 0)
{
_write(fh, "somebytes", 9);
_close(fh);
}
else
{
int err = errno;
char* message = strerror(err);
}
return 0;
}
I have removed my username and my employer name from my onedrive folder for anonymity.
If the file does not already exist, then the file is creates a file and filled with the appropriate text as expected.
If the file exists, but has not yet been synced to my onedrive then the file is opened, truncated and filled with the appropriate text as expected.
However, if the file exist and has been synced to my onedrive, the _open call fails and errno is set to EINVAL (invalid argument).
Removing O_TRUNC from the _open call stops the function from failing, but does not have the required behaviour. I.e. the file is not truncated before writing.
It is perhaps worth noting that from the microsoft documentation at https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/open-wopen, EINVAL seems a strange error code to set, given the symptoms.
My OneDrive is version 2021 (Build 21.150.0725.0001 64 bit)
Has anyone experienced this problem before and have a solution or workaround?
In my particular case, code like the snippet above is used as part of the netcdf/hdf5 file format library and this is causing my file writes to fail. Also I have had a problem where I cannot store visual studio projects in my onedrive folder, because once they sync, various files cannot be overwritten during the build process - I now wonder if this is due to the same issue.
Edit - I do not seem to have the same problem on my home PC. Only on my work computer - is the business version of OneDrive built upon Sharepoint? Perhaps this makes a difference if so.
I would suggest that you don't use One Drive to "backup" source code and instead use a source control system - GitHub or Azure Dev Ops both have free versions available

How to check a file is locked in MFC?

I am using MFC CFile.
In windows OS in my application I am locking the file by opening the file with share deny access.
In the same application or process I have to check whether the file is locked or not?
Right now, the only way I know is opening the file and checking GetLastError().
Is there any other solution?
Try to open the file first. If the file exists and is already open without share access, you get a sharing violation
CFileException::sharingViolation.
See CFileException for possible values of CFileException::m_cause
Example:
UINT open_flag = CFile::modeReadWrite | CFile::modeCreate | CFile::modeNoTruncate;
CFileException ex;
if(file.Open(filename, open_flag, &ex))
{
//success
}
else
{
if(ex.m_cause == CFileException::fileNotFound)
{
//file doesn't exit
}
else if(ex.m_cause == CFileException::sharingViolation)
{
//file exists and is locked
}
}
while reading a data from csv file, I got also same errors
In my case,
existed csv file with the same name was open. So, I closed that csv file and it was Okay.
later was the same issue again.
this time, I wrote inappropriate mode while creating
so I changed this code
file.Open(fileName, CFile::modeCreate | CFile::modeReadWrite)
to
file.Open(fileName, CFile::modeCreate | CFile::modeWrite)

Cygwin: Deleting file when handle is opened

I have a file which I want to delete, it's handle is held by system process so everytime I try to delete it it gives Access denied but for some reason cygwin is able to delete it.
I've downloaded the coreutils and investigated the source code of rm executable and found that it uses unlink function to achieve it. I've created a little test program which uses same function but it gives me Access denied anyway.
Then I found this article and guy describes how cygwin is able to delete a file which is the following:
Cygwin opens files always with all sharing flags
set, so a file opened by a Cygwin process should not result in a sharing
violation in another open call. The exception is the first NtOpenFile
in unlink_nt, which opens the file with FILE_SHARE_DELETE only to find
out if the file has an open handle somewhere else. In that case it gets
a STATUS_SHARING_VIOLATION, the next NtOpenFile will open the file with
all sharing flags set, and unlink_nt will try to delete the file or to
rename it, or to move it to the recycle bin, dependent on its path.
Which makes sense, So I started to implement same thing. Here is my code:
HANDLE file;
PIO_STATUS_BLOCK stat;
UNICODE_STRING myUnicodeStr;
RtlInitUnicodeString(&myUnicodeStr, L"C:\\Program Files (x86)\\TSU\\bin\\TSU.sys");
POBJECT_ATTRIBUTES attr;
InitializeObjectAttributes (attr, &myUnicodeStr, OBJ_OPENIF, NULL, NULL);
NtOpenFile(&file, MAXIMUM_ALLOWED, attr, NULL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_DELETE_ON_CLOSE);
NtClose(file);
As you can see I'm trying to open file with sharing flags set and also used FILE_DELETE_ON_CLOSE since I close the handle and I want it to be deleted afterwards.
The problem I have is Segmentation Fault(I'm using cygwin win10) for some reason. Little debugging showed that problem is in InitializeObjectAttributes function for some reason.
P.S
I know it's not the best solution to delete file when it's handle is held by some other process but the main goal is to mimic the rm.exe's behaviour in this way. Hope you can help. Thanks.
under windows not always possible delete file. for example when some process mapping this file as an image
if try delete running EXE file with rm.exe - it first call ZwOpenFile with DesiredAccess = DELETE, ShareAccess = FILE_SHARE_DELETE and OpenOptions = FILE_OPEN_FOR_BACKUP_INTENT. this is ok. than called ZwSetInformationFile with FileDispositionInformation - the DeleteFile from FILE_DISPOSITION_INFORMATION set to TRUE. this call failed with status STATUS_CANNOT_DELETE.
filesystem return STATUS_CANNOT_DELETE exactly from this place:
// Make sure there is no process mapping this file as an image.
if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers,
MmFlushForDelete )) {
DebugTrace(-1, Dbg, "Cannot delete user mapped image\n", 0);
return STATUS_CANNOT_DELETE;
}
than rm.exe again try open file, already with OpenOptions = FILE_OPEN_FOR_BACKUP_INTENT | FILE_DELETE_ON_CLOSE options. but this call of course fail with the same STATUS_CANNOT_DELETE. now error from this point:
// If the user wants to delete on close, we must check at this
// point though.
//
if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {
Fcb->OpenCount += 1;
DecrementFcbOpenCount = TRUE;
if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers,
MmFlushForWrite )) {
Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
STATUS_SHARING_VIOLATION;
try_return( Iosb );
}
}
after this rm.exe again call ZwSetInformationFile already with FileRenameInformation - where RootDirectory from FILE_RENAME_INFORMATION point to volume (on which file located) root (so like \Device\HarddiskVolume<N>\ and FileName point to some path in recycle bin. as result file actually moved but not deleted. rm.exe deceives you

CFile::modeCreate not working as advertised

CFile file;
CFileException fe;
if (file.Open(strPath, CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary, &fe) )
{
}
This doesn't work. The file path provided by strPath already exist but it will not open this file and returns with error code 5. If I do remove the CFile::modeCreateflag than the file is opened fine. The documentation says if the file already exists 'CFile::modeCreate' will attach itself to it and truncate it's to zero but in reality it never opens the file in the first place. Is there an issue with my call?
I resolved this. The problem was that the file had 'ready only' attribute set. I changed it to normal before I open it and that fixed it.
SetFileAttributes(strPath, FILE_ATTRIBUTE_NORMAL);