From 684b65cd522fff5cc8d17e63a377432c08a47ebc Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 16 Apr 2004 04:31:35 +0000 Subject: [PATCH] Added support for FILE_DIRECTORY_FILE and FILE_NON_DIRECTORY_FILE open options. --- files/file.c | 2 ++ server/fd.c | 43 ++++++++++++++++++++++++++++++++++--------- server/file.c | 10 +--------- server/file.h | 2 +- server/trace.c | 2 ++ 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/files/file.c b/files/file.c index b57b9a0402..5c673de1fa 100644 --- a/files/file.c +++ b/files/file.c @@ -204,6 +204,8 @@ HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing, options = 0; if (attributes & FILE_FLAG_BACKUP_SEMANTICS) options |= FILE_OPEN_FOR_BACKUP_INTENT; + else + options |= FILE_NON_DIRECTORY_FILE; if (attributes & FILE_FLAG_DELETE_ON_CLOSE) options |= FILE_DELETE_ON_CLOSE; if (!(attributes & FILE_FLAG_OVERLAPPED)) diff --git a/server/fd.c b/server/fd.c index 1b668d738a..68460d9f4e 100644 --- a/server/fd.c +++ b/server/fd.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,10 @@ #include "process.h" #include "request.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" + /* Because of the stupid Posix locking semantics, we need to keep * track of all file descriptors referencing a given file, and not * close a single one until all the locks are gone (sigh). @@ -415,7 +420,10 @@ static void inode_destroy( struct object *obj ) /* make sure it is still the same file */ struct stat st; if (!stat( fd->unlink, &st ) && st.st_dev == inode->dev && st.st_ino == inode->ino) - unlink( fd->unlink ); + { + if (S_ISDIR(st.st_mode)) rmdir( fd->unlink ); + else unlink( fd->unlink ); + } } free( fd ); } @@ -907,13 +915,15 @@ static int check_sharing( struct fd *fd, unsigned int access, unsigned int shari /* the fd must have been created with alloc_fd */ /* on error the fd object is released */ struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode, - unsigned int access, unsigned int sharing, const char *unlink_name ) + unsigned int access, unsigned int sharing, unsigned int options ) { struct stat st; struct closed_fd *closed_fd; + const char *unlink_name = ""; assert( fd->unix_fd == -1 ); + if (options & FILE_DELETE_ON_CLOSE) unlink_name = name; if (!(closed_fd = mem_alloc( sizeof(*closed_fd) + strlen(unlink_name) ))) { release_object( fd ); @@ -931,7 +941,20 @@ struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode, fstat( fd->unix_fd, &st ); *mode = st.st_mode; - if (S_ISREG(st.st_mode)) /* only bother with an inode for normal files */ + /* check directory options */ + if ((options & FILE_DIRECTORY_FILE) && !S_ISDIR(st.st_mode)) + { + set_error( STATUS_NOT_A_DIRECTORY ); + goto error; + } + if ((options & FILE_NON_DIRECTORY_FILE) && S_ISDIR(st.st_mode)) + { + set_error( STATUS_FILE_IS_A_DIRECTORY ); + goto error; + } + + /* only bother with an inode for normal files and directories */ + if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { struct inode *inode = get_inode( st.st_dev, st.st_ino ); @@ -940,9 +963,7 @@ struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode, /* we can close the fd because there are no others open on the same file, * otherwise we wouldn't have failed to allocate a new inode */ - release_object( fd ); - free( closed_fd ); - return NULL; + goto error; } fd->inode = inode; fd->closed = closed_fd; @@ -957,15 +978,19 @@ struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode, } else { - free( closed_fd ); if (unlink_name[0]) /* we can't unlink special files */ { - release_object( fd ); set_error( STATUS_INVALID_PARAMETER ); - return NULL; + goto error; } + free( closed_fd ); } return fd; + +error: + release_object( fd ); + free( closed_fd ); + return NULL; } /* create an fd for an anonymous file */ diff --git a/server/file.c b/server/file.c index 509a7c0321..a748766e1f 100644 --- a/server/file.c +++ b/server/file.c @@ -167,8 +167,7 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */ if (!(file->fd = alloc_fd( &file_fd_ops, &file->obj )) || !(file->fd = open_fd( file->fd, name, flags | O_NONBLOCK | O_LARGEFILE, - &mode, access, sharing, - (options & FILE_DELETE_ON_CLOSE) ? name : "" ))) + &mode, access, sharing, options ))) { free( name ); release_object( file ); @@ -176,13 +175,6 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int } free( name ); - /* refuse to open a directory */ - if (S_ISDIR(mode) && !(options & FILE_OPEN_FOR_BACKUP_INTENT)) - { - set_error( STATUS_ACCESS_DENIED ); - release_object( file ); - return NULL; - } /* check for serial port */ if (S_ISCHR(mode) && is_serial_fd( file->fd )) { diff --git a/server/file.h b/server/file.h index 159b630aa2..92321e49ab 100644 --- a/server/file.h +++ b/server/file.h @@ -46,7 +46,7 @@ struct fd_ops extern struct fd *alloc_fd( const struct fd_ops *fd_user_ops, struct object *user ); extern struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode, - unsigned int access, unsigned int sharing, const char *unlink_name ); + unsigned int access, unsigned int sharing, unsigned int options ); extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user ); extern void *get_fd_user( struct fd *fd ); diff --git a/server/trace.c b/server/trace.c index 81afe590a1..3d9d7b905c 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3082,6 +3082,7 @@ static const char *get_status_name( unsigned int status ) NAME(DIRECTORY_NOT_EMPTY), NAME(DISK_FULL), NAME(DLL_NOT_FOUND), + NAME(FILE_IS_A_DIRECTORY), NAME(FILE_LOCK_CONFLICT), NAME(INVALID_FILE_FOR_SECTION), NAME(INVALID_HANDLE), @@ -3089,6 +3090,7 @@ static const char *get_status_name( unsigned int status ) NAME(KEY_DELETED), NAME(MEDIA_WRITE_PROTECTED), NAME(MUTANT_NOT_OWNED), + NAME(NOT_A_DIRECTORY), NAME(NOT_IMPLEMENTED), NAME(NOT_REGISTRY_FILE), NAME(NO_DATA_DETECTED),