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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/umsdos/rdir.c
  3.  *
  4.  *  Written 1994 by Jacques Gelinas
  5.  *
  6.  *  Extended MS-DOS directory pure MS-DOS handling functions
  7.  *  (For directory without EMD file).
  8.  */
  9. #include <linux/sched.h>
  10. #include <linux/fs.h>
  11. #include <linux/msdos_fs.h>
  12. #include <linux/errno.h>
  13. #include <linux/stat.h>
  14. #include <linux/limits.h>
  15. #include <linux/umsdos_fs.h>
  16. #include <linux/slab.h>
  17. #include <asm/uaccess.h>
  18. extern struct dentry *saved_root;
  19. extern struct inode *pseudo_root;
  20. extern struct dentry_operations umsdos_dentry_operations;
  21. struct RDIR_FILLDIR {
  22. void *dirbuf;
  23. filldir_t filldir;
  24. int real_root;
  25. };
  26. static int rdir_filldir ( void *buf,
  27. const char *name,
  28. int name_len,
  29. loff_t offset,
  30. ino_t ino,
  31. unsigned int d_type)
  32. {
  33. int ret = 0;
  34. struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf;
  35. if (d->real_root) {
  36. PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!n"));
  37. /* real root of a pseudo_rooted partition */
  38. if (name_len != UMSDOS_PSDROOT_LEN
  39.     || memcmp (name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) != 0) {
  40. /* So it is not the /linux directory */
  41. if (name_len == 2 && name[0] == '.' && name[1] == '.') {
  42. /* Make sure the .. entry points back to the pseudo_root */
  43. ino = pseudo_root->i_ino;
  44. }
  45. ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN);
  46. }
  47. } else {
  48. /* Any DOS directory */
  49. ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN);
  50. }
  51. return ret;
  52. }
  53. static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir)
  54. {
  55. struct inode *dir = filp->f_dentry->d_inode;
  56. struct RDIR_FILLDIR bufk;
  57. bufk.filldir = filldir;
  58. bufk.dirbuf = dirbuf;
  59. bufk.real_root = pseudo_root && (dir == saved_root->d_inode);
  60. return fat_readdir (filp, &bufk, rdir_filldir);
  61. }
  62. /*
  63.  * Lookup into a non promoted directory.
  64.  * If the result is a directory, make sure we find out if it is
  65.  * a promoted one or not (calling umsdos_setup_dir_inode(inode)).
  66.  */
  67. /* #Specification: pseudo root / DOS/..
  68.  * In the real root directory (c:), the directory ..
  69.  * is the pseudo root (c:linux).
  70.  */
  71. struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
  72. {
  73. struct dentry *ret;
  74. if (saved_root && dir == saved_root->d_inode && !nopseudo &&
  75.     dentry->d_name.len == UMSDOS_PSDROOT_LEN &&
  76.     memcmp (dentry->d_name.name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) == 0) {
  77. /* #Specification: pseudo root / DOS/linux
  78.  * Even in the real root directory (c:), the directory
  79.  * /linux won't show
  80.  */
  81.  
  82. ret = ERR_PTR(-ENOENT);
  83. goto out;
  84. }
  85. ret = msdos_lookup (dir, dentry);
  86. if (ret) {
  87. printk(KERN_WARNING
  88. "umsdos_rlookup_x: %s/%s failed, ret=%ldn",
  89. dentry->d_parent->d_name.name, dentry->d_name.name,
  90. PTR_ERR(ret));
  91. goto out;
  92. }
  93. if (dentry->d_inode) {
  94. /* We must install the proper function table
  95.  * depending on whether this is an MS-DOS or 
  96.  * a UMSDOS directory
  97.  */
  98. Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%sn",
  99. dentry->d_parent->d_name.name, dentry->d_name.name));
  100. /* only patch if needed (because we get called even for lookup
  101.    (not only rlookup) stuff sometimes, like in umsdos_covered() */
  102. if (dentry->d_inode->u.umsdos_i.i_patched == 0)
  103. umsdos_patch_dentry_inode(dentry, 0);
  104. }
  105. out:
  106. /* always install our dentry ops ... */
  107. dentry->d_op = &umsdos_dentry_operations;
  108. return ret;
  109. }
  110. struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
  111. {
  112. return umsdos_rlookup_x (dir, dentry, 0);
  113. }
  114. /* #Specification: dual mode / rmdir in a DOS directory
  115.  * In a DOS (not EMD in it) directory, we use a reverse strategy
  116.  * compared with a UMSDOS directory. We assume that a subdirectory
  117.  * of a DOS directory is also a DOS directory. This is not always
  118.  * true (umssync may be used anywhere), but makes sense.
  119.  * 
  120.  * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
  121.  * then we check if it is a Umsdos directory. We check if it is
  122.  * really empty (only . .. and --linux-.--- in it). If it is true
  123.  * we remove the EMD and do a msdos_rmdir() again.
  124.  * 
  125.  * In a Umsdos directory, we assume all subdirectories are also
  126.  * Umsdos directories, so we check the EMD file first.
  127.  */
  128. /* #Specification: pseudo root / rmdir /DOS
  129.  * The pseudo sub-directory /DOS can't be removed!
  130.  * This is done even if the pseudo root is not a Umsdos
  131.  * directory anymore (very unlikely), but an accident (under
  132.  * MS-DOS) is always possible.
  133.  * 
  134.  * EPERM is returned.
  135.  */
  136. static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
  137. {
  138. int ret, empty;
  139. ret = -EPERM;
  140. if (umsdos_is_pseudodos (dir, dentry))
  141. goto out;
  142. ret = -EBUSY;
  143. if (!d_unhashed(dentry))
  144. goto out;
  145. ret = msdos_rmdir (dir, dentry);
  146. if (ret != -ENOTEMPTY)
  147. goto out;
  148. empty = umsdos_isempty (dentry);
  149. if (empty == 1) {
  150. struct dentry *demd;
  151. /* We have to remove the EMD file. */
  152. demd = umsdos_get_emd_dentry(dentry);
  153. ret = PTR_ERR(demd);
  154. if (!IS_ERR(demd)) {
  155. ret = 0;
  156. if (demd->d_inode)
  157. ret = msdos_unlink (dentry->d_inode, demd);
  158. if (!ret)
  159. d_delete(demd);
  160. dput(demd);
  161. }
  162. }
  163. if (ret)
  164. goto out;
  165. /* now retry the original ... */
  166. ret = msdos_rmdir (dir, dentry);
  167. out:
  168. return ret;
  169. }
  170. /* #Specification: dual mode / introduction
  171.  * One goal of UMSDOS is to allow a practical and simple coexistence
  172.  * between MS-DOS and Linux in a single partition. Using the EMD file
  173.  * in each directory, UMSDOS adds Unix semantics and capabilities to
  174.  * a normal DOS filesystem. To help and simplify coexistence, here is
  175.  * the logic related to the EMD file.
  176.  * 
  177.  * If it is missing, then the directory is managed by the MS-DOS driver.
  178.  * The names are limited to DOS limits (8.3). No links, no device special
  179.  * and pipe and so on.
  180.  * 
  181.  * If it is there, it is the directory. If it is there but empty, then
  182.  * the directory looks empty. The utility umssync allows synchronisation
  183.  * of the real DOS directory and the EMD.
  184.  * 
  185.  * Whenever umssync is applied to a directory without EMD, one is
  186.  * created on the fly.  The directory is promoted to full Unix semantics.
  187.  * Of course, the ls command will show exactly the same content as before
  188.  * the umssync session.
  189.  * 
  190.  * It is believed that the user/admin will promote directories to Unix
  191.  * semantics as needed.
  192.  * 
  193.  * The strategy to implement this is to use two function table (struct
  194.  * inode_operations). One for true UMSDOS directory and one for directory
  195.  * with missing EMD.
  196.  * 
  197.  * Functions related to the DOS semantic (but aware of UMSDOS) generally
  198.  * have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
  199.  * from the one with full UMSDOS semantics.
  200.  */
  201. struct file_operations umsdos_rdir_operations =
  202. {
  203. read: generic_read_dir,
  204. readdir: UMSDOS_rreaddir,
  205. ioctl: UMSDOS_ioctl_dir,
  206. };
  207. struct inode_operations umsdos_rdir_inode_operations =
  208. {
  209. create: msdos_create,
  210. lookup: UMSDOS_rlookup,
  211. unlink: msdos_unlink,
  212. mkdir: msdos_mkdir,
  213. rmdir: UMSDOS_rrmdir,
  214. rename: msdos_rename,
  215. setattr: UMSDOS_notify_change,
  216. };