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
-- v3: 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 | 12 ++++++++++-- server/fd.c | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 3 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..88d38e3fc12 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4344,12 +4344,16 @@ 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 { fill_file_info( &st, attr, info, class ); - info->DeletePending = FALSE; /* FIXME */ + if (!server_get_file_info( handle, io, &fdi, sizeof(fdi), FileDispositionInformation)) + info->DeletePending = fdi.DoDeleteFile; + else + info->DeletePending = FALSE; } } break; @@ -4378,6 +4382,7 @@ 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 ); @@ -4388,7 +4393,10 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
fill_file_info( &st, attr, info, FileAllInformation ); - info->StandardInformation.DeletePending = FALSE; /* FIXME */ + if (!server_get_file_info( handle, io, &fdi, sizeof(fdi), FileDispositionInformation)) + info->StandardInformation.DeletePending = fdi.DoDeleteFile; + else + info->StandardInformation.DeletePending = FALSE; 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 | 61 +++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 16 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..6db2da6764f 100644 --- a/server/fd.c +++ b/server/fd.c @@ -157,13 +157,17 @@ static inline int epoll_wait( int epfd, struct epoll_event *events, int maxevent
/* file descriptor object */
+#define UNLINK_OPENED_WITH_DELETE_ON_CLOSE 1u /* shared across all fd with same name */ +#define UNLINK_DISPOSITION 4u /* shared across all fd with same name */ + + /* closed_fd is used to keep track of the unix fd belonging to a closed fd object */ 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 */ - char *unix_name; /* name to unlink on close, points to parent fd unix_name */ + struct list entry; /* entry in inode closed list */ + int unix_fd; /* the unix file descriptor */ + unsigned int unlink; /* whether to unlink on close: or'ed of UNLINK_ flags above */ + char *unix_name; /* name to unlink on close, points to parent fd unix_name */ };
struct fd @@ -1132,6 +1136,45 @@ static void inode_close_pending( struct inode *inode, int keep_unlinks ) } }
+static void inode_propagate_unlink( struct fd *fd, unsigned or_mask, unsigned and_mask ) +{ + struct list *ptr; + + 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)) + { + 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)) + { + closed_fd->unlink |= or_mask; + closed_fd->unlink &= ~and_mask; + } + } +} + +static void inode_init_closed_unlink( struct fd *fd ) +{ + struct list *ptr; + + 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)) + { + if (fd_ptr->closed->unlink & UNLINK_OPENED_WITH_DELETE_ON_CLOSE) + fd->closed->unlink |= UNLINK_OPENED_WITH_DELETE_ON_CLOSE; + } + } +} + static void inode_dump( struct object *obj, int verbose ) { struct inode *inode = (struct inode *)obj; @@ -2026,7 +2069,7 @@ 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; + inode_init_closed_unlink( fd ); if (flags & O_TRUNC) { if (S_ISDIR(st.st_mode)) @@ -2036,6 +2079,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, UNLINK_OPENED_WITH_DELETE_ON_CLOSE, 0 ); } else /* special file */ { @@ -2542,9 +2586,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, UNLINK_DISPOSITION, 0 ); + else + inode_propagate_unlink( fd, 0, UNLINK_DISPOSITION ); }
/* 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 | 30 +++++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 11 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 6db2da6764f..6263d39c119 100644 --- a/server/fd.c +++ b/server/fd.c @@ -157,7 +157,8 @@ static inline int epoll_wait( int epfd, struct epoll_event *events, int maxevent
/* file descriptor object */
-#define UNLINK_OPENED_WITH_DELETE_ON_CLOSE 1u /* shared across all fd with same name */ +#define UNLINK_OPENED_WITH_DELETE_ON_CLOSE 1u /* only on fd opened with delete-on-close flag */ +#define UNLINK_PROPAGATED_DELETE_ON_CLOSE 2u /* shared across all fd with same name */ #define UNLINK_DISPOSITION 4u /* shared across all fd with same name */
@@ -1160,7 +1161,7 @@ static void inode_propagate_unlink( struct fd *fd, unsigned or_mask, unsigned an } }
-static void inode_init_closed_unlink( struct fd *fd ) +static BOOL inode_init_closed_unlink( struct fd *fd ) { struct list *ptr;
@@ -1169,10 +1170,21 @@ static void inode_init_closed_unlink( struct fd *fd ) 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)) { + if (fd_ptr->closed->unlink & UNLINK_DISPOSITION) return FALSE; if (fd_ptr->closed->unlink & UNLINK_OPENED_WITH_DELETE_ON_CLOSE) - fd->closed->unlink |= UNLINK_OPENED_WITH_DELETE_ON_CLOSE; + fd->closed->unlink |= UNLINK_PROPAGATED_DELETE_ON_CLOSE; } } + 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)) + { + if (closed_fd->unlink & (UNLINK_OPENED_WITH_DELETE_ON_CLOSE | UNLINK_DISPOSITION)) + return FALSE; + } + } + return TRUE; }
static void inode_dump( struct object *obj, int verbose ) @@ -2069,7 +2081,11 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam goto error; }
- inode_init_closed_unlink( fd ); + if (!inode_init_closed_unlink( fd )) + { + set_error( STATUS_OBJECT_NAME_NOT_FOUND ); + goto error; + } if (flags & O_TRUNC) { if (S_ISDIR(st.st_mode)) @@ -2079,7 +2095,11 @@ 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, UNLINK_OPENED_WITH_DELETE_ON_CLOSE, 0 ); + if (options & FILE_DELETE_ON_CLOSE) + { + inode_propagate_unlink( fd, UNLINK_PROPAGATED_DELETE_ON_CLOSE, 0 ); + fd->closed->unlink = UNLINK_OPENED_WITH_DELETE_ON_CLOSE; + } } else /* special file */ {
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=125717
Your paranoid android.
=== debian11 (32 bit report) ===
ddraw: ddraw4.c:17853: Test succeeded inside todo block: Got unexpected caps 0x3046737c. ddraw4.c:17882: Test failed: Got unexpected caps 0x3046737c.
v3: - fix getting FileStandardInformation on non-file handle - fix test for opening a file with already opened file & closed file with delete-on-close flag