r3240: - update the rules for what error codes should be given on the
[jelmer/samba4-debian.git] / source / ntvfs / posix / pvfs_open.c
index 95990f63323beadc06b936b5ba5cfc2eace56341..ffd1520b07010635548a5082814cdf475bab7b7d 100644 (file)
 #include "include/includes.h"
 #include "vfs_posix.h"
 
+/*
+  create file handles with convenient numbers for sniffers
+*/
+#define PVFS_MIN_FILE_FNUM 0x100
+#define PVFS_MIN_NEW_FNUM 0x200
+#define PVFS_MIN_DIR_FNUM 0x1000
 
 /*
   find open file handle given fnum
@@ -114,7 +120,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                return NT_STATUS_NO_MEMORY;
        }
 
-       fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
+       fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_DIR_FNUM, UINT16_MAX);
        if (fnum == -1) {
                talloc_free(f);
                return NT_STATUS_TOO_MANY_OPENED_FILES;
@@ -131,6 +137,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        f->locking_key = data_blob(NULL, 0);
        f->create_options = io->generic.in.create_options;
        f->share_access = io->generic.in.share_access;
+       f->seek_offset = 0;
+       f->position = 0;
 
        DLIST_ADD(pvfs->open_files, f);
 
@@ -142,7 +150,9 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        talloc_set_destructor(f, pvfs_dir_fd_destructor);
 
        if (!name->exists) {
-               if (mkdir(name->full_name, 0755) == -1) {
+               uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
+               mode_t mode = pvfs_fileperms(pvfs, attrib);
+               if (mkdir(name->full_name, mode) == -1) {
                        return pvfs_map_errno(pvfs,errno);
                }
                status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
@@ -170,8 +180,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        io->generic.out.write_time    = name->dos.write_time;
        io->generic.out.change_time   = name->dos.change_time;
        io->generic.out.attrib        = name->dos.attrib;
-       io->generic.out.alloc_size    = 0;
-       io->generic.out.size          = 0;
+       io->generic.out.alloc_size    = name->dos.alloc_size;
+       io->generic.out.size          = name->st.st_size;
        io->generic.out.file_type     = FILE_TYPE_DISK;
        io->generic.out.ipc_state     = 0;
        io->generic.out.is_directory  = 1;
@@ -202,6 +212,13 @@ static int pvfs_fd_destructor(void *p)
 
        idr_remove(f->pvfs->idtree_fnum, f->fnum);
 
+       if (f->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
+               if (unlink(f->name->full_name) != 0) {
+                       DEBUG(0,("pvfs_close: failed to delete '%s'\n", 
+                                f->name->full_name));
+               }
+       }
+
        lck = odb_lock(f, f->pvfs->odb_context, &f->locking_key);
        if (lck == NULL) {
                DEBUG(0,("Unable to lock opendb for close\n"));
@@ -214,12 +231,7 @@ static int pvfs_fd_destructor(void *p)
                         f->name->full_name, nt_errstr(status)));
        }
 
-       if (f->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
-               if (unlink(f->name->full_name) != 0) {
-                       DEBUG(0,("pvfs_close: failed to delete '%s'\n", 
-                                f->name->full_name));
-               }
-       }
+       talloc_free(lck);
 
        return 0;
 }
@@ -273,23 +285,33 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                return NT_STATUS_CANNOT_DELETE;
        }
        
-       flags = O_RDWR;
+       if (access_mask & SEC_RIGHT_MAXIMUM_ALLOWED) {
+               access_mask = GENERIC_RIGHTS_FILE_READ | GENERIC_RIGHTS_FILE_WRITE;
+       }
+
+       switch (access_mask & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_WRITE_DATA)) {
+       case SA_RIGHT_FILE_READ_DATA:
+               flags = O_RDONLY;
+               break;
+       case SA_RIGHT_FILE_WRITE_DATA:
+               flags = O_WRONLY;
+               break;
+       case SA_RIGHT_FILE_WRITE_DATA|SA_RIGHT_FILE_READ_DATA:
+               flags = O_RDWR;
+               break;
+       }
 
        f = talloc_p(req, struct pvfs_file);
        if (f == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
+       fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_NEW_FNUM, UINT16_MAX);
        if (fnum == -1) {
                return NT_STATUS_TOO_MANY_OPENED_FILES;
        }
 
-       if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) {
-               mode = 0444;
-       } else {
-               mode = 0644;
-       }
+       mode = pvfs_fileperms(pvfs, io->ntcreatex.in.file_attr);
 
        /* create the file */
        fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
@@ -345,7 +367,9 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->lock_count = 0;
        f->create_options = io->generic.in.create_options;
        f->share_access = io->generic.in.share_access;
-       f->access_mask = io->generic.in.access_mask;
+       f->access_mask = access_mask;
+       f->seek_offset = 0;
+       f->position = 0;
 
        DLIST_ADD(pvfs->open_files, f);
 
@@ -417,6 +441,14 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        share_access   = io->generic.in.share_access;
        access_mask    = io->generic.in.access_mask;
 
+       if (access_mask & SEC_RIGHT_MAXIMUM_ALLOWED) {
+               if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_READONLY)) {
+                       access_mask = GENERIC_RIGHTS_FILE_READ;
+               } else {
+                       access_mask = GENERIC_RIGHTS_FILE_READ | GENERIC_RIGHTS_FILE_WRITE;
+               }
+       }
+
        /* certain create options are not allowed */
        if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
            !(access_mask & STD_RIGHT_DELETE_ACCESS)) {
@@ -425,9 +457,6 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
 
        switch (io->generic.in.open_disposition) {
        case NTCREATEX_DISP_SUPERSEDE:
-               if (!name->exists) {
-                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-               }
                flags = O_TRUNC;
                break;
 
@@ -464,7 +493,17 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       flags |= O_RDWR;
+       switch (access_mask & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_WRITE_DATA)) {
+       case SA_RIGHT_FILE_READ_DATA:
+               flags |= O_RDONLY;
+               break;
+       case SA_RIGHT_FILE_WRITE_DATA:
+               flags |= O_WRONLY;
+               break;
+       case SA_RIGHT_FILE_WRITE_DATA|SA_RIGHT_FILE_READ_DATA:
+               flags |= O_RDWR;
+               break;
+       }
 
        /* handle creating a new file separately */
        if (!name->exists) {
@@ -498,7 +537,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        }
 
        /* allocate a fnum */
-       fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
+       fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_FILE_FNUM, UINT16_MAX);
        if (fnum == -1) {
                return NT_STATUS_TOO_MANY_OPENED_FILES;
        }
@@ -539,7 +578,9 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        f->lock_count = 0;
        f->create_options = io->generic.in.create_options;
        f->share_access = io->generic.in.share_access;
-       f->access_mask = io->generic.in.access_mask;
+       f->access_mask = access_mask;
+       f->seek_offset = 0;
+       f->position = 0;
 
        DLIST_ADD(pvfs->open_files, f);
 
@@ -591,6 +632,7 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
        struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_file *f;
        NTSTATUS status;
+       struct utimbuf unix_times;
 
        if (io->generic.level != RAW_CLOSE_CLOSE) {
                return ntvfs_map_close(req, io, ntvfs);
@@ -601,6 +643,12 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_HANDLE;
        }
 
+       if (!null_time(io->close.in.write_time)) {
+               unix_times.actime = 0;
+               unix_times.modtime = io->close.in.write_time;
+               utime(f->name->full_name, &unix_times);
+       }
+       
        if (f->fd != -1 && 
            close(f->fd) == -1) {
                status = pvfs_map_errno(pvfs, errno);
@@ -689,3 +737,27 @@ NTSTATUS pvfs_change_create_options(struct pvfs_state *pvfs,
 
        return status;
 }
+
+
+/*
+  determine if a file can be deleted, or if it is prevented by an
+  already open file
+*/
+NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, struct pvfs_filename *name)
+{
+       NTSTATUS status;
+       DATA_BLOB key;
+
+       status = pvfs_locking_key(name, name, &key);
+       if (!NT_STATUS_IS_OK(status)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = odb_can_open(pvfs->odb_context, &key, 
+                             NTCREATEX_SHARE_ACCESS_READ |
+                             NTCREATEX_SHARE_ACCESS_WRITE | 
+                             NTCREATEX_SHARE_ACCESS_DELETE, 
+                             0, STD_RIGHT_DELETE_ACCESS);
+
+       return status;
+}