Replaced chmod with safer fchmod

* Use fchmod so the file may not change underneath
* Add unit tests for SetFileAttributesA
* Add warning logs for unsupported flags
This commit is contained in:
Armin Novak 2021-09-06 09:07:57 +02:00 committed by akallabeth
parent 64403d9d40
commit c8571dd5fd
3 changed files with 231 additions and 7 deletions

View File

@ -539,15 +539,80 @@ DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
return ret;
}
static char* append(char* buffer, size_t size, const char* append)
{
const size_t len = strnlen(buffer, size);
if (len == 0)
_snprintf(buffer, size, "%s", append);
else
{
strcat(buffer, "|");
strcat(buffer, append);
}
return buffer;
}
static const char* flagsToStr(char* buffer, size_t size, DWORD flags)
{
char strflags[32] = { 0 };
if (flags & FILE_ATTRIBUTE_READONLY)
append(buffer, size, "FILE_ATTRIBUTE_READONLY");
if (flags & FILE_ATTRIBUTE_HIDDEN)
append(buffer, size, "FILE_ATTRIBUTE_HIDDEN");
if (flags & FILE_ATTRIBUTE_SYSTEM)
append(buffer, size, "FILE_ATTRIBUTE_SYSTEM");
if (flags & FILE_ATTRIBUTE_DIRECTORY)
append(buffer, size, "FILE_ATTRIBUTE_DIRECTORY");
if (flags & FILE_ATTRIBUTE_ARCHIVE)
append(buffer, size, "FILE_ATTRIBUTE_ARCHIVE");
if (flags & FILE_ATTRIBUTE_DEVICE)
append(buffer, size, "FILE_ATTRIBUTE_DEVICE");
if (flags & FILE_ATTRIBUTE_NORMAL)
append(buffer, size, "FILE_ATTRIBUTE_NORMAL");
if (flags & FILE_ATTRIBUTE_TEMPORARY)
append(buffer, size, "FILE_ATTRIBUTE_TEMPORARY");
if (flags & FILE_ATTRIBUTE_SPARSE_FILE)
append(buffer, size, "FILE_ATTRIBUTE_SPARSE_FILE");
if (flags & FILE_ATTRIBUTE_REPARSE_POINT)
append(buffer, size, "FILE_ATTRIBUTE_REPARSE_POINT");
if (flags & FILE_ATTRIBUTE_COMPRESSED)
append(buffer, size, "FILE_ATTRIBUTE_COMPRESSED");
if (flags & FILE_ATTRIBUTE_OFFLINE)
append(buffer, size, "FILE_ATTRIBUTE_OFFLINE");
if (flags & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
append(buffer, size, "FILE_ATTRIBUTE_NOT_CONTENT_INDEXED");
if (flags & FILE_ATTRIBUTE_ENCRYPTED)
append(buffer, size, "FILE_ATTRIBUTE_ENCRYPTED");
if (flags & FILE_ATTRIBUTE_VIRTUAL)
append(buffer, size, "FILE_ATTRIBUTE_VIRTUAL");
_snprintf(strflags, sizeof(strflags), " [0x%08" PRIx32 "]", flags);
strcat(buffer, strflags);
return buffer;
}
BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
{
struct stat st;
int fd;
BOOL rc = FALSE;
if (stat(lpFileName, &st) != 0)
if (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)
{
return FALSE;
char buffer[8192] = { 0 };
const char* flags =
flagsToStr(buffer, sizeof(buffer), dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
WLog_WARN(TAG, "[%s] Unsupported flags %s, ignoring!", __FUNCTION__, flags);
}
fd = open(lpFileName, O_RDONLY);
if (fd < 0)
return FALSE;
if (fstat(fd, &st) != 0)
goto fail;
if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
{
st.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
@ -557,12 +622,13 @@ BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
st.st_mode |= S_IWUSR;
}
if (chmod(lpFileName, st.st_mode) != 0)
{
return FALSE;
}
if (fchmod(fd, st.st_mode) != 0)
goto fail;
return TRUE;
rc = TRUE;
fail:
close(fd);
return rc;
}
BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
@ -570,6 +636,14 @@ BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
BOOL ret;
LPSTR lpCFileName;
if (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)
{
char buffer[8192] = { 0 };
const char* flags =
flagsToStr(buffer, sizeof(buffer), dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
WLog_WARN(TAG, "[%s] Unsupported flags %s, ignoring!", __FUNCTION__, flags);
}
if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpCFileName, 0, NULL, NULL) <= 0)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);

View File

@ -9,6 +9,7 @@ if (NOT WIN32)
TestFileCreateFile.c
TestFileDeleteFile.c
TestFileReadFile.c
TestSetFileAttributes.c
TestFileWriteFile.c
TestFilePatternMatch.c
TestFileFindFirstFile.c

View File

@ -0,0 +1,149 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/path.h>
#include <winpr/handle.h>
#include <winpr/windows.h>
#include <winpr/sysinfo.h>
static const DWORD allflags[] = {
0,
FILE_ATTRIBUTE_READONLY,
FILE_ATTRIBUTE_HIDDEN,
FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_DIRECTORY,
FILE_ATTRIBUTE_ARCHIVE,
FILE_ATTRIBUTE_DEVICE,
FILE_ATTRIBUTE_NORMAL,
FILE_ATTRIBUTE_TEMPORARY,
FILE_ATTRIBUTE_SPARSE_FILE,
FILE_ATTRIBUTE_REPARSE_POINT,
FILE_ATTRIBUTE_COMPRESSED,
FILE_ATTRIBUTE_OFFLINE,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
FILE_ATTRIBUTE_ENCRYPTED,
FILE_ATTRIBUTE_VIRTUAL,
FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE |
FILE_ATTRIBUTE_NORMAL,
FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | FILE_ATTRIBUTE_REPARSE_POINT |
FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_OFFLINE,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_VIRTUAL
};
static BOOL test_SetFileAttributesA(void)
{
BOOL rc = FALSE;
HANDLE handle;
DWORD x;
const DWORD flags[] = { 0, FILE_ATTRIBUTE_READONLY };
char* name = GetKnownSubPath(KNOWN_PATH_TEMP, "afsklhjwe4oq5iu432oijrlkejadlkhjaklhfdkahfd");
if (!name)
goto fail;
for (x = 0; x < ARRAYSIZE(allflags); x++)
{
const DWORD flag = allflags[x];
rc = SetFileAttributesA(NULL, flag);
if (rc)
goto fail;
rc = SetFileAttributesA(name, flag);
if (rc)
goto fail;
}
handle = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE)
goto fail;
CloseHandle(handle);
for (x = 0; x < ARRAYSIZE(flags); x++)
{
DWORD attr;
const DWORD flag = flags[x];
rc = SetFileAttributesA(name, flag);
if (!rc)
goto fail;
attr = GetFileAttributesA(name);
if (flag != 0)
{
if ((attr & flag) == 0)
goto fail;
}
}
fail:
DeleteFileA(name);
free(name);
return rc;
}
static BOOL test_SetFileAttributesW(void)
{
BOOL rc = FALSE;
WCHAR* name = NULL;
HANDLE handle;
DWORD x;
const DWORD flags[] = { 0, FILE_ATTRIBUTE_READONLY };
char* base = GetKnownSubPath(KNOWN_PATH_TEMP, "afsklhjwe4oq5iu432oijrlkejadlkhjaklhfdkahfd");
if (!base)
goto fail;
ConvertToUnicode(CP_UTF8, 0, base, -1, &name, 0);
for (x = 0; x < ARRAYSIZE(allflags); x++)
{
const DWORD flag = allflags[x];
rc = SetFileAttributesW(NULL, flag);
if (rc)
goto fail;
rc = SetFileAttributesW(name, flag);
if (rc)
goto fail;
}
handle = CreateFileW(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE)
goto fail;
CloseHandle(handle);
for (x = 0; x < ARRAYSIZE(flags); x++)
{
DWORD attr;
const DWORD flag = flags[x];
rc = SetFileAttributesW(name, flag);
if (!rc)
goto fail;
attr = GetFileAttributesW(name);
if (flag != 0)
{
if ((attr & flag) == 0)
goto fail;
}
}
fail:
DeleteFileW(name);
free(name);
free(base);
return rc;
}
int TestSetFileAttributes(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!test_SetFileAttributesA())
return -1;
if (!test_SetFileAttributesW())
return -1;
return 0;
}