The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/utimes.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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         if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
   46                 return true;
   47 
   48         return nsec >= 0 && nsec <= 999999999;
   49 }
   50 
   51 static int utimes_common(struct path *path, struct timespec *times)
   52 {
   53         int error;
   54         struct iattr newattrs;
   55         struct inode *inode = path->dentry->d_inode;
   56 
   57         error = mnt_want_write(path->mnt);
   58         if (error)
   59                 goto out;
   60 
   61         if (times && times[0].tv_nsec == UTIME_NOW &&
   62                      times[1].tv_nsec == UTIME_NOW)
   63                 times = NULL;
   64 
   65         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
   66         if (times) {
   67                 if (times[0].tv_nsec == UTIME_OMIT)
   68                         newattrs.ia_valid &= ~ATTR_ATIME;
   69                 else if (times[0].tv_nsec != UTIME_NOW) {
   70                         newattrs.ia_atime.tv_sec = times[0].tv_sec;
   71                         newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
   72                         newattrs.ia_valid |= ATTR_ATIME_SET;
   73                 }
   74 
   75                 if (times[1].tv_nsec == UTIME_OMIT)
   76                         newattrs.ia_valid &= ~ATTR_MTIME;
   77                 else if (times[1].tv_nsec != UTIME_NOW) {
   78                         newattrs.ia_mtime.tv_sec = times[1].tv_sec;
   79                         newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
   80                         newattrs.ia_valid |= ATTR_MTIME_SET;
   81                 }
   82                 /*
   83                  * Tell inode_change_ok(), that this is an explicit time
   84                  * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
   85                  * were used.
   86                  */
   87                 newattrs.ia_valid |= ATTR_TIMES_SET;
   88         } else {
   89                 /*
   90                  * If times is NULL (or both times are UTIME_NOW),
   91                  * then we need to check permissions, because
   92                  * inode_change_ok() won't do it.
   93                  */
   94                 error = -EACCES;
   95                 if (IS_IMMUTABLE(inode))
   96                         goto mnt_drop_write_and_out;
   97 
   98                 if (!inode_owner_or_capable(inode)) {
   99                         error = inode_permission(inode, MAY_WRITE);
  100                         if (error)
  101                                 goto mnt_drop_write_and_out;
  102                 }
  103         }
  104         mutex_lock(&inode->i_mutex);
  105         error = notify_change(path->dentry, &newattrs);
  106         mutex_unlock(&inode->i_mutex);
  107 
  108 mnt_drop_write_and_out:
  109         mnt_drop_write(path->mnt);
  110 out:
  111         return error;
  112 }
  113 
  114 /*
  115  * do_utimes - change times on filename or file descriptor
  116  * @dfd: open file descriptor, -1 or AT_FDCWD
  117  * @filename: path name or NULL
  118  * @times: new times or NULL
  119  * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment)
  120  *
  121  * If filename is NULL and dfd refers to an open file, then operate on
  122  * the file.  Otherwise look up filename, possibly using dfd as a
  123  * starting point.
  124  *
  125  * If times==NULL, set access and modification to current time,
  126  * must be owner or have write permission.
  127  * Else, update from *times, must be owner or super user.
  128  */
  129 long do_utimes(int dfd, const char __user *filename, struct timespec *times,
  130                int flags)
  131 {
  132         int error = -EINVAL;
  133 
  134         if (times && (!nsec_valid(times[0].tv_nsec) ||
  135                       !nsec_valid(times[1].tv_nsec))) {
  136                 goto out;
  137         }
  138 
  139         if (flags & ~AT_SYMLINK_NOFOLLOW)
  140                 goto out;
  141 
  142         if (filename == NULL && dfd != AT_FDCWD) {
  143                 struct fd f;
  144 
  145                 if (flags & AT_SYMLINK_NOFOLLOW)
  146                         goto out;
  147 
  148                 f = fdget(dfd);
  149                 error = -EBADF;
  150                 if (!f.file)
  151                         goto out;
  152 
  153                 error = utimes_common(&f.file->f_path, times);
  154                 fdput(f);
  155         } else {
  156                 struct path path;
  157                 int lookup_flags = 0;
  158 
  159                 if (!(flags & AT_SYMLINK_NOFOLLOW))
  160                         lookup_flags |= LOOKUP_FOLLOW;
  161 retry:
  162                 error = user_path_at(dfd, filename, lookup_flags, &path);
  163                 if (error)
  164                         goto out;
  165 
  166                 error = utimes_common(&path, times);
  167                 path_put(&path);
  168                 if (retry_estale(error, lookup_flags)) {
  169                         lookup_flags |= LOOKUP_REVAL;
  170                         goto retry;
  171                 }
  172         }
  173 
  174 out:
  175         return error;
  176 }
  177 
  178 SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename,
  179                 struct timespec __user *, utimes, int, flags)
  180 {
  181         struct timespec tstimes[2];
  182 
  183         if (utimes) {
  184                 if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
  185                         return -EFAULT;
  186 
  187                 /* Nothing to do, we must not even check the path.  */
  188                 if (tstimes[0].tv_nsec == UTIME_OMIT &&
  189                     tstimes[1].tv_nsec == UTIME_OMIT)
  190                         return 0;
  191         }
  192 
  193         return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags);
  194 }
  195 
  196 SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename,
  197                 struct timeval __user *, utimes)
  198 {
  199         struct timeval times[2];
  200         struct timespec tstimes[2];
  201 
  202         if (utimes) {
  203                 if (copy_from_user(&times, utimes, sizeof(times)))
  204                         return -EFAULT;
  205 
  206                 /* This test is needed to catch all invalid values.  If we
  207                    would test only in do_utimes we would miss those invalid
  208                    values truncated by the multiplication with 1000.  Note
  209                    that we also catch UTIME_{NOW,OMIT} here which are only
  210                    valid for utimensat.  */
  211                 if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 ||
  212                     times[1].tv_usec >= 1000000 || times[1].tv_usec < 0)
  213                         return -EINVAL;
  214 
  215                 tstimes[0].tv_sec = times[0].tv_sec;
  216                 tstimes[0].tv_nsec = 1000 * times[0].tv_usec;
  217                 tstimes[1].tv_sec = times[1].tv_sec;
  218                 tstimes[1].tv_nsec = 1000 * times[1].tv_usec;
  219         }
  220 
  221         return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
  222 }
  223 
  224 SYSCALL_DEFINE2(utimes, char __user *, filename,
  225                 struct timeval __user *, utimes)
  226 {
  227         return sys_futimesat(AT_FDCWD, filename, utimes);
  228 }

Cache object: 5102ef781b788c489f4b7ab16be72698


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.