Added support for FILE_DIRECTORY_FILE and FILE_NON_DIRECTORY_FILE open
options.
diff --git a/files/file.c b/files/file.c
index b57b9a0..5c673de 100644
--- a/files/file.c
+++ b/files/file.c
@@ -204,6 +204,8 @@
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 1b668d7..68460d9 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -26,6 +26,7 @@
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -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 @@
/* 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 @@
/* 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 @@
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 @@
/* 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 @@
}
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 509a7c0..a748766 100644
--- a/server/file.c
+++ b/server/file.c
@@ -167,8 +167,7 @@
/* 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 @@
}
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 159b630..92321e4 100644
--- a/server/file.h
+++ b/server/file.h
@@ -46,7 +46,7 @@
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 81afe59..3d9d7b9 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3082,6 +3082,7 @@
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 @@
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),