Fixes https://bugs.winehq.org/show_bug.cgi?id=44310
The following functions have been fixed to correctly report failure when they're unable to create the requested file:
WritePrivateProfileStringA WritePrivateProfileStringW WritePrivateProfileSectionA WritePrivateProfileSectionW WritePrivateProfileStructA WritePrivateProfileStructW
Tested on Ubuntu 16.04. Conformance tests based on work by Fabian Maurer, with some adaptations.
Signed-off-by: Paul Graham development@omega-software.com --- dlls/kernel32/profile.c | 15 ++++++++++----- dlls/kernel32/tests/profile.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/profile.c b/dlls/kernel32/profile.c index aad3ba3..4d6c016 100644 --- a/dlls/kernel32/profile.c +++ b/dlls/kernel32/profile.c @@ -1391,7 +1391,8 @@ BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry, SetLastError(ERROR_FILE_NOT_FOUND); } else { ret = PROFILE_SetString( section, entry, string, FALSE); - PROFILE_FlushFile(); + if (ret) + ret = PROFILE_FlushFile(); } }
@@ -1447,7 +1448,8 @@ BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section, else if (PROFILE_Open( filename, TRUE )) { if (!string) {/* delete the named section*/ ret = PROFILE_SetString(section,NULL,NULL, FALSE); - PROFILE_FlushFile(); + if (ret) + ret = PROFILE_FlushFile(); } else { PROFILE_DeleteAllKeys(section); ret = TRUE; @@ -1456,12 +1458,14 @@ BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section, strcpyW( buf, string ); if((p = strchrW( buf, '='))) { *p='\0'; - ret = PROFILE_SetString( section, buf, p+1, TRUE); + if (ret) + ret = PROFILE_SetString( section, buf, p+1, TRUE); } HeapFree( GetProcessHeap(), 0, buf ); string += strlenW(string)+1; } - PROFILE_FlushFile(); + if (ret) + ret = PROFILE_FlushFile(); } }
@@ -1744,7 +1748,8 @@ BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
if (PROFILE_Open( filename, TRUE )) { ret = PROFILE_SetString( section, key, outstring, FALSE); - PROFILE_FlushFile(); + if (ret) + ret = PROFILE_FlushFile(); }
RtlLeaveCriticalSection( &PROFILE_CritSect ); diff --git a/dlls/kernel32/tests/profile.c b/dlls/kernel32/tests/profile.c index 2eb90a8..17ba124 100644 --- a/dlls/kernel32/tests/profile.c +++ b/dlls/kernel32/tests/profile.c @@ -25,6 +25,7 @@ #include "windef.h" #include "winbase.h" #include "windows.h" +#include "sddl.h"
#define KEY "ProfileInt" #define SECTION "Test" @@ -534,6 +535,41 @@ static BOOL emptystr_ok(CHAR emptystr[MAX_PATH]) return TRUE; }
+static void test_profile_directory_readonly(void) +{ + BOOL ret; + CHAR path_folder[MAX_PATH]; + CHAR path_file[MAX_PATH]; + const char *sddl_string_everyone_readonly = "D:PAI(A;;0x1200a9;;;WD)"; + SECURITY_ATTRIBUTES attributes = {0}; + char lpStruct[] = { 's', 't', 'r', 'i', 'n', 'g' }; + + attributes.nLength = sizeof(attributes); + ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(sddl_string_everyone_readonly, SDDL_REVISION_1, &attributes.lpSecurityDescriptor, NULL); + ok(ret == TRUE, "ConvertStringSecurityDescriptorToSecurityDescriptor failed: %d\n", GetLastError()); + + GetTempPathA(MAX_PATH, path_folder); + lstrcatA(path_folder, "wine-test"); + + strcpy(path_file, path_folder); + lstrcatA(path_file, "\tmp.ini"); + + ret = CreateDirectoryA(path_folder, &attributes); + ok(ret == TRUE, "CreateDirectoryA failed: %d\n", GetLastError()); + + ret = WritePrivateProfileStringA("App", "key", "string", path_file); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + + ret = WritePrivateProfileSectionA("App", "key=string", path_file); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + + ret = WritePrivateProfileStructA("App", "key", lpStruct, sizeof(lpStruct), path_file); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + + ret = RemoveDirectoryA(path_folder); + ok(ret == TRUE, "RemoveDirectoryA failed: %d\n", GetLastError()); +} + static void test_GetPrivateProfileString(const char *content, const char *descript) { DWORD ret, len; @@ -1132,6 +1168,7 @@ START_TEST(profile) test_profile_existing(); test_profile_delete_on_close(); test_profile_refresh(); + test_profile_directory_readonly(); test_GetPrivateProfileString( "[section1]\r\n" "name1=val1\r\n"