I'm trying to figure out how to check if a directory can be changed to without actually changing to the directory.
On a posix system I would do:
if (access("/some/path", X_OK) == 0) {
// okay!
}
If only Windows was so simple ....
I've taken a look at the documentation or GetFileSecurity, but I can't seem to wrap my head around Windows ACLs and what I actually have to check for to ensure a directory can be changed to.
The only way to be sure if an operation will succeed is to actually try the operation.
However, SetCurrentDirectory will fail if you don't have FILE_TRAVERSE or SYNCHRONIZE permissions for the folder in question. So you can test this using CreateFile without actually changing the directory.
bool TestForSetCurrentDirPermission(LPCWSTR pszDir)
{
HANDLE hDir = CreateFile(pszDir, FILE_TRAVERSE | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hDir != INVALID_HANDLE_VALUE) CloseHandle(hDir);
return hDir != INVALID_HANDLE_VALUE;
}
Related
I'm working on a product where OpenFileById() fails with ERROR_ACCESS_DENIED on files and folders that are otherwise accessible (meaning a CreateFile() on the same file or folder specified by path with the same access level / share mode, etc. succeeds).
I'm using backup semantics so I could also get a handle to folders; SE_BACKUP_NAME and SE_RESTORE_NAME privileges are enabled. This code works everywhere else other than this one machine (Windows 8.1).
The process is running as a service under local system, I tried having them change that to a different account with admin privileges and that didn't work either. Files / folders in question haven't been open for deletion (which is one case when this function will fail with ERROR_ACCESS_DENIED as per documentation).
I don't have physical access to this machine so can't kernel debug or anything like that. Has anyone run into this before?
Here's what I'm trying to do in a nutshell:
hRoot = ::CreateFileA(szRootPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hRoot != INVALID_HANDLE_VALUE)
{
FILE_ID_DESCRIPTOR fileId;
fileId.dwSize = sizeof(fileId);
fileId.Type = FileIdType;
fileId.FileId.QuadPart = nId;
hFile = ::OpenFileById(hRoot, &fileId, SYNCHRONIZE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, FILE_FLAG_BACKUP_SEMANTICS);
if (hFile != INVALID_HANDLE_VALUE)
{
...
::CloseHandle(hFile);
}
::CloseHandle(hRoot);
}
Apparently this is caused by a third party software product's kernel components (can't really go into specifics)
So I'm trying to simulate a distant file opening, which is pointing back to my computer, however i keep failing with error 3 (FILE_NOT_FOUND). I went through the following documentation regarding network usage, but it didn't work either.
hFile1 = ::CreateFile(LR"(\\172.17.12.172\C$\Develop\Code\File.txt)", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (INVALID_HANDLE_VALUE == hFile1)
{
LOG_ERROR(L"Failed opening file with: " << GetLastError());
break;
}
The FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE flags are for the GetFileInformationByHandle which is used later on, i compare file paths.
I tried opening \\172.17.12.172\C$\Develop\Code\File.txt using notepad, it worked.
172.17.12.172 is my local ip address.
The syntax of your file name is fine. That the error code is FILE_NOT_FOUND rather than some other error means that the directory is found, but no file within that directory can be located.
You should be able to open a file with a path of that form using CreateFile. If you really can open the file with that path using Notepad, then you will be able to do the same using CreateFile, so long as you pass the same file name.
So the most plausible explanation is that you simply made a typographical error. I see no reason to look beyond the obvious conclusion suggested by FILE_NOT_FOUND. There is no file of that name.
When I'm using
time_t t = last_write_time("C:\\System Volume Information");
I get the following exception:
boost::filesystem::last_write_time: Access denied: "C:\System Volume Information"
Nevertheless, Windows Explorer is able to get access to that information. It looks like Boost requires extra access to the folder, and that's the reason the code doesn't work.
Is it possible to make a workaround somehow?
Edit. Here's a citation from libs\filesystem\src\operations.cpp:1312:
handle_wrapper hw(
create_file_handle(p.c_str(), 0,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
I don't see what's wrong with it yet.
That folder is off limits even to users with an Admin account, it contains restore points. Not that you couldn't change the ACL with such an account but that is of course not the correct solution. Trying to open a handle on the directory is too heavy-handed, use FindFirstFile() instead. Like this:
WIN32_FIND_DATA info;
auto hdl = FindFirstFile(L"C:\\System Volume Information", &info);
if (hdl == INVALID_HANDLE_VALUE) throw win32_error(GetLastError());
SYSTEMTIME time;
FileTimeToSystemTime(&info.ftLastWriteTime, &time);
// etc..
//...
FindClose(hdl);
I have admin rights and have no problem getting a valid handle and ultimately reading an entire hard drive via:
IntPtr handle = CreateFile(#"\\.\PHYSICALDRIVE1", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
I can also get a valid handle when I try to open a directory of that drive:
IntPtr handle = CreateFile(#"\\.\Z:\\", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
But I cannot get a valid handle when I try to simply open a partition of that drive:
IntPtr handle = CreateFile(#"\\.\Z:", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
GetLastWin32Error returns access denied (5).
Of course if I offline the drive, then I get "The system cannot find the file specified."
I've tried everything I could think of with different partitions, different options etc. to no available.
I found the answer myself. Let me correct myself in pointing out that CreateFile(#"\.\Z:" is opening a Volume, not necessarily a partition. However, I could not even open a volume.
Until I added FILE_SHARE_WRITE to the options as follows:
IntPtr handle = CreateFile(#"\.\Z:", GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
That was the key to getting a valid handle. This is certainly not intuitive!
Why this should be the case is only known by Microsoft I guess.
I would like to point out that the documentation of CreateFile says the following about FILE_SHARE_WRITE:
Enables subsequent open operations on a file or device to request write access.
Otherwise, other processes cannot open the file or device if they request write access.
If this flag is not specified, but the file or device has been opened for write access or has a file mapping with write access, the function fails.
I am trying to write a C++/WinAPI code to change a monitor brightness. The code must be compatible with Windows XP so I can't use APIs like SetMonitorBrightness. So I thought to try out IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS but I can't seem to even get a device handle.
HANDLE hDevice = ::CreateFile(_T("\\\\.\\LCD"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0, NULL);
if(hDevice != INVALID_HANDLE_VALUE)
{
//Do work here
::CloseHandle(hDevice);
}
else
{
nOSErr = ::GetLastError();
//Get code 2
}
I tried various combinations of GENERIC_READ, GENERIC_WRITE and FILE_SHARE_READ, FILE_SHARE_WRITE flags but I always get error code 2 when CreateFile is called.
So what am I doing wrong here?
You know that not all devices support this API, right? Your laptop probably supports it because it allows software adjustment of its screen brightness, perhaps even with function keys on the keyboard. Your other machine (the one running Windows 7) probably doesn't support it, so calling CreateHandle with \\\\.\\LCD doesn't get you anything useful. It has nothing to do with the operating system and everything to do with the hardware and/or the video drivers.