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 */