LCOV - code coverage report
Current view: top level - fs - utimes.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 62 71 87.3 %
Date: 2014-02-18 Functions: 5 5 100.0 %
Branches: 60 73 82.2 %

           Branch data     Line data    Source code
       1                 :            : #include <linux/compiler.h>
       2                 :            : #include <linux/file.h>
       3                 :            : #include <linux/fs.h>
       4                 :            : #include <linux/linkage.h>
       5                 :            : #include <linux/mount.h>
       6                 :            : #include <linux/namei.h>
       7                 :            : #include <linux/sched.h>
       8                 :            : #include <linux/stat.h>
       9                 :            : #include <linux/utime.h>
      10                 :            : #include <linux/syscalls.h>
      11                 :            : #include <asm/uaccess.h>
      12                 :            : #include <asm/unistd.h>
      13                 :            : 
      14                 :            : #ifdef __ARCH_WANT_SYS_UTIME
      15                 :            : 
      16                 :            : /*
      17                 :            :  * sys_utime() can be implemented in user-level using sys_utimes().
      18                 :            :  * Is this for backwards compatibility?  If so, why not move it
      19                 :            :  * into the appropriate arch directory (for those architectures that
      20                 :            :  * need it).
      21                 :            :  */
      22                 :            : 
      23                 :            : /* If times==NULL, set access and modification to current time,
      24                 :            :  * must be owner or have write permission.
      25                 :            :  * Else, update from *times, must be owner or super user.
      26                 :            :  */
      27                 :            : SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times)
      28                 :            : {
      29                 :            :         struct timespec tv[2];
      30                 :            : 
      31                 :            :         if (times) {
      32                 :            :                 if (get_user(tv[0].tv_sec, &times->actime) ||
      33                 :            :                     get_user(tv[1].tv_sec, &times->modtime))
      34                 :            :                         return -EFAULT;
      35                 :            :                 tv[0].tv_nsec = 0;
      36                 :            :                 tv[1].tv_nsec = 0;
      37                 :            :         }
      38                 :            :         return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
      39                 :            : }
      40                 :            : 
      41                 :            : #endif
      42                 :            : 
      43                 :            : static bool nsec_valid(long nsec)
      44                 :            : {
      45 [ +  + ][ +  + ]:       1800 :         if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
      46                 :            :                 return true;
      47                 :            : 
      48                 :       1720 :         return nsec >= 0 && nsec <= 999999999;
      49                 :            : }
      50                 :            : 
      51                 :          0 : static int utimes_common(struct path *path, struct timespec *times)
      52                 :            : {
      53                 :            :         int error;
      54                 :            :         struct iattr newattrs;
      55                 :       2090 :         struct inode *inode = path->dentry->d_inode;
      56                 :       2090 :         struct inode *delegated_inode = NULL;
      57                 :            : 
      58                 :       2090 :         error = mnt_want_write(path->mnt);
      59            [ + ]:       2090 :         if (error)
      60                 :            :                 goto out;
      61                 :            : 
      62 [ +  + ][ +  + ]:       4180 :         if (times && times[0].tv_nsec == UTIME_NOW &&
                 [ +  + ]
      63                 :         27 :                      times[1].tv_nsec == UTIME_NOW)
      64                 :            :                 times = NULL;
      65                 :            : 
      66                 :       4180 :         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
      67         [ +  + ]:       4180 :         if (times) {
      68         [ +  + ]:        882 :                 if (times[0].tv_nsec == UTIME_OMIT)
      69                 :         13 :                         newattrs.ia_valid &= ~ATTR_ATIME;
      70         [ +  + ]:        869 :                 else if (times[0].tv_nsec != UTIME_NOW) {
      71                 :        856 :                         newattrs.ia_atime.tv_sec = times[0].tv_sec;
      72                 :        856 :                         newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
      73                 :        856 :                         newattrs.ia_valid |= ATTR_ATIME_SET;
      74                 :            :                 }
      75                 :            : 
      76         [ +  + ]:        882 :                 if (times[1].tv_nsec == UTIME_OMIT)
      77                 :         13 :                         newattrs.ia_valid &= ~ATTR_MTIME;
      78         [ +  + ]:        869 :                 else if (times[1].tv_nsec != UTIME_NOW) {
      79                 :        856 :                         newattrs.ia_mtime.tv_sec = times[1].tv_sec;
      80                 :        856 :                         newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
      81                 :        856 :                         newattrs.ia_valid |= ATTR_MTIME_SET;
      82                 :            :                 }
      83                 :            :                 /*
      84                 :            :                  * Tell inode_change_ok(), that this is an explicit time
      85                 :            :                  * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
      86                 :            :                  * were used.
      87                 :            :                  */
      88                 :        882 :                 newattrs.ia_valid |= ATTR_TIMES_SET;
      89                 :            :         } else {
      90                 :            :                 /*
      91                 :            :                  * If times is NULL (or both times are UTIME_NOW),
      92                 :            :                  * then we need to check permissions, because
      93                 :            :                  * inode_change_ok() won't do it.
      94                 :            :                  */
      95                 :            :                 error = -EACCES;
      96         [ +  + ]:       1208 :                 if (IS_IMMUTABLE(inode))
      97                 :            :                         goto mnt_drop_write_and_out;
      98                 :            : 
      99         [ +  + ]:       1200 :                 if (!inode_owner_or_capable(inode)) {
     100                 :         24 :                         error = inode_permission(inode, MAY_WRITE);
     101         [ +  + ]:       2082 :                         if (error)
     102                 :            :                                 goto mnt_drop_write_and_out;
     103                 :            :                 }
     104                 :            :         }
     105                 :            : retry_deleg:
     106                 :       2077 :         mutex_lock(&inode->i_mutex);
     107                 :       2077 :         error = notify_change(path->dentry, &newattrs, &delegated_inode);
     108                 :       2077 :         mutex_unlock(&inode->i_mutex);
     109         [ -  + ]:       2077 :         if (delegated_inode) {
     110                 :            :                 error = break_deleg_wait(&delegated_inode);
     111         [ #  # ]:          0 :                 if (!error)
     112                 :            :                         goto retry_deleg;
     113                 :            :         }
     114                 :            : 
     115                 :            : mnt_drop_write_and_out:
     116                 :       2090 :         mnt_drop_write(path->mnt);
     117                 :            : out:
     118                 :          0 :         return error;
     119                 :            : }
     120                 :            : 
     121                 :            : /*
     122                 :            :  * do_utimes - change times on filename or file descriptor
     123                 :            :  * @dfd: open file descriptor, -1 or AT_FDCWD
     124                 :            :  * @filename: path name or NULL
     125                 :            :  * @times: new times or NULL
     126                 :            :  * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment)
     127                 :            :  *
     128                 :            :  * If filename is NULL and dfd refers to an open file, then operate on
     129                 :            :  * the file.  Otherwise look up filename, possibly using dfd as a
     130                 :            :  * starting point.
     131                 :            :  *
     132                 :            :  * If times==NULL, set access and modification to current time,
     133                 :            :  * must be owner or have write permission.
     134                 :            :  * Else, update from *times, must be owner or super user.
     135                 :            :  */
     136                 :          0 : long do_utimes(int dfd, const char __user *filename, struct timespec *times,
     137                 :            :                int flags)
     138                 :            : {
     139                 :            :         int error = -EINVAL;
     140                 :            : 
     141 [ +  + ][ +  - ]:       3898 :         if (times && (!nsec_valid(times[0].tv_nsec) ||
                 [ +  - ]
     142                 :        900 :                       !nsec_valid(times[1].tv_nsec))) {
     143                 :            :                 goto out;
     144                 :            :         }
     145                 :            : 
     146         [ +  - ]:       2098 :         if (flags & ~AT_SYMLINK_NOFOLLOW)
     147                 :            :                 goto out;
     148                 :            : 
     149         [ +  + ]:       2098 :         if (filename == NULL && dfd != AT_FDCWD) {
     150                 :            :                 struct fd f;
     151                 :            : 
     152         [ +  + ]:       1421 :                 if (flags & AT_SYMLINK_NOFOLLOW)
     153                 :            :                         goto out;
     154                 :            : 
     155                 :       1420 :                 f = fdget(dfd);
     156                 :            :                 error = -EBADF;
     157         [ +  - ]:       1420 :                 if (!f.file)
     158                 :            :                         goto out;
     159                 :            : 
     160                 :       1420 :                 error = utimes_common(&f.file->f_path, times);
     161                 :            :                 fdput(f);
     162                 :            :         } else {
     163                 :            :                 struct path path;
     164                 :            :                 int lookup_flags = 0;
     165                 :            : 
     166         [ +  + ]:        677 :                 if (!(flags & AT_SYMLINK_NOFOLLOW))
     167                 :            :                         lookup_flags |= LOOKUP_FOLLOW;
     168                 :            : retry:
     169                 :        677 :                 error = user_path_at(dfd, filename, lookup_flags, &path);
     170         [ +  + ]:        677 :                 if (error)
     171                 :            :                         goto out;
     172                 :            : 
     173                 :        670 :                 error = utimes_common(&path, times);
     174                 :        670 :                 path_put(&path);
     175         [ -  + ]:        670 :                 if (retry_estale(error, lookup_flags)) {
     176                 :          0 :                         lookup_flags |= LOOKUP_REVAL;
     177                 :        677 :                         goto retry;
     178                 :            :                 }
     179                 :            :         }
     180                 :            : 
     181                 :            : out:
     182                 :          0 :         return error;
     183                 :            : }
     184                 :            : 
     185                 :          0 : SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename,
     186                 :            :                 struct timespec __user *, utimes, int, flags)
     187                 :            : {
     188                 :            :         struct timespec tstimes[2];
     189                 :            : 
     190         [ +  + ]:       1703 :         if (utimes) {
     191         [ +  - ]:        532 :                 if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
     192                 :            :                         return -EFAULT;
     193                 :            : 
     194                 :            :                 /* Nothing to do, we must not even check the path.  */
     195 [ +  + ][ +  + ]:        532 :                 if (tstimes[0].tv_nsec == UTIME_OMIT &&
     196                 :         27 :                     tstimes[1].tv_nsec == UTIME_OMIT)
     197                 :            :                         return 0;
     198                 :            :         }
     199                 :            : 
     200         [ +  + ]:       1689 :         return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags);
     201                 :            : }
     202                 :            : 
     203                 :          0 : SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename,
     204                 :            :                 struct timeval __user *, utimes)
     205                 :            : {
     206                 :            :         struct timeval times[2];
     207                 :            :         struct timespec tstimes[2];
     208                 :            : 
     209         [ +  + ]:        409 :         if (utimes) {
     210         [ +  - ]:        382 :                 if (copy_from_user(&times, utimes, sizeof(times)))
     211                 :            :                         return -EFAULT;
     212                 :            : 
     213                 :            :                 /* This test is needed to catch all invalid values.  If we
     214                 :            :                    would test only in do_utimes we would miss those invalid
     215                 :            :                    values truncated by the multiplication with 1000.  Note
     216                 :            :                    that we also catch UTIME_{NOW,OMIT} here which are only
     217                 :            :                    valid for utimensat.  */
     218 [ +  - ][ +  - ]:        382 :                 if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 ||
     219         [ +  - ]:        382 :                     times[1].tv_usec >= 1000000 || times[1].tv_usec < 0)
     220                 :            :                         return -EINVAL;
     221                 :            : 
     222                 :        382 :                 tstimes[0].tv_sec = times[0].tv_sec;
     223                 :        382 :                 tstimes[0].tv_nsec = 1000 * times[0].tv_usec;
     224                 :        382 :                 tstimes[1].tv_sec = times[1].tv_sec;
     225                 :        382 :                 tstimes[1].tv_nsec = 1000 * times[1].tv_usec;
     226                 :            :         }
     227                 :            : 
     228         [ +  + ]:        409 :         return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
     229                 :            : }
     230                 :            : 
     231                 :          0 : SYSCALL_DEFINE2(utimes, char __user *, filename,
     232                 :            :                 struct timeval __user *, utimes)
     233                 :            : {
     234                 :        404 :         return sys_futimesat(AT_FDCWD, filename, utimes);
     235                 :            : }

Generated by: LCOV version 1.9