[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / smbd / files.c
index a37d190f01ca43b61fdf22f30fb0b945e8308ae8..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;
 
-#define MAX_OPEN_FILES 100
+#define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < real_max_open_files))
 
-#define MAX_FNUMS (MAX_OPEN_FILES+MAX_OPEN_DIRECTORIES)
-#define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < MAX_FNUMS))
+#define FILE_HANDLE_OFFSET 0x1000
 
-static files_struct Files[MAX_FNUMS];
+static struct bitmap *file_bmap;
 
-/*
- * Indirection for file fd's. Needed as POSIX locking
- * is based on file/process, not fd/process.
- */
-static file_fd_struct FileFd[MAX_OPEN_FILES];
-static int max_file_fd_used = 0;
+static files_struct *Files;
+/* a fsp to use when chaining */
+static files_struct *chain_fsp = NULL;
 
+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;
 
 /****************************************************************************
-  find first available file slot
+ Return a unique number identifying this fsp over the life of this pid.
 ****************************************************************************/
-files_struct *find_free_file(void )
+
+static unsigned long get_gen_count(void)
+{
+       static unsigned long file_gen_counter;
+
+       if ((++file_gen_counter) == 0)
+               return ++file_gen_counter;
+       return file_gen_counter;
+}
+
+/****************************************************************************
+ Find first available file slot.
+****************************************************************************/
+
+NTSTATUS file_new(connection_struct *conn, files_struct **result)
 {
        int i;
        static int first_file;
+       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
@@ -52,270 +69,498 @@ files_struct *find_free_file(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;
-               if (first_file == 0) first_file = 1;
+               first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
        }
 
-       if (first_file >= MAX_FNUMS)
-               first_file = 1;
+       /* TODO: Port the id-tree implementation from Samba4 */
 
-       for (i=first_file;i<MAX_FNUMS;i++)
-               if (!Files[i].open && !Files[i].reserved) {
-                       memset(&Files[i], 0, sizeof(Files[i]));
-                       first_file = i+1;
-                       Files[i].reserved = True;
-                       Files[i].fnum = i;
-                       return &Files[i];
-               }
+       i = bitmap_find(file_bmap, first_file);
+       if (i == -1) {
+               DEBUG(0,("ERROR! Out of file structures\n"));
+               /* 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;
+       }
 
-       /* returning a file handle of 0 is a bad idea - so we start at 1 */
-       for (i=1;i<first_file;i++)
-               if (!Files[i].open && !Files[i].reserved) {
-                       memset(&Files[i], 0, sizeof(Files[i]));
-                       first_file = i+1;
-                       Files[i].reserved = True;
-                       Files[i].fnum = i;
-                       return &Files[i];
-               }
+       fsp = SMB_MALLOC_P(files_struct);
+       if (!fsp) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
-        /* 
-         * 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 (i=first_file;i<MAX_FNUMS;i++) {
-          if(attempt_close_oplocked_file( &Files[i])) {
-            memset(&Files[i], 0, sizeof(Files[i]));
-            first_file = i+1;
-            Files[i].reserved = True;
-           Files[i].fnum = i;
-           return &Files[i];
-          }
-        }
-
-        for (i=1;i<MAX_FNUMS;i++) {
-          if(attempt_close_oplocked_file( &Files[i])) {
-            memset(&Files[i], 0, sizeof(Files[i]));
-            first_file = i+1;
-            Files[i].reserved = True;
-           Files[i].fnum = i;
-           return &Files[i];
-          }
-        }
-
-       DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
-       return NULL;
-}
+       ZERO_STRUCTP(fsp);
+
+       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;
+       SMB_ASSERT(fsp->fnum < 65536);
 
+       string_set(&fsp->fsp_name,"");
+       
+       DLIST_ADD(Files, fsp);
+
+       DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
+                i, fsp->fnum, files_used));
+
+       chain_fsp = 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(struct stat *sbuf)
+
+void file_close_conn(connection_struct *conn)
 {
-  int i;
-  file_fd_struct *fd_ptr;
-
-  if(sbuf == 0)
-    return 0;
-
-  for(i = 0; i <= max_file_fd_used; i++) {
-    fd_ptr = &FileFd[i];
-    if((fd_ptr->ref_count > 0) &&
-       (((uint32)sbuf->st_dev) == fd_ptr->dev) &&
-       (((uint32)sbuf->st_ino) == fd_ptr->inode)) {
-      fd_ptr->ref_count++;
-      DEBUG(3,
-       ("Re-used file_fd_struct %d, dev = %x, inode = %x, ref_count = %d\n",
-        i, fd_ptr->dev, fd_ptr->inode, fd_ptr->ref_count));
-      return fd_ptr;
-    }
-  }
-  return 0;
+       files_struct *fsp, *next;
+       
+       for (fsp=Files;fsp;fsp=next) {
+               next = fsp->next;
+               if (fsp->conn == conn) {
+                       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.
+ Close all open files for a pid and a vuid.
 ****************************************************************************/
-file_fd_struct *fd_get_new(void)
+
+void file_close_pid(uint16 smbpid, int vuid)
 {
-  extern struct current_user current_user;
-  int i;
-  file_fd_struct *fd_ptr;
-
-  for(i = 0; i < MAX_OPEN_FILES; i++) {
-    fd_ptr = &FileFd[i];
-    if(fd_ptr->ref_count == 0) {
-      fd_ptr->dev = (uint32)-1;
-      fd_ptr->inode = (uint32)-1;
-      fd_ptr->fd = -1;
-      fd_ptr->fd_readonly = -1;
-      fd_ptr->fd_writeonly = -1;
-      fd_ptr->real_open_flags = -1;
-      fd_ptr->uid_cache_count = 0;
-      fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
-      fd_ptr->ref_count++;
-      /* Increment max used counter if neccessary, cuts down
-         on search time when re-using */
-      if(i > max_file_fd_used)
-        max_file_fd_used = i;
-      DEBUG(3,("Allocated new file_fd_struct %d, dev = %x, inode = %x\n",
-               i, fd_ptr->dev, fd_ptr->inode));
-      return fd_ptr;
-    }
-  }
-  DEBUG(1,("ERROR! Out of file_fd structures - perhaps increase MAX_OPEN_FILES?\n"));
-  return 0;
+       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); 
+               }
+       }
 }
 
-
 /****************************************************************************
-close all open files for a connection
+ Initialise file structures.
 ****************************************************************************/
-void file_close_conn(connection_struct *conn)
+
+#define MAX_OPEN_FUDGEFACTOR 20
+
+void file_init(void)
 {
-  int i;
-  for (i=0;i<MAX_FNUMS;i++)
-    if (Files[i].conn == conn && Files[i].open) {
-      if(Files[i].is_directory)
-        close_directory(&Files[i]); 
-      else                  
-        close_file(&Files[i],False); 
-    }
+       int request_max_open_files = lp_max_open_files();
+       int real_lim;
+
+       /*
+        * 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);
+
+       real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR;
+
+       if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536)
+               real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
+
+       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));
+       }
+
+       SMB_ASSERT(real_max_open_files > 100);
+
+       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);
 }
 
 /****************************************************************************
-initialise file structures
+ Close files open by a specified vuid.
 ****************************************************************************/
-void file_init(void)
+
+void file_close_user(int vuid)
 {
-       int i;
+       files_struct *fsp, *next;
 
-#ifdef HAVE_GETRLIMIT
-#ifdef RLIMIT_NOFILE
-       {
-               struct rlimit rlp;
-               getrlimit(RLIMIT_NOFILE, &rlp);
-               /* Set the fd limit to be MAX_OPEN_FILES + 10 to
-                * account for the extra fd we need to read
-                * directories, 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=next) {
+               next=fsp->next;
+               if (fsp->vuid == vuid) {
+                       close_file(fsp,SHUTDOWN_CLOSE);
+               }
        }
-#endif
-#endif
+}
 
-  
+/****************************************************************************
+ Debug to enumerate all open files in the smbd.
+****************************************************************************/
+
+void file_dump_open_table(void)
+{
+       int count=0;
+       files_struct *fsp;
 
-       for (i=0;i<MAX_FNUMS;i++) {
-               Files[i].open = False;
-               string_init(&Files[i].fsp_name,"");
+       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)));
        }
+}
 
-       for (i=0;i<MAX_OPEN_FILES;i++) {
-               file_fd_struct *fd_ptr = &FileFd[i];
-               fd_ptr->ref_count = 0;
-               fd_ptr->dev = (int32)-1;
-               fd_ptr->inode = (int32)-1;
-               fd_ptr->fd = -1;
-               fd_ptr->fd_readonly = -1;
-               fd_ptr->fd_writeonly = -1;
-               fd_ptr->real_open_flags = -1;
+/****************************************************************************
+ Find a fsp given a file descriptor.
+****************************************************************************/
+
+files_struct *file_find_fd(int fd)
+{
+       int count=0;
+       files_struct *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 fnum
+ Find a fsp given a device, inode and file_id.
 ****************************************************************************/
-files_struct *file_fsp(int fnum)
+
+files_struct *file_find_dif(struct file_id id, unsigned long gen_id)
 {
-       if (!VALID_FNUM(fnum)) return NULL;
-       return &Files[fnum];
+       int count=0;
+       files_struct *fsp;
+
+       for (fsp=Files;fsp;fsp=fsp->next,count++) {
+               /* 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;
+               }
+       }
+
+       return NULL;
 }
 
+/****************************************************************************
+ Check if an fsp still exists.
+****************************************************************************/
+
+files_struct *file_find_fsp(files_struct *orig_fsp)
+{
+       files_struct *fsp;
+
+       for (fsp=Files;fsp;fsp=fsp->next) {
+               if (fsp == orig_fsp)
+                       return fsp;
+       }
+
+       return NULL;
+}
 
 /****************************************************************************
-close files open by a specified vuid
+ Find the first fsp given a device and inode.
+ We use a singleton cache here to speed up searching from getfilepathinfo
+ calls.
 ****************************************************************************/
-void file_close_user(int vuid)
+
+files_struct *file_find_di_first(struct file_id id)
 {
-       int i;
-       for (i=0;i<MAX_FNUMS;i++) {
-               files_struct *fsp = &Files[i];
-               if ((fsp->vuid == vuid) && fsp->open) {
-                       if(!fsp->is_directory)
-                               close_file(fsp,False);
-                       else
-                               close_directory(fsp);
+       files_struct *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 a fsp given a device, inode and timevalue
+ Find the next fsp having the same device and inode.
 ****************************************************************************/
-files_struct *file_find_dit(int dev, int inode, struct timeval *tval)
+
+files_struct *file_find_di_next(files_struct *start_fsp)
 {
-       int i;
-       for (i=0;i<MAX_FNUMS;i++) {
-               files_struct *fsp = &Files[i];
-               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) {
+       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;
 }
 
 /****************************************************************************
-find a fsp that is open for printing
+ Find a fsp that is open for printing.
 ****************************************************************************/
+
 files_struct *file_find_print(void)
 {
-       int i;
+       files_struct *fsp;
 
-       for (i=0;i<MAX_FNUMS;i++) {
-               files_struct *fsp = &Files[i];
-               if (fsp->open && fsp->print_file) {
+       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;
+
+       if (null_timespec(mod)) {
+               return;
+       }
+
+       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;
+               }
+       }
+
+       tfsp->pending_modtime_owner = True;
+}
 
 /****************************************************************************
-sync open files on a connection
+ Sync open files on a connection.
 ****************************************************************************/
+
 void file_sync_all(connection_struct *conn)
 {
-       int i;
-       for (i=0;i<MAX_FNUMS;i++) {
-               files_struct *fsp = &Files[i];
-               if (fsp->open && conn == fsp->conn) {
-                       sync_file(conn,fsp);
+       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.
+****************************************************************************/
 
 void file_free(files_struct *fsp)
 {
-       memset(fsp, 0, sizeof(*fsp));
+       DLIST_REMOVE(Files, fsp);
+
+       string_free(&fsp->fsp_name);
+
+       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--;
+
+       DEBUG(5,("freed files structure %d (%d used)\n",
+                fsp->fnum, files_used));
+
+       /* this is paranoia, just in case someone tries to reuse the 
+          information */
+       ZERO_STRUCTP(fsp);
+
+       if (fsp == chain_fsp) {
+               chain_fsp = NULL;
+       }
+
+       /* Closing a file can invalidate the positive cache. */
+       if (fsp == fsp_fi_cache.fsp) {
+               ZERO_STRUCT(fsp_fi_cache);
+       }
+
+       SAFE_FREE(fsp);
+}
+
+/****************************************************************************
+ Get an fsp from a 16 bit fnum.
+****************************************************************************/
+
+files_struct *file_fnum(uint16 fnum)
+{
+       files_struct *fsp;
+       int count=0;
+
+       for (fsp=Files;fsp;fsp=fsp->next, count++) {
+               if (fsp->fnum == fnum) {
+                       if (count > 10) {
+                               DLIST_PROMOTE(Files, fsp);
+                       }
+                       return fsp;
+               }
+       }
+       return NULL;
+}
+
+/****************************************************************************
+ Get an fsp from a packet given the offset of a 16 bit fnum.
+****************************************************************************/
+
+files_struct *file_fsp(uint16 fid)
+{
+       files_struct *fsp;
+
+       if (chain_fsp) {
+               return chain_fsp;
+       }
+
+       fsp = file_fnum(fid);
+       if (fsp) {
+               chain_fsp = fsp;
+       }
+       return fsp;
+}
+
+/****************************************************************************
+ Reset the chained fsp - done at the start of a packet reply.
+****************************************************************************/
+
+void file_chain_reset(void)
+{
+       chain_fsp = NULL;
+}
+
+/****************************************************************************
+ Duplicate the file handle part for a DOS or FCB open.
+****************************************************************************/
+
+NTSTATUS dup_file_fsp(files_struct *fsp,
+                               uint32 access_mask,
+                               uint32 share_access,
+                               uint32 create_options,
+                               files_struct **result)
+{
+       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;
 }