This series improves Wine's support for delete-on-close flag and delete disposition information on files: - adapts tests for Windows 10 - extend and fix some tests - implement some missing features in ntdll & server
-- v2: server: Let file creation fail depending unlink status. server: Propagate the unlink status to all opened/closed files. ntdll: Query FILE_STANDARD_INFORMATION.DeletePending from server. ntdll: Extend file tests about delete-on-close and disposition. ntdll: Fix share mode for some delete-on-close/delete disposition tests. ntdll: Adapt file tests on delete-on-close / delete disposition to Windows 10.
From: Eric Pouech eric.pouech@gmail.com
Fix a couple of failures on Windows 10: - it seems that attributes are no longer accessible by name after shared deletion - really looks like that shared deletion is now marked at object's name hierarchy level (see error codes have changed too)
So, - replace tests based on GetFileAttribute with testing presence of pending deletion flag (FileStandardInformation) - add Win10 error codes (and mark the Win7/8 ones as broken)
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/ntdll/tests/file.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 98d9e6b3b0a..7b6cf704971 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2957,6 +2957,7 @@ static void test_file_disposition_information(void) NTSTATUS res; IO_STATUS_BLOCK io; FILE_DISPOSITION_INFORMATION fdi; + FILE_STANDARD_INFORMATION fsi; BOOL fileDeleted; DWORD fdi2, size; void *view; @@ -3141,18 +3142,23 @@ static void test_file_disposition_information(void) GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, 0, 0); ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); fileDeleted = DeleteFileA( buffer ); ok( fileDeleted, "File should have been deleted\n" ); - fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - ok( !fileDeleted, "File shouldn't have been deleted\n" ); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + todo_wine + ok(fsi.DeletePending, "Handle should be marked for deletion\n"); res = nt_get_file_attrs( buffer, &fdi2 ); todo_wine - ok( res == STATUS_DELETE_PENDING, "got %#lx\n", res ); + ok( res == STATUS_OBJECT_NAME_NOT_FOUND || broken(res == STATUS_DELETE_PENDING), "got %#lx\n", res ); /* can't open the deleted file */ handle2 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); ok( handle2 == INVALID_HANDLE_VALUE, "CreateFile should fail\n" ); todo_wine - ok(GetLastError() == ERROR_ACCESS_DENIED, "got %lu\n", GetLastError()); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || broken(GetLastError() == ERROR_ACCESS_DENIED), "got %lu\n", GetLastError()); CloseHandle( handle ); fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( fileDeleted, "File should have been deleted\n" ); @@ -3190,19 +3196,24 @@ static void test_file_disposition_information(void) ok( CreateDirectoryA( buffer, NULL ), "CreateDirectory failed\n" ); handle = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); ok( handle != INVALID_HANDLE_VALUE, "failed to open a directory\n" ); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); fileDeleted = RemoveDirectoryA( buffer ); ok( fileDeleted, "Directory should have been deleted\n" ); - fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - ok( !fileDeleted, "Directory shouldn't have been deleted\n" ); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + todo_wine + ok(fsi.DeletePending, "Handle should be marked for deletion\n"); res = nt_get_file_attrs( buffer, &fdi2 ); todo_wine - ok( res == STATUS_DELETE_PENDING, "got %#lx\n", res ); + ok( res == STATUS_OBJECT_NAME_NOT_FOUND || broken(res == STATUS_DELETE_PENDING), "got %#lx\n", res ); /* can't open the deleted directory */ handle2 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); todo_wine ok( handle2 == INVALID_HANDLE_VALUE, "CreateFile should fail\n" ); todo_wine - ok(GetLastError() == ERROR_ACCESS_DENIED, "got %lu\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || broken(GetLastError() == ERROR_ACCESS_DENIED), "got %lu\n", GetLastError()); if (handle2 != INVALID_HANDLE_VALUE) CloseHandle( handle2 ); CloseHandle( handle ); fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/ntdll/tests/file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 7b6cf704971..2ec61f72aa9 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3155,10 +3155,13 @@ static void test_file_disposition_information(void) todo_wine ok( res == STATUS_OBJECT_NAME_NOT_FOUND || broken(res == STATUS_DELETE_PENDING), "got %#lx\n", res ); /* can't open the deleted file */ - handle2 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); + handle2 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + todo_wine ok( handle2 == INVALID_HANDLE_VALUE, "CreateFile should fail\n" ); todo_wine ok( GetLastError() == ERROR_FILE_NOT_FOUND || broken(GetLastError() == ERROR_ACCESS_DENIED), "got %lu\n", GetLastError()); + if (handle2 != INVALID_HANDLE_VALUE) + CloseHandle( handle2); CloseHandle( handle ); fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( fileDeleted, "File should have been deleted\n" );
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/ntdll/tests/file.c | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 2ec61f72aa9..6186afdfb63 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3000,6 +3000,10 @@ static void test_file_disposition_information(void) fdi.DoDeleteFile = TRUE; res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation ); ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %lx)\n", res ); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + todo_wine + ok(fsi.DeletePending, "Handle should be marked for deletion\n"); CloseHandle( handle ); fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( fileDeleted, "File should have been deleted\n" ); @@ -3408,6 +3412,68 @@ static void test_file_disposition_information(void) res = DeleteFileA( buffer ); ok( !res, "expected failure\n" ); ok( GetLastError() == ERROR_FILE_NOT_FOUND, "got error %lu\n", GetLastError() ); + + /* pending delete flag is shared across handles */ + GetTempFileNameA( tmp_path, "dis", 0, buffer ); + handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, 0, 0); + ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); + handle2 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + ok( handle2 != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + res = NtQueryInformationFile(handle2, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); + fdi.DoDeleteFile = TRUE; + res = NtSetInformationFile(handle, &io, &fdi, sizeof(fdi), FileDispositionInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + res = NtQueryInformationFile(handle2, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + todo_wine + ok(fsi.DeletePending, "Handle should be marked for deletion\n"); + fdi.DoDeleteFile = FALSE; + res = NtSetInformationFile(handle2, &io, &fdi, sizeof(fdi), FileDispositionInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); + CloseHandle(handle); + CloseHandle(handle2); + res = GetFileAttributesA( buffer ); + todo_wine + ok( res != INVALID_FILE_ATTRIBUTES, "expected file to exist\n" ); + + /* pending delete flag is shared across handles (even after closing) */ + GetTempFileNameA( tmp_path, "dis", 0, buffer ); + handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, 0, 0); + ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); + handle2 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + ok( handle2 != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + res = NtQueryInformationFile(handle2, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); + fdi.DoDeleteFile = TRUE; + res = NtSetInformationFile(handle, &io, &fdi, sizeof(fdi), FileDispositionInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + res = NtQueryInformationFile(handle2, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + todo_wine + ok(fsi.DeletePending, "Handle should be marked for deletion\n"); + fdi.DoDeleteFile = FALSE; + res = NtSetInformationFile(handle2, &io, &fdi, sizeof(fdi), FileDispositionInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + CloseHandle(handle2); + res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); + ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); + CloseHandle(handle); + res = GetFileAttributesA( buffer ); + todo_wine + ok( res != INVALID_FILE_ATTRIBUTES, "expected file to exist\n" ); }
static void test_file_name_information(void)
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/ntdll/tests/file.c | 3 ++- dlls/ntdll/unix/file.c | 11 +++++++---- server/fd.c | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 6186afdfb63..1a4b306a9da 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3002,7 +3002,6 @@ static void test_file_disposition_information(void) ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %lx)\n", res ); res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); - todo_wine ok(fsi.DeletePending, "Handle should be marked for deletion\n"); CloseHandle( handle ); fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -3437,6 +3436,7 @@ static void test_file_disposition_information(void) ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + todo_wine ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); CloseHandle(handle); CloseHandle(handle2); @@ -3469,6 +3469,7 @@ static void test_file_disposition_information(void) CloseHandle(handle2); res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); + todo_wine ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); CloseHandle(handle); res = GetFileAttributesA( buffer ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 6b73d9dc7e8..7c64938c478 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4344,12 +4344,13 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, case FileStandardInformation: { FILE_STANDARD_INFORMATION *info = ptr; + FILE_DISPOSITION_INFORMATION fdi;
if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); - else + else if (!(status = server_get_file_info( handle, io, &fdi, sizeof(fdi), FileDispositionInformation))) { fill_file_info( &st, attr, info, class ); - info->DeletePending = FALSE; /* FIXME */ + info->DeletePending = fdi.DoDeleteFile; } } break; @@ -4378,17 +4379,19 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, case FileAllInformation: { FILE_ALL_INFORMATION *info = ptr; + FILE_DISPOSITION_INFORMATION fdi; char *unix_name;
if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; - else if (!(status = server_get_unix_name( handle, &unix_name ))) + else if (!(status = server_get_unix_name( handle, &unix_name )) && + !(status = server_get_file_info( handle, io, &fdi, sizeof(fdi), FileDispositionInformation))) { LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
fill_file_info( &st, attr, info, FileAllInformation ); - info->StandardInformation.DeletePending = FALSE; /* FIXME */ + info->StandardInformation.DeletePending = fdi.DoDeleteFile; info->EaInformation.EaSize = 0; info->AccessInformation.AccessFlags = 0; /* FIXME */ info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR ); diff --git a/server/fd.c b/server/fd.c index eaebe044f37..e11a66ce625 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2391,6 +2391,24 @@ void default_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int set_reply_data( &info, sizeof(info) ); break; } + /* Wine internal, not bound to a direct request from NtQueryInformationFile */ + case FileDispositionInformation: + { + FILE_DISPOSITION_INFORMATION info; + if (get_reply_max_size() < sizeof(info)) + { + set_error( STATUS_INFO_LENGTH_MISMATCH ); + return; + } + if (!fd->closed) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + info.DoDeleteFile = fd->closed->unlink != 0; + set_reply_data( &info, sizeof(info) ); + break; + } default: set_error( STATUS_NOT_IMPLEMENTED ); }
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/ntdll/tests/file.c | 8 -------- server/fd.c | 42 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 1a4b306a9da..b3b6cb79bcf 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3152,7 +3152,6 @@ static void test_file_disposition_information(void) ok( fileDeleted, "File should have been deleted\n" ); res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); - todo_wine ok(fsi.DeletePending, "Handle should be marked for deletion\n"); res = nt_get_file_attrs( buffer, &fdi2 ); todo_wine @@ -3209,7 +3208,6 @@ static void test_file_disposition_information(void) ok( fileDeleted, "Directory should have been deleted\n" ); res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); - todo_wine ok(fsi.DeletePending, "Handle should be marked for deletion\n"); res = nt_get_file_attrs( buffer, &fdi2 ); todo_wine @@ -3429,19 +3427,16 @@ static void test_file_disposition_information(void) ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); res = NtQueryInformationFile(handle2, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); - todo_wine ok(fsi.DeletePending, "Handle should be marked for deletion\n"); fdi.DoDeleteFile = FALSE; res = NtSetInformationFile(handle2, &io, &fdi, sizeof(fdi), FileDispositionInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); - todo_wine ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); CloseHandle(handle); CloseHandle(handle2); res = GetFileAttributesA( buffer ); - todo_wine ok( res != INVALID_FILE_ATTRIBUTES, "expected file to exist\n" );
/* pending delete flag is shared across handles (even after closing) */ @@ -3461,7 +3456,6 @@ static void test_file_disposition_information(void) ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); res = NtQueryInformationFile(handle2, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); - todo_wine ok(fsi.DeletePending, "Handle should be marked for deletion\n"); fdi.DoDeleteFile = FALSE; res = NtSetInformationFile(handle2, &io, &fdi, sizeof(fdi), FileDispositionInformation); @@ -3469,11 +3463,9 @@ static void test_file_disposition_information(void) CloseHandle(handle2); res = NtQueryInformationFile(handle, &io, &fsi, sizeof(fsi), FileStandardInformation); ok(res == STATUS_SUCCESS, "NtQueryInformationFile failed %lx\n", res); - todo_wine ok(!fsi.DeletePending, "Handle shouldn't be marked for deletion\n"); CloseHandle(handle); res = GetFileAttributesA( buffer ); - todo_wine ok( res != INVALID_FILE_ATTRIBUTES, "expected file to exist\n" ); }
diff --git a/server/fd.c b/server/fd.c index e11a66ce625..292850682fd 100644 --- a/server/fd.c +++ b/server/fd.c @@ -162,7 +162,8 @@ struct closed_fd { struct list entry; /* entry in inode closed list */ int unix_fd; /* the unix file descriptor */ - int unlink; /* whether to unlink on close: -1 - implicit FILE_DELETE_ON_CLOSE, 1 - explicit disposition */ + int unlink; /* whether to unlink on close: bit0 - implicit FILE_DELETE_ON_CLOSE, bit1 - explicit disposition */ + /* value duplicated (=shared) across all closed_fd:s of same path */ char *unix_name; /* name to unlink on close, points to parent fd unix_name */ };
@@ -1132,6 +1133,34 @@ static void inode_close_pending( struct inode *inode, int keep_unlinks ) } }
+static unsigned int inode_propagate_unlink( struct fd *fd, unsigned or_mask, unsigned and_mask ) +{ + struct list *ptr; + unsigned int unlink = 0; + + LIST_FOR_EACH( ptr, &fd->inode->open ) + { + struct fd *fd_ptr = LIST_ENTRY( ptr, struct fd, inode_entry ); + if (fd_ptr->unix_name && fd->unix_name && !strcmp(fd_ptr->unix_name, fd->unix_name)) + { + unlink |= fd_ptr->closed->unlink; + fd_ptr->closed->unlink |= or_mask; + fd_ptr->closed->unlink &= ~and_mask; + } + } + LIST_FOR_EACH( ptr, &fd->inode->closed ) + { + struct closed_fd *closed_fd = LIST_ENTRY( ptr, struct closed_fd, entry ); + if (closed_fd->unix_name && fd->unix_name && !strcmp(closed_fd->unix_name, fd->unix_name)) + { + unlink |= closed_fd->unlink; + closed_fd->unlink |= or_mask; + closed_fd->unlink &= ~and_mask; + } + } + return unlink; +} + static void inode_dump( struct object *obj, int verbose ) { struct inode *inode = (struct inode *)obj; @@ -2026,7 +2055,8 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam goto error; }
- fd->closed->unlink = (options & FILE_DELETE_ON_CLOSE) ? -1 : 0; + /* get existing unlink value from open/closed fd */ + fd->closed->unlink = inode_propagate_unlink( fd, 0, 0 ); if (flags & O_TRUNC) { if (S_ISDIR(st.st_mode)) @@ -2036,6 +2066,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam } ftruncate( fd->unix_fd, 0 ); } + if (options & FILE_DELETE_ON_CLOSE) inode_propagate_unlink( fd, 1, 0 ); } else /* special file */ { @@ -2542,9 +2573,10 @@ static void set_fd_disposition( struct fd *fd, int unlink ) } }
- fd->closed->unlink = unlink ? 1 : 0; - if (fd->options & FILE_DELETE_ON_CLOSE) - fd->closed->unlink = -1; + if (unlink) + inode_propagate_unlink( fd, 2, 0 ); + else + inode_propagate_unlink( fd, 0, 2 ); }
/* set new name for the fd */
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/ntdll/tests/file.c | 6 ------ server/fd.c | 13 ++++++++++++- 2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index b3b6cb79bcf..7d7de7d1a32 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3021,7 +3021,6 @@ static void test_file_disposition_information(void) ok( res == STATUS_DELETE_PENDING, "got %#lx\n", res ); /* can't open the deleted file */ handle3 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - todo_wine ok( handle3 == INVALID_HANDLE_VALUE, "CreateFile should fail\n" ); if (handle3 != INVALID_HANDLE_VALUE) CloseHandle( handle3 ); @@ -3158,9 +3157,7 @@ static void test_file_disposition_information(void) ok( res == STATUS_OBJECT_NAME_NOT_FOUND || broken(res == STATUS_DELETE_PENDING), "got %#lx\n", res ); /* can't open the deleted file */ handle2 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - todo_wine ok( handle2 == INVALID_HANDLE_VALUE, "CreateFile should fail\n" ); - todo_wine ok( GetLastError() == ERROR_FILE_NOT_FOUND || broken(GetLastError() == ERROR_ACCESS_DENIED), "got %lu\n", GetLastError()); if (handle2 != INVALID_HANDLE_VALUE) CloseHandle( handle2); @@ -3214,9 +3211,7 @@ static void test_file_disposition_information(void) ok( res == STATUS_OBJECT_NAME_NOT_FOUND || broken(res == STATUS_DELETE_PENDING), "got %#lx\n", res ); /* can't open the deleted directory */ handle2 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); - todo_wine ok( handle2 == INVALID_HANDLE_VALUE, "CreateFile should fail\n" ); - todo_wine ok(GetLastError() == ERROR_FILE_NOT_FOUND || broken(GetLastError() == ERROR_ACCESS_DENIED), "got %lu\n", GetLastError()); if (handle2 != INVALID_HANDLE_VALUE) CloseHandle( handle2 ); CloseHandle( handle ); @@ -3239,7 +3234,6 @@ static void test_file_disposition_information(void) ok( res == STATUS_DELETE_PENDING, "got %#lx\n", res ); /* can't open the deleted directory */ handle3 = CreateFileA(buffer, DELETE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); - todo_wine ok( handle3 == INVALID_HANDLE_VALUE, "CreateFile should fail\n" ); if (handle3 != INVALID_HANDLE_VALUE) CloseHandle( handle3 ); diff --git a/server/fd.c b/server/fd.c index 292850682fd..cf6bbb1eae9 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1133,6 +1133,10 @@ static void inode_close_pending( struct inode *inode, int keep_unlinks ) } }
+/* returns: + * bit0-1 or'ed unlink value of all open & closed fd + * bit2-3 or'ed unlink value of all closed fd only + */ static unsigned int inode_propagate_unlink( struct fd *fd, unsigned or_mask, unsigned and_mask ) { struct list *ptr; @@ -1153,7 +1157,7 @@ static unsigned int inode_propagate_unlink( struct fd *fd, unsigned or_mask, uns struct closed_fd *closed_fd = LIST_ENTRY( ptr, struct closed_fd, entry ); if (closed_fd->unix_name && fd->unix_name && !strcmp(closed_fd->unix_name, fd->unix_name)) { - unlink |= closed_fd->unlink; + unlink |= closed_fd->unlink | (closed_fd->unlink << 2); closed_fd->unlink |= or_mask; closed_fd->unlink &= ~and_mask; } @@ -2057,6 +2061,13 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
/* get existing unlink value from open/closed fd */ fd->closed->unlink = inode_propagate_unlink( fd, 0, 0 ); + /* either unlink=delete-on-close in closed fd, or unlink=disposition in any fd */ + if (fd->closed->unlink & 6) + { + set_error( STATUS_OBJECT_NAME_NOT_FOUND ); + goto error; + } + fd->closed->unlink &= 3; if (flags & O_TRUNC) { if (S_ISDIR(st.st_mode))
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=125668
Your paranoid android.
=== debian11 (32 bit report) ===
advapi32: security.c:4041: Test failed: GetNamedSecurityInfo failed with error 2 security.c:4054: Test failed: Current User ACE has unexpected mask (0x310032 != 0x1f01ff) security.c:4065: Test failed: Administators Group ACE has unexpected flags (0x33 != 0x0) security.c:4067: Test failed: Administators Group ACE has unexpected mask (0x343435 != 0x1f01ff) security.c:4078: Test failed: SetNamedSecurityInfoA failed with error 2 security.c:4083: Test failed: GetNamedSecurityInfo failed with error 2 security.c:4098: Test failed: CreateFile error 2 security.c:4104: Test failed: SetNamedSecurityInfoA failed with error 2 security.c:4108: Test failed: GetNamedSecurityInfo failed with error 2 security.c:4114: Test failed: CreateFile error 2 security.c:4166: Test failed: CreateFile error 2
d3drm: d3drm.c:6423: Test failed: Test 0: Failed to load texture, hr 0x88760316. d3drm.c:6425: Test failed: Test 0: Expected ref2 > ref1, got ref1 1, ref2 1. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x00413c09).
v2: fixed failing test