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