[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / smbd / files.c
index ed14b86e5fefbd5709479c7924ba8c99baf52f79..179963dae9b5250995608386b2dc5b17cb98362f 100644 (file)
@@ -1,12 +1,11 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    Files[] structure handling
    Copyright (C) Andrew Tridgell 1998
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
-extern int DEBUGLEVEL;
+static int real_max_open_files;
 
-/* the only restriction is that this must be less than PIPE_HANDLE_OFFSET */
-#define MAX_FNUMS 4096
-
-#define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < MAX_FNUMS))
+#define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < real_max_open_files))
 
 #define FILE_HANDLE_OFFSET 0x1000
 
 static struct bitmap *file_bmap;
-static struct bitmap *fd_bmap;
 
 static files_struct *Files;
-
 /* a fsp to use when chaining */
 static files_struct *chain_fsp = NULL;
-/* a fsp to use to save when breaking an oplock. */
-static files_struct *oplock_save_chain_fsp = NULL;
 
-/*
- * Indirection for file fd's. Needed as POSIX locking
- * is based on file/process, not fd/process.
- */
-static file_fd_struct *FileFd;
+static int files_used;
+
+/* A singleton cache to speed up searching by dev/inode. */
+static struct fsp_singleton_cache {
+       files_struct *fsp;
+       struct file_id id;
+} fsp_fi_cache;
+
+/****************************************************************************
+ Return a unique number identifying this fsp over the life of this pid.
+****************************************************************************/
+
+static unsigned long get_gen_count(void)
+{
+       static unsigned long file_gen_counter;
 
-static int files_used, fd_ptr_used;
+       if ((++file_gen_counter) == 0)
+               return ++file_gen_counter;
+       return file_gen_counter;
+}
 
 /****************************************************************************
-  find first available file slot
+ Find first available file slot.
 ****************************************************************************/
-files_struct *file_new(void )
+
+NTSTATUS file_new(connection_struct *conn, files_struct **result)
 {
        int i;
        static int first_file;
-       files_struct *fsp, *next;
+       files_struct *fsp;
 
        /* we want to give out file handles differently on each new
           connection because of a common bug in MS clients where they try to
@@ -63,218 +69,222 @@ files_struct *file_new(void )
           increases the chance that the errant client will get an error rather
           than causing corruption */
        if (first_file == 0) {
-               first_file = (getpid() ^ (int)time(NULL)) % MAX_FNUMS;
+               first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
        }
 
+       /* TODO: Port the id-tree implementation from Samba4 */
+
        i = bitmap_find(file_bmap, first_file);
        if (i == -1) {
-               /* 
-                * Before we give up, go through the open files 
-                * and see if there are any files opened with a
-                * batch oplock. If so break the oplock and then
-                * re-use that entry (if it becomes closed).
-                * This may help as NT/95 clients tend to keep
-                * files batch oplocked for quite a long time
-                * after they have finished with them.
-                */
-               for (fsp=Files;fsp;fsp=next) {
-                       next=fsp->next;
-                       if (attempt_close_oplocked_file(fsp)) {
-                               return file_new();
-                       }
-               }
-
                DEBUG(0,("ERROR! Out of file structures\n"));
-               return NULL;
+               /* TODO: We have to unconditionally return a DOS error here,
+                * W2k3 even returns ERRDOS/ERRnofids for ntcreate&x with
+                * NTSTATUS negotiated */
+               return NT_STATUS_TOO_MANY_OPENED_FILES;
        }
 
-       fsp = (files_struct *)malloc(sizeof(*fsp));
-       if (!fsp) return NULL;
+       fsp = SMB_MALLOC_P(files_struct);
+       if (!fsp) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        ZERO_STRUCTP(fsp);
 
-       first_file = (i+1) % MAX_FNUMS;
+       fsp->fh = SMB_MALLOC_P(struct fd_handle);
+       if (!fsp->fh) {
+               SAFE_FREE(fsp);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ZERO_STRUCTP(fsp->fh);
+
+       fsp->fh->ref_count = 1;
+       fsp->fh->fd = -1;
+
+       fsp->conn = conn;
+       fsp->fh->gen_id = get_gen_count();
+       GetTimeOfDay(&fsp->open_time);
+
+       first_file = (i+1) % real_max_open_files;
 
        bitmap_set(file_bmap, i);
        files_used++;
 
        fsp->fnum = i + FILE_HANDLE_OFFSET;
-       string_init(&fsp->fsp_name,"");
+       SMB_ASSERT(fsp->fnum < 65536);
+
+       string_set(&fsp->fsp_name,"");
        
        DLIST_ADD(Files, fsp);
 
-       DEBUG(5,("allocated file structure %d (%d used)\n",
-                i, files_used));
+       DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
+                i, fsp->fnum, files_used));
 
        chain_fsp = fsp;
-       
-       return fsp;
-}
 
+       /* A new fsp invalidates a negative fsp_fi_cache. */
+       if (fsp_fi_cache.fsp == NULL) {
+               ZERO_STRUCT(fsp_fi_cache);
+       }
 
+       *result = fsp;
+       return NT_STATUS_OK;
+}
 
 /****************************************************************************
-fd support routines - attempt to find an already open file by dev
-and inode - increments the ref_count of the returned file_fd_struct *.
+ Close all open files for a connection.
 ****************************************************************************/
-file_fd_struct *fd_get_already_open(SMB_STRUCT_STAT *sbuf)
+
+void file_close_conn(connection_struct *conn)
 {
-       file_fd_struct *fd_ptr;
-
-       if(!sbuf) return NULL;
-
-       for (fd_ptr=FileFd;fd_ptr;fd_ptr=fd_ptr->next) {
-               if ((fd_ptr->ref_count > 0) &&
-                   (sbuf->st_dev == fd_ptr->dev) &&
-                   (sbuf->st_ino == fd_ptr->inode)) {
-                       fd_ptr->ref_count++;
-#ifdef LARGE_SMB_INO_T
-                       DEBUG(3,("Re-used file_fd_struct dev = %x, inode = %.0f, ref_count = %d\n",
-                                (unsigned int)fd_ptr->dev, (double)fd_ptr->inode, 
-                                fd_ptr->ref_count));
-#else /* LARGE_SMB_INO_T */
-                       DEBUG(3,("Re-used file_fd_struct dev = %x, inode = %x, ref_count = %d\n",
-                                (unsigned int)fd_ptr->dev, 
-                                (unsigned int)fd_ptr->inode, 
-                                fd_ptr->ref_count));
-#endif /* LARGE_SMB_INO_T */
-                       return fd_ptr;
+       files_struct *fsp, *next;
+       
+       for (fsp=Files;fsp;fsp=next) {
+               next = fsp->next;
+               if (fsp->conn == conn) {
+                       close_file(fsp,SHUTDOWN_CLOSE); 
                }
        }
-
-       return NULL;
 }
 
+/****************************************************************************
+ Close all open files for a pid and a vuid.
+****************************************************************************/
 
+void file_close_pid(uint16 smbpid, int vuid)
+{
+       files_struct *fsp, *next;
+       
+       for (fsp=Files;fsp;fsp=next) {
+               next = fsp->next;
+               if ((fsp->file_pid == smbpid) && (fsp->vuid == vuid)) {
+                       close_file(fsp,SHUTDOWN_CLOSE); 
+               }
+       }
+}
 
 /****************************************************************************
-fd support routines - attempt to find a empty slot in the FileFd array.
-Increments the ref_count of the returned entry.
+ Initialise file structures.
 ****************************************************************************/
-file_fd_struct *fd_get_new(void)
+
+#define MAX_OPEN_FUDGEFACTOR 20
+
+void file_init(void)
 {
-       extern struct current_user current_user;
-       int i;
-       file_fd_struct *fd_ptr;
+       int request_max_open_files = lp_max_open_files();
+       int real_lim;
 
-       i = bitmap_find(fd_bmap, 1);
-       if (i == -1) {
-               DEBUG(0,("ERROR! Out of file_fd structures\n"));
-               return NULL;
-       }
+       /*
+        * Set the max_open files to be the requested
+        * max plus a fudgefactor to allow for the extra
+        * fd's we need such as log files etc...
+        */
+       real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR);
 
-       fd_ptr = (file_fd_struct *)malloc(sizeof(*fd_ptr));
-       if (!fd_ptr) return NULL;
-       
-       ZERO_STRUCTP(fd_ptr);
-       
-       fd_ptr->fdnum = i;
-       fd_ptr->dev = (SMB_DEV_T)-1;
-       fd_ptr->inode = (SMB_INO_T)-1;
-       fd_ptr->fd = -1;
-       fd_ptr->fd_readonly = -1;
-       fd_ptr->fd_writeonly = -1;
-       fd_ptr->real_open_flags = -1;
-       fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
-       fd_ptr->ref_count++;
+       real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR;
 
-       bitmap_set(fd_bmap, i);
-       fd_ptr_used++;
+       if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536)
+               real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
 
-       DLIST_ADD(FileFd, fd_ptr);
+       if(real_max_open_files != request_max_open_files) {
+               DEBUG(1,("file_init: Information only: requested %d \
+open files, %d are available.\n", request_max_open_files, real_max_open_files));
+       }
 
-       DEBUG(5,("allocated fd_ptr structure %d (%d used)\n",
-                i, fd_ptr_used));
+       SMB_ASSERT(real_max_open_files > 100);
 
-       return fd_ptr;
+       file_bmap = bitmap_allocate(real_max_open_files);
+       
+       if (!file_bmap) {
+               exit_server("out of memory in file_init");
+       }
+       
+       /*
+        * Ensure that pipe_handle_oppset is set correctly.
+        */
+       set_pipe_handle_offset(real_max_open_files);
 }
 
-
 /****************************************************************************
-close all open files for a connection
+ Close files open by a specified vuid.
 ****************************************************************************/
-void file_close_conn(connection_struct *conn)
+
+void file_close_user(int vuid)
 {
        files_struct *fsp, *next;
-       
+
        for (fsp=Files;fsp;fsp=next) {
-               next = fsp->next;
-               if (fsp->conn == conn && fsp->open) {
-                       if (fsp->is_directory)
-                               close_directory(fsp); 
-                       else                  
-                               close_file(fsp,False); 
+               next=fsp->next;
+               if (fsp->vuid == vuid) {
+                       close_file(fsp,SHUTDOWN_CLOSE);
                }
        }
 }
 
 /****************************************************************************
-initialise file structures
+ Debug to enumerate all open files in the smbd.
 ****************************************************************************/
-void file_init(void)
-{
-       file_bmap = bitmap_allocate(MAX_FNUMS);
-       fd_bmap = bitmap_allocate(MAX_FNUMS);
 
-       if (!file_bmap || !fd_bmap) {
-               exit_server("out of memory in file_init");
-       }
+void file_dump_open_table(void)
+{
+       int count=0;
+       files_struct *fsp;
 
-#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
-       {
-               struct rlimit rlp;
-               getrlimit(RLIMIT_NOFILE, &rlp);
-               /* Set the fd limit to be MAX_FNUMS + 10 to
-                * account for the extra fd we need 
-                * as well as the log files and standard
-                * handles etc.  */
-               rlp.rlim_cur = (MAX_FNUMS+10>rlp.rlim_max)? 
-                       rlp.rlim_max:MAX_FNUMS+10;
-               setrlimit(RLIMIT_NOFILE, &rlp);
-               getrlimit(RLIMIT_NOFILE, &rlp);
-               DEBUG(3,("Maximum number of open files per session is %d\n",
-                        (int)rlp.rlim_cur));
+       for (fsp=Files;fsp;fsp=fsp->next,count++) {
+               DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, gen = %lu, fileid=%s\n",
+                       count, fsp->fnum, fsp->fsp_name, fsp->fh->fd, (unsigned long)fsp->fh->gen_id,
+                         file_id_string_tos(&fsp->file_id)));
        }
-#endif
 }
 
-
 /****************************************************************************
-close files open by a specified vuid
+ Find a fsp given a file descriptor.
 ****************************************************************************/
-void file_close_user(int vuid)
+
+files_struct *file_find_fd(int fd)
 {
-       files_struct *fsp, *next;
+       int count=0;
+       files_struct *fsp;
 
-       for (fsp=Files;fsp;fsp=next) {
-               next=fsp->next;
-               if ((fsp->vuid == vuid) && fsp->open) {
-                       if(!fsp->is_directory)
-                               close_file(fsp,False);
-                       else
-                               close_directory(fsp);
+       for (fsp=Files;fsp;fsp=fsp->next,count++) {
+               if (fsp->fh->fd == fd) {
+                       if (count > 10) {
+                               DLIST_PROMOTE(Files, fsp);
+                       }
+                       return fsp;
                }
        }
-}
 
+       return NULL;
+}
 
 /****************************************************************************
-find a fsp given a device, inode and timevalue
+ Find a fsp given a device, inode and file_id.
 ****************************************************************************/
-files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
+
+files_struct *file_find_dif(struct file_id id, unsigned long gen_id)
 {
        int count=0;
        files_struct *fsp;
 
        for (fsp=Files;fsp;fsp=fsp->next,count++) {
-               if (fsp->open && 
-                   fsp->fd_ptr->dev == dev && 
-                   fsp->fd_ptr->inode == inode &&
-                   fsp->open_time.tv_sec == tval->tv_sec &&
-                   fsp->open_time.tv_usec == tval->tv_usec) {
+               /* We can have a fsp->fh->fd == -1 here as it could be a stat open. */
+               if (file_id_equal(&fsp->file_id, &id) &&
+                   fsp->fh->gen_id == gen_id ) {
                        if (count > 10) {
                                DLIST_PROMOTE(Files, fsp);
                        }
+                       /* Paranoia check. */
+                       if ((fsp->fh->fd == -1) &&
+                           (fsp->oplock_type != NO_OPLOCK) &&
+                           (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) {
+                               DEBUG(0,("file_find_dif: file %s file_id = %s, gen = %u \
+oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, 
+                                        file_id_string_tos(&fsp->file_id),
+                                        (unsigned int)fsp->fh->gen_id,
+                                        (unsigned int)fsp->oplock_type ));
+                               smb_panic("file_find_dif");
+                       }
                        return fsp;
                }
        }
@@ -282,70 +292,155 @@ files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval
        return NULL;
 }
 
-
 /****************************************************************************
-find a fsp that is open for printing
+ Check if an fsp still exists.
 ****************************************************************************/
-files_struct *file_find_print(void)
+
+files_struct *file_find_fsp(files_struct *orig_fsp)
 {
        files_struct *fsp;
 
        for (fsp=Files;fsp;fsp=fsp->next) {
-               if (fsp->open && fsp->print_file) return fsp;
-       } 
+               if (fsp == orig_fsp)
+                       return fsp;
+       }
+
        return NULL;
 }
 
-
 /****************************************************************************
-sync open files on a connection
+ Find the first fsp given a device and inode.
+ We use a singleton cache here to speed up searching from getfilepathinfo
+ calls.
 ****************************************************************************/
-void file_sync_all(connection_struct *conn)
+
+files_struct *file_find_di_first(struct file_id id)
 {
-       files_struct *fsp, *next;
+       files_struct *fsp;
 
-       for (fsp=Files;fsp;fsp=next) {
-               next=fsp->next;
-               if (fsp->open && conn == fsp->conn) {
-                       sync_file(conn,fsp);
+       if (file_id_equal(&fsp_fi_cache.id, &id)) {
+               /* Positive or negative cache hit. */
+               return fsp_fi_cache.fsp;
+       }
+
+       fsp_fi_cache.id = id;
+
+       for (fsp=Files;fsp;fsp=fsp->next) {
+               if ( fsp->fh->fd != -1 &&
+                    file_id_equal(&fsp->file_id, &id)) {
+                       /* Setup positive cache. */
+                       fsp_fi_cache.fsp = fsp;
+                       return fsp;
                }
        }
+
+       /* Setup negative cache. */
+       fsp_fi_cache.fsp = NULL;
+       return NULL;
 }
 
+/****************************************************************************
+ Find the next fsp having the same device and inode.
+****************************************************************************/
+
+files_struct *file_find_di_next(files_struct *start_fsp)
+{
+       files_struct *fsp;
+
+       for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
+               if ( fsp->fh->fd != -1 &&
+                    file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
+                       return fsp;
+               }
+       }
+
+       return NULL;
+}
 
 /****************************************************************************
-free up a fd_ptr
+ Find a fsp that is open for printing.
 ****************************************************************************/
-void fd_ptr_free(file_fd_struct *fd_ptr)
+
+files_struct *file_find_print(void)
 {
-       DLIST_REMOVE(FileFd, fd_ptr);
+       files_struct *fsp;
 
-       bitmap_clear(fd_bmap, fd_ptr->fdnum);
-       fd_ptr_used--;
+       for (fsp=Files;fsp;fsp=fsp->next) {
+               if (fsp->print_file) {
+                       return fsp;
+               }
+       } 
+
+       return NULL;
+}
+
+/****************************************************************************
+ Set a pending modtime across all files with a given dev/ino pair.
+ Record the owner of that modtime.
+****************************************************************************/
+
+void fsp_set_pending_modtime(files_struct *tfsp, const struct timespec mod)
+{
+       files_struct *fsp;
 
-       DEBUG(5,("freed fd_ptr structure %d (%d used)\n",
-                fd_ptr->fdnum, fd_ptr_used));
+       if (null_timespec(mod)) {
+               return;
+       }
 
-       /* paranoia */
-       ZERO_STRUCTP(fd_ptr);
+       for (fsp = Files;fsp;fsp=fsp->next) {
+               if ( fsp->fh->fd != -1 && file_id_equal(&fsp->file_id, &tfsp->file_id)) {
+                       fsp->pending_modtime = mod;
+                       fsp->pending_modtime_owner = False;
+               }
+       }
 
-       free(fd_ptr);
+       tfsp->pending_modtime_owner = True;
 }
 
+/****************************************************************************
+ Sync open files on a connection.
+****************************************************************************/
+
+void file_sync_all(connection_struct *conn)
+{
+       files_struct *fsp, *next;
+
+       for (fsp=Files;fsp;fsp=next) {
+               next=fsp->next;
+               if ((conn == fsp->conn) && (fsp->fh->fd != -1)) {
+                       sync_file(conn, fsp, True /* write through */);
+               }
+       }
+}
 
 /****************************************************************************
-free up a fsp
+ Free up a fsp.
 ****************************************************************************/
+
 void file_free(files_struct *fsp)
 {
        DLIST_REMOVE(Files, fsp);
 
        string_free(&fsp->fsp_name);
 
-       if (fsp->fd_ptr && fsp->fd_ptr->ref_count == 0) {
-               fd_ptr_free(fsp->fd_ptr);
+       if (fsp->fake_file_handle) {
+               destroy_fake_file_handle(&fsp->fake_file_handle);
+       }
+
+       if (fsp->fh->ref_count == 1) {
+               SAFE_FREE(fsp->fh);
+       } else {
+               fsp->fh->ref_count--;
+       }
+
+       if (fsp->notify) {
+               notify_remove(fsp->conn->notify_ctx, fsp);
+               TALLOC_FREE(fsp->notify);
        }
 
+       /* Ensure this event will never fire. */
+       TALLOC_FREE(fsp->oplock_timeout);
+
        bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
        files_used--;
 
@@ -356,59 +451,116 @@ void file_free(files_struct *fsp)
           information */
        ZERO_STRUCTP(fsp);
 
-       if (fsp == chain_fsp) chain_fsp = NULL;
+       if (fsp == chain_fsp) {
+               chain_fsp = NULL;
+       }
 
-       free(fsp);
-}
+       /* Closing a file can invalidate the positive cache. */
+       if (fsp == fsp_fi_cache.fsp) {
+               ZERO_STRUCT(fsp_fi_cache);
+       }
 
+       SAFE_FREE(fsp);
+}
 
 /****************************************************************************
-get a fsp from a packet given the offset of a 16 bit fnum
+ Get an fsp from a 16 bit fnum.
 ****************************************************************************/
-files_struct *file_fsp(char *buf, int where)
+
+files_struct *file_fnum(uint16 fnum)
 {
-       int fnum, count=0;
        files_struct *fsp;
-
-       if (chain_fsp) return chain_fsp;
-
-       fnum = SVAL(buf, where);
+       int count=0;
 
        for (fsp=Files;fsp;fsp=fsp->next, count++) {
                if (fsp->fnum == fnum) {
-                       chain_fsp = fsp;
                        if (count > 10) {
                                DLIST_PROMOTE(Files, fsp);
                        }
                        return fsp;
                }
        }
-
        return NULL;
 }
 
 /****************************************************************************
- Reset the chained fsp - done at the start of a packet reply
+ Get an fsp from a packet given the offset of a 16 bit fnum.
 ****************************************************************************/
 
-void file_chain_reset(void)
+files_struct *file_fsp(uint16 fid)
 {
-       chain_fsp = NULL;
+       files_struct *fsp;
+
+       if (chain_fsp) {
+               return chain_fsp;
+       }
+
+       fsp = file_fnum(fid);
+       if (fsp) {
+               chain_fsp = fsp;
+       }
+       return fsp;
 }
 
 /****************************************************************************
-Save the chained fsp - done when about to do an oplock break.
+ Reset the chained fsp - done at the start of a packet reply.
 ****************************************************************************/
 
-void file_chain_save(void)
+void file_chain_reset(void)
 {
-       oplock_save_chain_fsp = chain_fsp;
+       chain_fsp = NULL;
 }
 
 /****************************************************************************
-Restore the chained fsp - done after an oplock break.
+ Duplicate the file handle part for a DOS or FCB open.
 ****************************************************************************/
-void file_chain_restore(void)
+
+NTSTATUS dup_file_fsp(files_struct *fsp,
+                               uint32 access_mask,
+                               uint32 share_access,
+                               uint32 create_options,
+                               files_struct **result)
 {
-       chain_fsp = oplock_save_chain_fsp;
+       NTSTATUS status;
+       files_struct *dup_fsp;
+
+       status = file_new(fsp->conn, &dup_fsp);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       SAFE_FREE(dup_fsp->fh);
+
+       dup_fsp->fh = fsp->fh;
+       dup_fsp->fh->ref_count++;
+
+       dup_fsp->file_id = fsp->file_id;
+       dup_fsp->initial_allocation_size = fsp->initial_allocation_size;
+       dup_fsp->mode = fsp->mode;
+       dup_fsp->file_pid = fsp->file_pid;
+       dup_fsp->vuid = fsp->vuid;
+       dup_fsp->open_time = fsp->open_time;
+       dup_fsp->access_mask = access_mask;
+       dup_fsp->share_access = share_access;
+       dup_fsp->pending_modtime_owner = fsp->pending_modtime_owner;
+       dup_fsp->pending_modtime = fsp->pending_modtime;
+       dup_fsp->last_write_time = fsp->last_write_time;
+       dup_fsp->oplock_type = fsp->oplock_type;
+       dup_fsp->can_lock = fsp->can_lock;
+       dup_fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
+       if (!CAN_WRITE(fsp->conn)) {
+               dup_fsp->can_write = False;
+       } else {
+               dup_fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False;
+       }
+       dup_fsp->print_file = fsp->print_file;
+       dup_fsp->modified = fsp->modified;
+       dup_fsp->is_directory = fsp->is_directory;
+       dup_fsp->is_stat = fsp->is_stat;
+       dup_fsp->aio_write_behind = fsp->aio_write_behind;
+        string_set(&dup_fsp->fsp_name,fsp->fsp_name);
+
+       *result = dup_fsp;
+       return NT_STATUS_OK;
 }