r5720: Attempt to fix bug #2382 (Excel shared workbook stops working). Also
authorJeremy Allison <jra@samba.org>
Thu, 10 Mar 2005 01:30:14 +0000 (01:30 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:55:57 +0000 (10:55 -0500)
incorporates part of the fix created by ke_miyata@itg.hitachi.co.jp
for bug #2045 (MS-Office behavior of timestamp).
Jeremy.

source/smbd/files.c
source/smbd/nttrans.c
source/smbd/reply.c
source/smbd/trans2.c

index ecf39c2b54f0d70536c7fb5df52079b6968846f6..547206815ed7bf360dc623cca07f18b0aad1b298 100644 (file)
@@ -37,6 +37,13 @@ static files_struct *oplock_save_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;
+       SMB_DEV_T dev;
+       SMB_INO_T inode;
+} fsp_fi_cache;
+
 /****************************************************************************
  Return a unique number identifying this fsp over the life of this pid.
 ****************************************************************************/
@@ -122,6 +129,11 @@ files_struct *file_new(connection_struct *conn)
                 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);
+       }
        
        return fsp;
 }
@@ -299,19 +311,34 @@ files_struct *file_find_fsp(files_struct *orig_fsp)
 
 /****************************************************************************
  Find the first fsp given a device and inode.
+ We use a singleton cache here to speed up searching from getfilepathinfo
+ calls.
 ****************************************************************************/
 
 files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode)
 {
        files_struct *fsp;
 
+       if (fsp_fi_cache.dev == dev && fsp_fi_cache.inode == inode) {
+               /* Positive or negative cache hit. */
+               return fsp_fi_cache.fsp;
+       }
+
+       fsp_fi_cache.dev = dev;
+       fsp_fi_cache.inode = inode;
+
        for (fsp=Files;fsp;fsp=fsp->next) {
                if ( fsp->fd != -1 &&
                                fsp->dev == dev &&
-                               fsp->inode == inode )
+                               fsp->inode == inode ) {
+                       /* Setup positive cache. */
+                       fsp_fi_cache.fsp = fsp;
                        return fsp;
+               }
        }
 
+       /* Setup negative cache. */
+       fsp_fi_cache.fsp = NULL;
        return NULL;
 }
 
@@ -342,12 +369,35 @@ files_struct *file_find_print(void)
        files_struct *fsp;
 
        for (fsp=Files;fsp;fsp=fsp->next) {
-               if (fsp->print_file) return fsp;
+               if (fsp->print_file) {
+                       return fsp;
+               }
        } 
 
        return NULL;
 }
 
+/****************************************************************************
+ Set a pending modtime across all files with a given dev/ino pair.
+****************************************************************************/
+
+void fsp_set_pending_modtime(files_struct *tfsp, time_t pmod)
+{
+       files_struct *fsp;
+
+       if (null_mtime(pmod)) {
+               return;
+       }
+
+       for (fsp = Files;fsp;fsp=fsp->next) {
+               if ( fsp->fd != -1 &&
+                               fsp->dev == tfsp->dev &&
+                               fsp->inode == tfsp->inode ) {
+                       fsp->pending_modtime = pmod;
+               }
+       }
+}
+
 /****************************************************************************
  Sync open files on a connection.
 ****************************************************************************/
@@ -392,6 +442,11 @@ void file_free(files_struct *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);
 }
 
index eb2232942be74bafdf69ea983558f566c3b75b03..fbb73640901d75be2decfa48244e77bc32295d19 100644 (file)
@@ -1698,7 +1698,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
        close_file(fsp1,False);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       fsp2->pending_modtime = sbuf1.st_mtime;
+       fsp_set_pending_modtime(fsp2, sbuf1.st_mtime);
 
        close_ret = close_file(fsp2,False);
 
index 2dfeebbb9f73da0a1e94518ff5599c549900bf3c..f149b79f793bd7a5a476c9199cd6556a972f58dd 100644 (file)
@@ -2875,6 +2875,13 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                         fsp->fd, fsp->fnum,
                         conn->num_files_open));
  
+               /*
+                * Take care of any time sent in the close.
+                */
+
+               mtime = make_unix_date3(inbuf+smb_vwv1);
+               fsp_set_pending_modtime(fsp, mtime);
+
                /*
                 * close_file() returns the unix errno if an error
                 * was detected on close - normally this is due to
@@ -2886,16 +2893,6 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                        END_PROFILE(SMBclose);
                        return (UNIXERROR(ERRHRD,ERRgeneral));
                }
-
-               /*
-                * Now take care of any time sent in the close.
-                */
-
-               mtime = make_unix_date3(inbuf+smb_vwv1);
-               
-               /* try and set the date */
-               set_filetime(conn, file_name, mtime);
-
        }  
 
        /* We have a cached error */
@@ -4233,7 +4230,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
        close_file(fsp1,False);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       fsp2->pending_modtime = src_sbuf.st_mtime;
+       fsp_set_pending_modtime( fsp2, src_sbuf.st_mtime);
 
        /*
         * As we are opening fsp1 read-only we only expect
@@ -4917,7 +4914,7 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
         * Sometimes times are sent as zero - ignore them.
         */
 
-       if ((unix_times.actime == 0) && (unix_times.modtime == 0)) {
+       if (null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
                /* Ignore request */
                if( DEBUGLVL( 3 ) ) {
                        dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
@@ -4925,12 +4922,13 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
                }
                END_PROFILE(SMBsetattrE);
                return(outsize);
-       } else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) {
-               /* set modify time = to access time if modify time was 0 */
+       } else if (!null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
+               /* set modify time = to access time if modify time was unset */
                unix_times.modtime = unix_times.actime;
        }
 
        /* Set the date on this file */
+       /* Should we set pending modtime here ? JRA */
        if(file_utime(conn, fsp->fsp_name, &unix_times)) {
                END_PROFILE(SMBsetattrE);
                return ERROR_DOS(ERRDOS,ERRnoaccess);
@@ -5170,6 +5168,7 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
        put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
+       /* Should we check pending modtime here ? JRA */
        put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
 
        if (mode & aDIR) {
index cb9b7db47272586e9f8cb3d17f4edbfe838782e3..3f3d9c2f461fa33975116b9d24c6050bc6c7f336 100644 (file)
@@ -2469,9 +2469,18 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
 
        c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
 
-       if (fsp && fsp->pending_modtime) {
-               /* the pending modtime overrides the current modtime */
-               sbuf.st_mtime = fsp->pending_modtime;
+       if (fsp) {
+               if (fsp->pending_modtime) {
+                       /* the pending modtime overrides the current modtime */
+                       sbuf.st_mtime = fsp->pending_modtime;
+               }
+       } else {
+               /* Do we have this path open ? */
+               files_struct *fsp1 = file_find_di_first(sbuf.st_dev, sbuf.st_ino);
+               if (fsp1 && fsp1->pending_modtime) {
+                       /* the pending modtime overrides the current modtime */
+                       sbuf.st_mtime = fsp1->pending_modtime;
+               }
        }
 
        if (lp_dos_filetime_resolution(SNUM(conn))) {
@@ -3323,9 +3332,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
                                tvs.modtime = write_time;
                        }
                        /* Prefer a defined time to an undefined one. */
-                       if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
-                               tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1
-                                       ? changed_time : write_time);
+                       if (null_mtime(tvs.modtime)) {
+                               tvs.modtime = null_mtime(write_time) ? changed_time : write_time;
+                       }
 
                        /* attributes */
                        dosmode = IVAL(pdata,32);
@@ -3805,11 +3814,13 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
        }
 
        /* get some defaults (no modifications) if any info is zero or -1. */
-       if (tvs.actime == (time_t)0 || tvs.actime == (time_t)-1)
+       if (null_mtime(tvs.actime)) {
                tvs.actime = sbuf.st_atime;
+       }
 
-       if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
+       if (null_mtime(tvs.modtime)) {
                tvs.modtime = sbuf.st_mtime;
+       }
 
        DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
        DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
@@ -3841,30 +3852,6 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
         * Try and set the times, size and mode of this file -
         * if they are different from the current values
         */
-       if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) {
-               if(fsp != NULL) {
-                       /*
-                        * This was a setfileinfo on an open file.
-                        * NT does this a lot. We also need to 
-                        * set the time here, as it can be read by 
-                        * FindFirst/FindNext and with the patch for bug #2045
-                        * in smbd/fileio.c it ensures that this timestamp is
-                        * kept sticky even after a write. We save the request
-                        * away and will set it on file close and after a write. JRA.
-                        */
-
-                       if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
-                               DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n", ctime(&tvs.modtime) ));
-                               fsp->pending_modtime = tvs.modtime;
-                       }
-
-                       DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
-
-                       if(file_utime(conn, fname, &tvs)!=0) {
-                               return(UNIXERROR(ERRDOS,ERRnoaccess));
-                       }
-               }
-       }
 
        /* check the mode isn't different, before changing it */
        if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, &sbuf))) {
@@ -3877,6 +3864,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                }
        }
 
+       /* Now the size. */
        if (size != get_file_size(sbuf)) {
 
                int ret;
@@ -3917,6 +3905,34 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        return (UNIXERROR(ERRHRD,ERRdiskfull));
        }
 
+       /*
+        * Finally the times.
+        */
+       if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) {
+               if(fsp != NULL) {
+                       /*
+                        * This was a setfileinfo on an open file.
+                        * NT does this a lot. We also need to 
+                        * set the time here, as it can be read by 
+                        * FindFirst/FindNext and with the patch for bug #2045
+                        * in smbd/fileio.c it ensures that this timestamp is
+                        * kept sticky even after a write. We save the request
+                        * away and will set it on file close and after a write. JRA.
+                        */
+
+                       if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
+                               DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n", ctime(&tvs.modtime) ));
+                               fsp_set_pending_modtime(fsp, tvs.modtime);
+                       }
+
+               }
+               DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
+
+               if(file_utime(conn, fname, &tvs)!=0) {
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+               }
+       }
+
        SSVAL(params,0,0);
        send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);