Rebase against 3b5107d06305972beaa9c5ff147ecbcd99949a75.

This commit is contained in:
Sebastian Lackner
2015-08-19 17:13:50 +02:00
parent f28931a026
commit 428f65dd68
21 changed files with 27 additions and 663 deletions

View File

@@ -1,168 +0,0 @@
From 47f1bcd94dab7f58cda802dd89233ee21274c9fa Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Thu, 7 Aug 2014 18:31:33 -0600
Subject: server: Keep a pointer to parent's fd unix_name in the closed_fd
structure.
---
server/fd.c | 38 +++++++++++++++++++++-----------------
1 file changed, 21 insertions(+), 17 deletions(-)
diff --git a/server/fd.c b/server/fd.c
index 14e98ac..7c2d717 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -164,7 +164,8 @@ struct closed_fd
{
struct list entry; /* entry in inode closed list */
int unix_fd; /* the unix file descriptor */
- char unlink[1]; /* name to unlink on close (if any) */
+ int unlink; /* whether to unlink on close */
+ char *unix_name; /* name to unlink on close, points to parent fd unix_name */
};
struct fd
@@ -1016,9 +1017,10 @@ static void inode_close_pending( struct inode *inode, int keep_unlinks )
close( fd->unix_fd );
fd->unix_fd = -1;
}
- if (!keep_unlinks || !fd->unlink[0]) /* get rid of it unless there's an unlink pending on that file */
+ if (!keep_unlinks || !fd->unlink) /* get rid of it unless there's an unlink pending on that file */
{
list_remove( ptr );
+ free( fd->unix_name );
free( fd );
}
ptr = next;
@@ -1048,16 +1050,17 @@ static void inode_destroy( struct object *obj )
struct closed_fd *fd = LIST_ENTRY( ptr, struct closed_fd, entry );
list_remove( ptr );
if (fd->unix_fd != -1) close( fd->unix_fd );
- if (fd->unlink[0])
+ if (fd->unlink)
{
/* make sure it is still the same file */
struct stat st;
- if (!stat( fd->unlink, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
+ if (!stat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
{
- if (S_ISDIR(st.st_mode)) rmdir( fd->unlink );
- else unlink( fd->unlink );
+ if (S_ISDIR(st.st_mode)) rmdir( fd->unix_name );
+ else unlink( fd->unix_name );
}
}
+ free( fd->unix_name );
free( fd );
}
release_object( inode->device );
@@ -1103,7 +1106,7 @@ static void inode_add_closed_fd( struct inode *inode, struct closed_fd *fd )
{
list_add_head( &inode->closed, &fd->entry );
}
- else if (fd->unlink[0]) /* close the fd but keep the structure around for unlink */
+ else if (fd->unlink) /* close the fd but keep the structure around for unlink */
{
if (fd->unix_fd != -1) close( fd->unix_fd );
fd->unix_fd = -1;
@@ -1112,6 +1115,7 @@ static void inode_add_closed_fd( struct inode *inode, struct closed_fd *fd )
else /* no locks on this inode and no unlink, get rid of the fd */
{
if (fd->unix_fd != -1) close( fd->unix_fd );
+ free( fd->unix_name );
free( fd );
}
}
@@ -1451,7 +1455,7 @@ static void fd_dump( struct object *obj, int verbose )
{
struct fd *fd = (struct fd *)obj;
fprintf( stderr, "Fd unix_fd=%d user=%p options=%08x", fd->unix_fd, fd->user, fd->options );
- if (fd->inode) fprintf( stderr, " inode=%p unlink='%s'", fd->inode, fd->closed->unlink );
+ if (fd->inode) fprintf( stderr, " inode=%p unlink=%d", fd->inode, fd->closed->unlink );
fprintf( stderr, "\n" );
}
@@ -1465,7 +1469,6 @@ static void fd_destroy( struct object *obj )
if (fd->completion) release_object( fd->completion );
remove_fd_locks( fd );
- free( fd->unix_name );
list_remove( &fd->inode_entry );
if (fd->poll_index != -1) remove_poll_user( fd, fd->poll_index );
if (fd->inode)
@@ -1476,6 +1479,7 @@ static void fd_destroy( struct object *obj )
else /* no inode, close it right away */
{
if (fd->unix_fd != -1) close( fd->unix_fd );
+ free( fd->unix_name );
}
}
@@ -1563,7 +1567,7 @@ static inline void unmount_fd( struct fd *fd )
fd->unix_fd = -1;
fd->no_fd_status = STATUS_VOLUME_DISMOUNTED;
fd->closed->unix_fd = -1;
- fd->closed->unlink[0] = 0;
+ fd->closed->unlink = 0;
/* stop using Unix locks on this fd (existing locks have been removed by close) */
fd->fs_locks = 0;
@@ -1662,7 +1666,8 @@ struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sha
goto failed;
}
closed->unix_fd = fd->unix_fd;
- closed->unlink[0] = 0;
+ closed->unlink = 0;
+ closed->unix_name = fd->unix_name;
fd->closed = closed;
fd->inode = (struct inode *)grab_object( orig->inode );
list_add_head( &fd->inode->open, &fd->inode_entry );
@@ -1738,7 +1743,6 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
struct stat st;
struct closed_fd *closed_fd;
struct fd *fd;
- const char *unlink_name = "";
int root_fd = -1;
int rw_mode;
int do_chmod = 0;
@@ -1753,8 +1757,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
if (!(fd = alloc_fd_object())) return NULL;
fd->options = options;
- if (options & FILE_DELETE_ON_CLOSE) unlink_name = name;
- if (!(closed_fd = mem_alloc( sizeof(*closed_fd) + strlen(unlink_name) )))
+ if (!(closed_fd = mem_alloc( sizeof(*closed_fd) )))
{
release_object( fd );
return NULL;
@@ -1834,7 +1837,8 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
}
closed_fd->unix_fd = fd->unix_fd;
- closed_fd->unlink[0] = 0;
+ closed_fd->unlink = 0;
+ closed_fd->unix_name = fd->unix_name;
if (do_chmod) fchmod( fd->unix_fd, *mode );
fstat( fd->unix_fd, &st );
@@ -1877,7 +1881,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
set_error( err );
return NULL;
}
- strcpy( closed_fd->unlink, unlink_name );
+ closed_fd->unlink = (options & FILE_DELETE_ON_CLOSE) != 0;
if (flags & O_TRUNC)
{
if (S_ISDIR(st.st_mode))
@@ -1891,7 +1895,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
}
else /* special file */
{
- if (unlink_name[0]) /* we can't unlink special files */
+ if (options & FILE_DELETE_ON_CLOSE) /* we can't unlink special files */
{
set_error( STATUS_INVALID_PARAMETER );
goto error;
--
2.4.2

View File

@@ -1,229 +0,0 @@
From 2009dee9faca0fb2ac2b1422a62445a523c4fe56 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Thu, 7 Aug 2014 20:32:19 -0600
Subject: server: Add support for setting file disposition information.
Based on a patch by Dmitry Timoshkov.
---
dlls/kernel32/tests/file.c | 1 -
dlls/ntdll/file.c | 16 ++++++++++++++++
dlls/ntdll/tests/file.c | 13 ++-----------
server/fd.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
server/protocol.def | 7 +++++++
5 files changed, 69 insertions(+), 12 deletions(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 53d225c..dd64c91 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -4645,7 +4645,6 @@ todo_wine
dispinfo.DeleteFile = TRUE;
ret = pSetFileInformationByHandle(file, FileDispositionInfo, &dispinfo, sizeof(dispinfo));
-todo_wine
ok(ret, "setting FileDispositionInfo failed, error %d\n", GetLastError());
CloseHandle(file);
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index d081750..314c233 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -2765,6 +2765,22 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
else io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
+ case FileDispositionInformation:
+ if (len >= sizeof(FILE_DISPOSITION_INFORMATION))
+ {
+ FILE_DISPOSITION_INFORMATION *info = ptr;
+
+ SERVER_START_REQ( set_fd_info )
+ {
+ req->handle = wine_server_obj_handle( handle );
+ req->unlink = info->DoDeleteFile;
+ io->u.Status = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+ } else
+ io->u.Status = STATUS_INVALID_PARAMETER_3;
+ break;
+
default:
FIXME("Unsupported class (%d)\n", class);
io->u.Status = STATUS_NOT_IMPLEMENTED;
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 86a4516..57ae15c 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -1473,7 +1473,6 @@ static void test_file_disposition_information(void)
ok( res == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %x\n", res );
fdi2 = 0x100;
res = pNtSetInformationFile( handle, &io, &fdi2, sizeof(fdi2), FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %x\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@@ -1488,7 +1487,6 @@ static void test_file_disposition_information(void)
ok( res == STATUS_INVALID_INFO_CLASS || res == STATUS_NOT_IMPLEMENTED, "Unexpected NtQueryInformationFile result (expected STATUS_INVALID_INFO_CLASS, got %x)\n", res );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_ACCESS_DENIED, "unexpected FileDispositionInformation result (expected STATUS_ACCESS_DENIED, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@@ -1501,11 +1499,9 @@ static void test_file_disposition_information(void)
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
- todo_wine
ok( fileDeleted, "File should have been deleted\n" );
DeleteFileA( buffer );
@@ -1519,6 +1515,7 @@ static void test_file_disposition_information(void)
ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ todo_wine
ok( !fileDeleted, "File shouldn't have been deleted\n" );
SetFileAttributesA( buffer, FILE_ATTRIBUTE_NORMAL );
DeleteFileA( buffer );
@@ -1529,11 +1526,9 @@ static void test_file_disposition_information(void)
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@@ -1546,7 +1541,6 @@ static void test_file_disposition_information(void)
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@@ -1561,7 +1555,6 @@ static void test_file_disposition_information(void)
CloseHandle( handle );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle2, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle2 );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@@ -1576,11 +1569,9 @@ static void test_file_disposition_information(void)
ok( handle != INVALID_HANDLE_VALUE, "failed to open a directory\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
- todo_wine
ok( fileDeleted, "Directory should have been deleted\n" );
RemoveDirectoryA( buffer );
@@ -1593,7 +1584,6 @@ static void test_file_disposition_information(void)
RemoveDirectoryA( buffer );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@@ -1618,6 +1608,7 @@ static void test_file_disposition_information(void)
buffer[dirpos] = '\0';
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ todo_wine
ok( !fileDeleted, "Directory shouldn't have been deleted\n" );
RemoveDirectoryA( buffer );
}
diff --git a/server/fd.c b/server/fd.c
index 6b95d6c..f607261 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2214,6 +2214,39 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
return fd;
}
+/* set disposition for the fd */
+static void set_fd_disposition( struct fd *fd, int unlink )
+{
+ struct stat st;
+
+ if (!fd->inode)
+ {
+ set_error( STATUS_OBJECT_TYPE_MISMATCH );
+ return;
+ }
+
+ if (fd->unix_fd == -1)
+ {
+ set_error( fd->no_fd_status );
+ return;
+ }
+
+ if (fstat( fd->unix_fd, &st ) == -1)
+ {
+ file_set_error();
+ return;
+ }
+
+ /* can't unlink special files */
+ if (unlink && !S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+
+ fd->closed->unlink = unlink || (fd->options & FILE_DELETE_ON_CLOSE);
+}
+
struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key )
{
*p_key = fd->comp_key;
@@ -2409,3 +2442,14 @@ DECL_HANDLER(add_fd_completion)
release_object( fd );
}
}
+
+/* set fd information */
+DECL_HANDLER(set_fd_info)
+{
+ struct fd *fd = get_handle_fd_obj( current->process, req->handle, DELETE );
+ if (fd)
+ {
+ set_fd_disposition( fd, req->unlink );
+ release_object( fd );
+ }
+}
diff --git a/server/protocol.def b/server/protocol.def
index ffee0c0..ea9eb12 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3525,6 +3525,13 @@ enum coords_relative
@END
+/* set fd information */
+@REQ(set_fd_info)
+ obj_handle_t handle; /* handle to a file or directory */
+ int unlink; /* whether to unlink file on close */
+@END
+
+
/* Retrieve layered info for a window */
@REQ(get_window_layered_info)
user_handle_t handle; /* handle to the window */
--
2.5.0

View File

@@ -1,57 +0,0 @@
From ccc579e226c2061d3138da446d30b8ba68397751 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 7 Aug 2014 21:14:25 -0600
Subject: server: Do not permit FileDispositionInformation to delete a file
without write access.
---
dlls/ntdll/tests/file.c | 14 ++++++++++++++
server/fd.c | 7 +++++++
2 files changed, 21 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 57ae15c..d215d09 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -1507,6 +1507,20 @@ static void test_file_disposition_information(void)
/* cannot set disposition on readonly file */
GetTempFileNameA( tmp_path, "dis", 0, buffer );
+ DeleteFileA( buffer );
+ handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
+ ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
+ fdi.DoDeleteFile = TRUE;
+ res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
+ ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
+ CloseHandle( handle );
+ fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "File shouldn't have been deleted\n" );
+ SetFileAttributesA( buffer, FILE_ATTRIBUTE_NORMAL );
+ DeleteFileA( buffer );
+
+ /* cannot set disposition on readonly file */
+ GetTempFileNameA( tmp_path, "dis", 0, buffer );
handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
diff --git a/server/fd.c b/server/fd.c
index f607261..0bac57d 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2244,6 +2244,13 @@ static void set_fd_disposition( struct fd *fd, int unlink )
return;
}
+ /* can't unlink files we don't have permission to access */
+ if (unlink && !(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
+ {
+ set_error( STATUS_CANNOT_DELETE );
+ return;
+ }
+
fd->closed->unlink = unlink || (fd->options & FILE_DELETE_ON_CLOSE);
}
--
2.5.0