]> Zhao Yanbai Git Server - minix.git/commitdiff
VFS: reimplement truncate mtime/ctime fix
authorDavid van Moolenbroek <david@minix3.org>
Fri, 20 Apr 2012 09:12:04 +0000 (11:12 +0200)
committerDavid van Moolenbroek <david@minix3.org>
Fri, 20 Apr 2012 09:35:59 +0000 (11:35 +0200)
POSIX mandates that a file's modification and change time be left
untouched upon truncate/ftruncate iff the file size does not change.
However, an open(O_TRUNC) call must always update the modification and
change time of the file, even if it was already zero-sized. VFS uses
the file systems' truncate call to implement O_TRUNC. This patch
replaces git-255ae85, which did not take into account the open case.
The size check is now moved into VFS, so that individual file systems
need not check for this case anymore.

servers/ext2/link.c
servers/mfs/link.c
servers/vfs/link.c
test/test16.c

index 5786076c43e6aa4d8f1c2ef34181129597114a56..9f741aa1d67ade7bc81d9357488f0026f1e0dce1 100644 (file)
@@ -563,8 +563,6 @@ off_t newsize;                      /* inode must become this size */
        return(EINVAL);
   if (newsize > rip->i_sp->s_max_size) /* don't let inode grow too big */
        return(EFBIG);
-  if (rip->i_size == newsize)
-       return(OK);
 
   /* Free the actual space if truncating. */
   if (newsize < rip->i_size) {
index 2c499810b0c3fdd584c8c252d31cb7ce6e4e739d..47f6325a402be04c9ea05083c83912bda950c76d 100644 (file)
@@ -533,8 +533,6 @@ off_t newsize;                      /* inode must become this size */
   file_type = rip->i_mode & I_TYPE;    /* check to see if file is special */
   if (file_type == I_CHAR_SPECIAL || file_type == I_BLOCK_SPECIAL)
        return(EINVAL);
-  if (rip->i_size == newsize)
-       return(OK);
   if (newsize > rip->i_sp->s_max_size) /* don't let inode grow too big */
        return(EFBIG);
 
index e6bfeb2533076c9592df482af79889f9a32d41dc..c343bce4ca99ab7268990f0de921df2ec012a480 100644 (file)
@@ -310,8 +310,16 @@ int do_truncate()
   if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code);
 
   /* Ask FS to truncate the file */
-  if ((r = forbidden(fp, vp, W_BIT)) == OK)
-       r = truncate_vnode(vp, length);
+  if ((r = forbidden(fp, vp, W_BIT)) == OK) {
+       /* If the file size does not change, do not make the actual call. This
+        * ensures that the file times are retained when the file size remains
+        * the same, which is a POSIX requirement.
+        */
+       if (S_ISREG(vp->v_mode) && vp->v_size == length)
+               r = OK;
+       else
+               r = truncate_vnode(vp, length);
+  }
 
   unlock_vnode(vp);
   unlock_vmnt(vmp);
@@ -326,6 +334,7 @@ int do_ftruncate()
 {
 /* As with do_truncate(), truncate_vnode() does the actual work. */
   struct filp *rfilp;
+  struct vnode *vp;
   int r;
   off_t length;
 
@@ -338,10 +347,18 @@ int do_ftruncate()
   if ((rfilp = get_filp(scratch(fp).file.fd_nr, VNODE_WRITE)) == NULL)
        return(err_code);
 
+  vp = rfilp->filp_vno;
+
   if (!(rfilp->filp_mode & W_BIT))
        r = EBADF;
+  else if (S_ISREG(vp->v_mode) && vp->v_size == length)
+       /* If the file size does not change, do not make the actual call. This
+        * ensures that the file times are retained when the file size remains
+        * the same, which is a POSIX requirement.
+        */
+       r = OK;
   else
-       r = truncate_vnode(rfilp->filp_vno, length);
+       r = truncate_vnode(vp, length);
 
   unlock_filp(rfilp);
   return(r);
@@ -361,6 +378,11 @@ off_t newsize;
   assert(tll_locked_by_me(&vp->v_lock));
   file_type = vp->v_mode & I_TYPE;
   if (file_type != I_REGULAR && file_type != I_NAMED_PIPE) return(EINVAL);
+
+  /* We must not compare the old and the new size here: this function may be
+   * called for open(2), which requires an update to the file times if O_TRUNC
+   * is given, even if the file size remains the same.
+   */
   if ((r = req_ftrunc(vp->v_fs_e, vp->v_inode_nr, newsize, 0)) == OK)
        vp->v_size = newsize;
   return(r);
index 74c4205081d0b19d2446fd05da2966dc27174174..2f174479fdb6f00f91185433f75ff885ce034c67 100644 (file)
@@ -126,6 +126,14 @@ void test16a()
   if (yc != pc) e(39);
   if (ym != pm) e(40);
   if (close(fd) != 0) e(41);
+  /* Try once more, now without changing the file size. */
+  sleep(1);
+  if ( (fd = open("T16.e", O_WRONLY|O_TRUNC)) < 0) e(89);
+  get_times("T16.e", &a, &c, &m);
+  if (c != m) e(90);
+  if (c == xc) e(91);
+  if (m == xm) e(92);
+  if (close(fd) != 0) e(93);
 
   /* Test the times for link/unlink. */
   get_times("T16.e", &a, &c, &m);