utimes.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #include <linux/compiler.h>
  2. #include <linux/fs.h>
  3. #include <linux/linkage.h>
  4. #include <linux/namei.h>
  5. #include <linux/utime.h>
  6. #include <asm/uaccess.h>
  7. #include <asm/unistd.h>
  8. #ifdef __ARCH_WANT_SYS_UTIME
  9. /*
  10. * sys_utime() can be implemented in user-level using sys_utimes().
  11. * Is this for backwards compatibility? If so, why not move it
  12. * into the appropriate arch directory (for those architectures that
  13. * need it).
  14. */
  15. /* If times==NULL, set access and modification to current time,
  16. * must be owner or have write permission.
  17. * Else, update from *times, must be owner or super user.
  18. */
  19. asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
  20. {
  21. int error;
  22. struct nameidata nd;
  23. struct inode * inode;
  24. struct iattr newattrs;
  25. error = user_path_walk(filename, &nd);
  26. if (error)
  27. goto out;
  28. inode = nd.dentry->d_inode;
  29. error = -EROFS;
  30. if (IS_RDONLY(inode))
  31. goto dput_and_out;
  32. /* Don't worry, the checks are done in inode_change_ok() */
  33. newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
  34. if (times) {
  35. error = -EPERM;
  36. if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
  37. goto dput_and_out;
  38. error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
  39. newattrs.ia_atime.tv_nsec = 0;
  40. if (!error)
  41. error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime);
  42. newattrs.ia_mtime.tv_nsec = 0;
  43. if (error)
  44. goto dput_and_out;
  45. newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
  46. } else {
  47. error = -EACCES;
  48. if (IS_IMMUTABLE(inode))
  49. goto dput_and_out;
  50. if (current->fsuid != inode->i_uid &&
  51. (error = vfs_permission(&nd, MAY_WRITE)) != 0)
  52. goto dput_and_out;
  53. }
  54. mutex_lock(&inode->i_mutex);
  55. error = notify_change(nd.dentry, &newattrs);
  56. mutex_unlock(&inode->i_mutex);
  57. dput_and_out:
  58. path_release(&nd);
  59. out:
  60. return error;
  61. }
  62. #endif
  63. /* If times==NULL, set access and modification to current time,
  64. * must be owner or have write permission.
  65. * Else, update from *times, must be owner or super user.
  66. */
  67. long do_utimes(int dfd, char __user *filename, struct timeval *times)
  68. {
  69. int error;
  70. struct nameidata nd;
  71. struct inode * inode;
  72. struct iattr newattrs;
  73. error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
  74. if (error)
  75. goto out;
  76. inode = nd.dentry->d_inode;
  77. error = -EROFS;
  78. if (IS_RDONLY(inode))
  79. goto dput_and_out;
  80. /* Don't worry, the checks are done in inode_change_ok() */
  81. newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
  82. if (times) {
  83. error = -EPERM;
  84. if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
  85. goto dput_and_out;
  86. newattrs.ia_atime.tv_sec = times[0].tv_sec;
  87. newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
  88. newattrs.ia_mtime.tv_sec = times[1].tv_sec;
  89. newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
  90. newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
  91. } else {
  92. error = -EACCES;
  93. if (IS_IMMUTABLE(inode))
  94. goto dput_and_out;
  95. if (current->fsuid != inode->i_uid &&
  96. (error = vfs_permission(&nd, MAY_WRITE)) != 0)
  97. goto dput_and_out;
  98. }
  99. mutex_lock(&inode->i_mutex);
  100. error = notify_change(nd.dentry, &newattrs);
  101. mutex_unlock(&inode->i_mutex);
  102. dput_and_out:
  103. path_release(&nd);
  104. out:
  105. return error;
  106. }
  107. asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
  108. {
  109. struct timeval times[2];
  110. if (utimes && copy_from_user(&times, utimes, sizeof(times)))
  111. return -EFAULT;
  112. return do_utimes(dfd, filename, utimes ? times : NULL);
  113. }
  114. asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
  115. {
  116. return sys_futimesat(AT_FDCWD, filename, utimes);
  117. }