stat.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/stat.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6. #include <linux/config.h>
  7. #include <linux/mm.h>
  8. #include <linux/errno.h>
  9. #include <linux/file.h>
  10. #include <linux/smp_lock.h>
  11. #include <linux/highuid.h>
  12. #include <asm/uaccess.h>
  13. /*
  14.  * Revalidate the inode. This is required for proper NFS attribute caching.
  15.  */
  16. static __inline__ int
  17. do_revalidate(struct dentry *dentry)
  18. {
  19. struct inode * inode = dentry->d_inode;
  20. if (inode->i_op && inode->i_op->revalidate)
  21. return inode->i_op->revalidate(dentry);
  22. return 0;
  23. }
  24. #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
  25. /*
  26.  * For backward compatibility?  Maybe this should be moved
  27.  * into arch/i386 instead?
  28.  */
  29. static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
  30. {
  31. static int warncount = 5;
  32. struct __old_kernel_stat tmp;
  33. if (warncount > 0) {
  34. warncount--;
  35. printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.n",
  36. current->comm);
  37. } else if (warncount < 0) {
  38. /* it's laughable, but... */
  39. warncount = 0;
  40. }
  41. tmp.st_dev = kdev_t_to_nr(inode->i_dev);
  42. tmp.st_ino = inode->i_ino;
  43. tmp.st_mode = inode->i_mode;
  44. tmp.st_nlink = inode->i_nlink;
  45. SET_OLDSTAT_UID(tmp, inode->i_uid);
  46. SET_OLDSTAT_GID(tmp, inode->i_gid);
  47. tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
  48. #if BITS_PER_LONG == 32
  49. if (inode->i_size > MAX_NON_LFS)
  50. return -EOVERFLOW;
  51. #endif
  52. tmp.st_size = inode->i_size;
  53. tmp.st_atime = inode->i_atime;
  54. tmp.st_mtime = inode->i_mtime;
  55. tmp.st_ctime = inode->i_ctime;
  56. return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
  57. }
  58. #endif
  59. static int cp_new_stat(struct inode * inode, struct stat * statbuf)
  60. {
  61. struct stat tmp;
  62. unsigned int blocks, indirect;
  63. memset(&tmp, 0, sizeof(tmp));
  64. tmp.st_dev = kdev_t_to_nr(inode->i_dev);
  65. tmp.st_ino = inode->i_ino;
  66. tmp.st_mode = inode->i_mode;
  67. tmp.st_nlink = inode->i_nlink;
  68. SET_STAT_UID(tmp, inode->i_uid);
  69. SET_STAT_GID(tmp, inode->i_gid);
  70. tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
  71. #if BITS_PER_LONG == 32
  72. if (inode->i_size > MAX_NON_LFS)
  73. return -EOVERFLOW;
  74. #endif
  75. tmp.st_size = inode->i_size;
  76. tmp.st_atime = inode->i_atime;
  77. tmp.st_mtime = inode->i_mtime;
  78. tmp.st_ctime = inode->i_ctime;
  79. /*
  80.  * st_blocks and st_blksize are approximated with a simple algorithm if
  81.  * they aren't supported directly by the filesystem. The minix and msdos
  82.  * filesystems don't keep track of blocks, so they would either have to
  83.  * be counted explicitly (by delving into the file itself), or by using
  84.  * this simple algorithm to get a reasonable (although not 100% accurate)
  85.  * value.
  86.  */
  87. /*
  88.  * Use minix fs values for the number of direct and indirect blocks.  The
  89.  * count is now exact for the minix fs except that it counts zero blocks.
  90.  * Everything is in units of BLOCK_SIZE until the assignment to
  91.  * tmp.st_blksize.
  92.  */
  93. #define D_B   7
  94. #define I_B   (BLOCK_SIZE / sizeof(unsigned short))
  95. if (!inode->i_blksize) {
  96. blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
  97. if (blocks > D_B) {
  98. indirect = (blocks - D_B + I_B - 1) / I_B;
  99. blocks += indirect;
  100. if (indirect > 1) {
  101. indirect = (indirect - 1 + I_B - 1) / I_B;
  102. blocks += indirect;
  103. if (indirect > 1)
  104. blocks++;
  105. }
  106. }
  107. tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
  108. tmp.st_blksize = BLOCK_SIZE;
  109. } else {
  110. tmp.st_blocks = inode->i_blocks;
  111. tmp.st_blksize = inode->i_blksize;
  112. }
  113. return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
  114. }
  115. #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
  116. /*
  117.  * For backward compatibility?  Maybe this should be moved
  118.  * into arch/i386 instead?
  119.  */
  120. asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
  121. {
  122. struct nameidata nd;
  123. int error;
  124. error = user_path_walk(filename, &nd);
  125. if (!error) {
  126. error = do_revalidate(nd.dentry);
  127. if (!error)
  128. error = cp_old_stat(nd.dentry->d_inode, statbuf);
  129. path_release(&nd);
  130. }
  131. return error;
  132. }
  133. #endif
  134. asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
  135. {
  136. struct nameidata nd;
  137. int error;
  138. error = user_path_walk(filename, &nd);
  139. if (!error) {
  140. error = do_revalidate(nd.dentry);
  141. if (!error)
  142. error = cp_new_stat(nd.dentry->d_inode, statbuf);
  143. path_release(&nd);
  144. }
  145. return error;
  146. }
  147. #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
  148. /*
  149.  * For backward compatibility?  Maybe this should be moved
  150.  * into arch/i386 instead?
  151.  */
  152. asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
  153. {
  154. struct nameidata nd;
  155. int error;
  156. error = user_path_walk_link(filename, &nd);
  157. if (!error) {
  158. error = do_revalidate(nd.dentry);
  159. if (!error)
  160. error = cp_old_stat(nd.dentry->d_inode, statbuf);
  161. path_release(&nd);
  162. }
  163. return error;
  164. }
  165. #endif
  166. asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
  167. {
  168. struct nameidata nd;
  169. int error;
  170. error = user_path_walk_link(filename, &nd);
  171. if (!error) {
  172. error = do_revalidate(nd.dentry);
  173. if (!error)
  174. error = cp_new_stat(nd.dentry->d_inode, statbuf);
  175. path_release(&nd);
  176. }
  177. return error;
  178. }
  179. #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
  180. /*
  181.  * For backward compatibility?  Maybe this should be moved
  182.  * into arch/i386 instead?
  183.  */
  184. asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
  185. {
  186. struct file * f;
  187. int err = -EBADF;
  188. f = fget(fd);
  189. if (f) {
  190. struct dentry * dentry = f->f_dentry;
  191. err = do_revalidate(dentry);
  192. if (!err)
  193. err = cp_old_stat(dentry->d_inode, statbuf);
  194. fput(f);
  195. }
  196. return err;
  197. }
  198. #endif
  199. asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf)
  200. {
  201. struct file * f;
  202. int err = -EBADF;
  203. f = fget(fd);
  204. if (f) {
  205. struct dentry * dentry = f->f_dentry;
  206. err = do_revalidate(dentry);
  207. if (!err)
  208. err = cp_new_stat(dentry->d_inode, statbuf);
  209. fput(f);
  210. }
  211. return err;
  212. }
  213. asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz)
  214. {
  215. struct nameidata nd;
  216. int error;
  217. if (bufsiz <= 0)
  218. return -EINVAL;
  219. error = user_path_walk_link(path, &nd);
  220. if (!error) {
  221. struct inode * inode = nd.dentry->d_inode;
  222. error = -EINVAL;
  223. if (inode->i_op && inode->i_op->readlink &&
  224.     !(error = do_revalidate(nd.dentry))) {
  225. UPDATE_ATIME(inode);
  226. error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
  227. }
  228. path_release(&nd);
  229. }
  230. return error;
  231. }
  232. /* ---------- LFS-64 ----------- */
  233. #if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(__x86_64__) && !defined(CONFIG_ARCH_S390X)
  234. static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
  235. {
  236. struct stat64 tmp;
  237. unsigned int blocks, indirect;
  238. memset(&tmp, 0, sizeof(tmp));
  239. tmp.st_dev = kdev_t_to_nr(inode->i_dev);
  240. tmp.st_ino = inode->i_ino;
  241. #ifdef STAT64_HAS_BROKEN_ST_INO
  242. tmp.__st_ino = inode->i_ino;
  243. #endif
  244. tmp.st_mode = inode->i_mode;
  245. tmp.st_nlink = inode->i_nlink;
  246. tmp.st_uid = inode->i_uid;
  247. tmp.st_gid = inode->i_gid;
  248. tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
  249. tmp.st_atime = inode->i_atime;
  250. tmp.st_mtime = inode->i_mtime;
  251. tmp.st_ctime = inode->i_ctime;
  252. tmp.st_size = inode->i_size;
  253. /*
  254.  * st_blocks and st_blksize are approximated with a simple algorithm if
  255.  * they aren't supported directly by the filesystem. The minix and msdos
  256.  * filesystems don't keep track of blocks, so they would either have to
  257.  * be counted explicitly (by delving into the file itself), or by using
  258.  * this simple algorithm to get a reasonable (although not 100% accurate)
  259.  * value.
  260.  */
  261. /*
  262.  * Use minix fs values for the number of direct and indirect blocks.  The
  263.  * count is now exact for the minix fs except that it counts zero blocks.
  264.  * Everything is in units of BLOCK_SIZE until the assignment to
  265.  * tmp.st_blksize.
  266.  */
  267. #define D_B   7
  268. #define I_B   (BLOCK_SIZE / sizeof(unsigned short))
  269. if (!inode->i_blksize) {
  270. blocks = (tmp.st_size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
  271. if (blocks > D_B) {
  272. indirect = (blocks - D_B + I_B - 1) / I_B;
  273. blocks += indirect;
  274. if (indirect > 1) {
  275. indirect = (indirect - 1 + I_B - 1) / I_B;
  276. blocks += indirect;
  277. if (indirect > 1)
  278. blocks++;
  279. }
  280. }
  281. tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
  282. tmp.st_blksize = BLOCK_SIZE;
  283. } else {
  284. tmp.st_blocks = inode->i_blocks;
  285. tmp.st_blksize = inode->i_blksize;
  286. }
  287. return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
  288. }
  289. asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags)
  290. {
  291. struct nameidata nd;
  292. int error;
  293. error = user_path_walk(filename, &nd);
  294. if (!error) {
  295. error = do_revalidate(nd.dentry);
  296. if (!error)
  297. error = cp_new_stat64(nd.dentry->d_inode, statbuf);
  298. path_release(&nd);
  299. }
  300. return error;
  301. }
  302. asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags)
  303. {
  304. struct nameidata nd;
  305. int error;
  306. error = user_path_walk_link(filename, &nd);
  307. if (!error) {
  308. error = do_revalidate(nd.dentry);
  309. if (!error)
  310. error = cp_new_stat64(nd.dentry->d_inode, statbuf);
  311. path_release(&nd);
  312. }
  313. return error;
  314. }
  315. asmlinkage long sys_fstat64(unsigned long fd, struct stat64 * statbuf, long flags)
  316. {
  317. struct file * f;
  318. int err = -EBADF;
  319. f = fget(fd);
  320. if (f) {
  321. struct dentry * dentry = f->f_dentry;
  322. err = do_revalidate(dentry);
  323. if (!err)
  324. err = cp_new_stat64(dentry->d_inode, statbuf);
  325. fput(f);
  326. }
  327. return err;
  328. }
  329. #endif /* LFS-64 */