How to tell if a path is a file or a directory without elevated privileges
我有一个没有提升特权的进程,因此,我无法获得某些文件/目录的File属性。
1
| const auto attr = GetFileAttributesW(path); |
要么
1 2
| auto *pwfd = new WIN32_FIND_DATAW;
const auto handle = FindFirstFileW(path, pwfd); |
在这两种情况下,我都无法访问文件属性是有道理的(因为我没有提升的特权)
但是我只需要知道path是文件还是目录。
有没有办法知道有效路径是没有提升特权的文件还是目录?
编辑这不是"如何确定给定路径是目录还是文件"的副本。 (例如,C / C ++),我已经知道如何获取文件属性。
我想知道是否该路径是没有提升特权的文件/目录。
-
如何确定给定路径是目录还是文件的可能重复项? (C / C ++)
-
不,它不是重复的,我在问题中提到了GetFileAttributesW。我在问提升特权。不一样
-
您是否看到以下链接:forum.codecall.net/topic/68935-how-to-test-if-file-or-direct ory?
-
@SimonGoodman如果您没有访问路径的权限,则可能无法使用。
-
GetFileAttributesW返回的错误(更好的状态)是什么?您无权访问父文件夹吗?
-
我应该提到提升的特权("以管理员身份运行")与文件访问控制不同。
-
您如何获得path?仅当您对父文件夹没有读权限时,GetFileAttributesW才能失败。
-
@RbMm,我从ReadDirectoryChangesW获取文件/目录,当我执行修改后的操作时,无法分辨它是在文件还是文件夹上。
-
GetFileAttributesW返回的错误是什么?分享违规? FindFirstFileW返回的错误是什么?
-
FindFirstFileW在这里更强大,因为GetFileAttributesW可以返回ERROR_SHARING_VIOLATION,但是在这种情况下FindFirstFileW可以-您需要的所有内容-访问父文件夹以进行读取
-
@SimonGoodman最好您发布一个最小的可复制示例,以说明您要做什么,而不是在评论中进行冗长的讨论。这可能会为解决您的实际问题提供一个很好的答案。
-
@RbMm它返回ERROR_ACCESS_DENIED,我还应该指出,有时(但不总是),GetFileAttributesW返回ERROR_ACCESS_DENIED,其中FindFirstFileW能够返回有效属性。
-
GetFileAttributesW返回ERROR_ACCESS_DENIED,其中FindFirstFileW能够返回有效属性-对此非常怀疑。对于GetFileAttributesW,我们只需要FILE_READ_ATTRIBUTES访问。但这是特殊的访问权限-如果呼叫者对父级具有FILE_LIST_DIRECTORY访问权限,则ntfs会授予它访问权限。但是如果您没有此访??问权限-FindFirstFileW将失败
-
我刚刚对其进行了测试,如果文件处于临时折叠状态,我会从GetFileAttributesW中得到一些ERROR_ACCESS_DENIED,但随后FindFirstFileW成功返回了文件属性。
-
这可能是因为文件被删除-有人调用DeleteFile,但仍然存在打开文件句柄。在这种情况下,对文件的任何访问都会返回拒绝访问错误,但是FindFirstFileW仍然能够返回有效属性。但是您说在某些情况下FindFirstFileW也会失败。也具有拒绝访问权限吗?可能与找不到文件错误有关?
-
是的,当它在FindFirstFileW上失败时,出于相同的原因,在ERROR_ACCESS_DENIED上,我忽略了文件未找到错误(因为无论如何我再也无法确定它是否是文件/目录)。
-
还调用RtlGetLastNtStatus()而不是GetLastError()(此api信息不足)-我几乎确定在GetFileAttributes失败后您得到了STATUS_DELETE_PENDING
-
FindFirstFileW失败,访问被拒绝(也调用RtlGetLastNtStatus()以获得更准确的信息-确实win32错误5并不总是访问被拒绝)-可能您只是没有对文件夹的读取权限。您可以尝试打开父文件夹来进行检查。在呼叫ReadDirectoryChanges bWatchSubtree中是真的吗?如果是-可能您确实无权访问文件夹
-
因此,我强烈建议文件api失败后再调用RtlGetLastNtStatus()。 如果在GetFileAttributes失败后返回STATUS_DELETE_PENDING,则表示正在删除文件。 这与任何特权无关。 但是FindFirstFileEx(始终称为Ex版本!)仍然可以获取属性(如果文件仍然存在)。
首先,GetLastError返回的ERROR_ACCESS_DENIED并不总是意味着访问被拒绝错误。通常(但并非总是)错误源-是NTSTATUS代码,由本机api返回,然后通过RtlNtStatusToDosError转换为win32错误代码。但是这种转换不是内射的。许多不同的NTSTATUS代码不仅转换为STATUS_ACCESS_DENIED,而且转换为相同的ERROR_ACCESS_DENIED,结果经常导致关于真正错误原因的混淆。如果GetFileAttributes,FindFirstFileExW无法更好地调用
1
| extern"C" NTSYSAPI ULONG NTAPI RtlGetLastNtStatus(); |
api,而不是GetLastError()。这没有记录,但是在某些情况下很有帮助。
现在关于具体的GetFileAttributesW-我们需要对文件具有FILE_READ_ATTRIBUTES访问权限,以免访问失败而被拒绝。但是文件系统将FILE_READ_ATTRIBUTES授予调用者,或者如果文件安全描述符授予了它,则父文件夹是否授予了调用者FILE_LIST_DIRECTORY。当然,如果我们同时没有为父文件夹提供FILE_LIST_DIRECTORY且为文件和调用者提供的FILE_READ_ATTRIBUTES都没有SeBackupPrivilege(此特权将导致系统将所有文件的读取访问控制权授予任何文件,而不管访问控制列表(ACL )为文件指定的内容。)-此处无法执行任何操作。
但在具体情况下,我想op确实不是STATUS_ACCESS_DENIED而是STATUS_DELETE_PENDING错误。如果有人调用DeleteFile但文件上仍然存在打开的句柄,则会出现此错误:
The DeleteFile function marks a file for deletion on close.
Therefore, the file deletion does not occur until the last handle to
the file is closed. Subsequent calls to CreateFile to open the file
fail with ERROR_ACCESS_DENIED.
(在这种情况下,NTSTATUS代码当然会是STATUS_DELETE_PENDING,但RtlNtStatusToDosError会将其转换为ERROR_ACCESS_DENIED)
因此GetFileAttributes可能失败的可能原因是该文件在关闭时被标记为删除。但如果文件仍未删除,则可以通过FindFirstFileExW获取它的属性。注意-FindFirstFileExW返回有关父文件夹中文件属性的信息。对于调用此api,我们仅需要FILE_LIST_DIRECTORY访问父文件夹。这就是为什么如果父文件夹有FILE_LIST_DIRECTORY的情况,文件系统会为文件授予FILE_READ_ATTRIBUTES的原因。如果在页面文件上调用GetFileAttributes,它也会因错误STATUS_SHARING_VIOLATION而失败(当然是非常特殊的情况)。如果我们没有对父文件夹的FILE_LIST_DIRECTORY访问权限(并且未启用备份权限)-FindFirstFileExW也会失败,因此无法执行任何操作。
因此,在关闭时标记为要删除的文件时,可能的解决方案(不会失败)-在这种情况下调用FindFirstFileExW。请注意,FindFirstFileExW调用比GetFileAttributes昂贵得多,从另一方面来看,当我们查询标记为删除的文件时非常罕见。因此始终最好先调用GetFileAttributes,并且仅当失败并使用代码STATUS_DELETE_PENDING失败时才尝试FindFirstFileExW调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| NTSTATUS GetFileAttributesEx(PCWSTR FileName, DWORD* pdwFileAttributes)
{
DWORD dwFileAttributes = GetFileAttributes(FileName);
if (INVALID_FILE_ATTRIBUTES != dwFileAttributes)
{
*pdwFileAttributes = dwFileAttributes;
return STATUS_SUCCESS;
}
NTSTATUS status = RtlGetLastNtStatus();
switch (status)
{
case STATUS_SHARING_VIOLATION: // this is only for pagefile i think can be
case STATUS_DELETE_PENDING:
WIN32_FIND_DATAW fd;
HANDLE hFile = FindFirstFileExW(FileName, FindExInfoBasic, &fd, FindExSearchNameMatch, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
*pdwFileAttributes = fd.dwFileAttributes;
FindClose(hFile);
status = STATUS_SUCCESS;
}
else
{
status = RtlGetLastNtStatus();
}
break;
}
return status;
} |
演示代码进行测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| ULONG cb = 0, rcb = 0x80;
static volatile UCHAR guz = 0;
PVOID stack = alloca(guz);
PWSTR FileName = 0;
do
{
if (cb < rcb)
{
cb = (ULONG)((PWSTR)stack - (FileName = (PWSTR)alloca((rcb - cb)* sizeof(WCHAR))));
}
rcb = ExpandEnvironmentStringsW(L"%tmp%/test.tmp", FileName, cb);
} while (cb < rcb);
if (rcb)
{
HANDLE hFile = CreateFile(FileName, DELETE, 0, 0, CREATE_NEW,
FILE_ATTRIBUTE_TEMPORARY|FILE_ATTRIBUTE_HIDDEN|FILE_FLAG_DELETE_ON_CLOSE, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
ULONG dwFileAttributes;
GetFileAttributesEx(FileName, &dwFileAttributes);
static FILE_DISPOSITION_INFO fdi = { TRUE };
SetFileInformationByHandle(hFile, FileDispositionInfo, &fdi, sizeof(fdi));
GetFileAttributesEx(FileName, &dwFileAttributes);
CloseHandle(hFile);
GetFileAttributesEx(FileName, &dwFileAttributes);
}
} |