Linux 2.2.0
[davej-history.git] / fs / umsdos / rdir.c
blob10ff145b7c6657e3b1ec1fb630b3ebaf265e7123
1 /*
2 * linux/fs/umsdos/rdir.c
4 * Written 1994 by Jacques Gelinas
6 * Extended MS-DOS directory pure MS-DOS handling functions
7 * (For directory without EMD file).
8 */
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>
19 #include <asm/uaccess.h>
22 extern struct dentry *saved_root;
23 extern struct inode *pseudo_root;
24 extern struct dentry_operations umsdos_dentry_operations;
26 struct RDIR_FILLDIR {
27 void *dirbuf;
28 filldir_t filldir;
29 int real_root;
32 static int rdir_filldir ( void *buf,
33 const char *name,
34 int name_len,
35 off_t offset,
36 ino_t ino)
38 int ret = 0;
39 struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf;
41 if (d->real_root) {
42 PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n"));
43 /* real root of a pseudo_rooted partition */
44 if (name_len != UMSDOS_PSDROOT_LEN
45 || memcmp (name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) != 0) {
46 /* So it is not the /linux directory */
47 if (name_len == 2 && name[0] == '.' && name[1] == '.') {
48 /* Make sure the .. entry points back to the pseudo_root */
49 ino = pseudo_root->i_ino;
51 ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
53 } else {
54 /* Any DOS directory */
55 ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
57 return ret;
61 static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir)
63 struct inode *dir = filp->f_dentry->d_inode;
64 struct RDIR_FILLDIR bufk;
66 bufk.filldir = filldir;
67 bufk.dirbuf = dirbuf;
68 bufk.real_root = pseudo_root && (dir == saved_root->d_inode);
69 return fat_readdir (filp, &bufk, rdir_filldir);
74 * Lookup into a non promoted directory.
75 * If the result is a directory, make sure we find out if it is
76 * a promoted one or not (calling umsdos_setup_dir_inode(inode)).
78 /* #Specification: pseudo root / DOS/..
79 * In the real root directory (c:\), the directory ..
80 * is the pseudo root (c:\linux).
82 int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
84 int ret;
86 if (saved_root && dir == saved_root->d_inode && !nopseudo &&
87 dentry->d_name.len == UMSDOS_PSDROOT_LEN &&
88 memcmp (dentry->d_name.name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) == 0) {
89 /* #Specification: pseudo root / DOS/linux
90 * Even in the real root directory (c:\), the directory
91 * /linux won't show
94 ret = -ENOENT;
95 goto out;
98 ret = msdos_lookup (dir, dentry);
99 if (ret) {
100 printk(KERN_WARNING
101 "umsdos_rlookup_x: %s/%s failed, ret=%d\n",
102 dentry->d_parent->d_name.name, dentry->d_name.name,ret);
103 goto out;
105 if (dentry->d_inode) {
106 /* We must install the proper function table
107 * depending on whether this is an MS-DOS or
108 * a UMSDOS directory
110 Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n",
111 dentry->d_parent->d_name.name, dentry->d_name.name));
112 umsdos_patch_dentry_inode(dentry, 0);
115 out:
116 /* always install our dentry ops ... */
117 dentry->d_op = &umsdos_dentry_operations;
118 return ret;
122 int UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
124 return umsdos_rlookup_x (dir, dentry, 0);
128 /* #Specification: dual mode / rmdir in a DOS directory
129 * In a DOS (not EMD in it) directory, we use a reverse strategy
130 * compared with a UMSDOS directory. We assume that a subdirectory
131 * of a DOS directory is also a DOS directory. This is not always
132 * true (umssync may be used anywhere), but makes sense.
134 * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
135 * then we check if it is a Umsdos directory. We check if it is
136 * really empty (only . .. and --linux-.--- in it). If it is true
137 * we remove the EMD and do a msdos_rmdir() again.
139 * In a Umsdos directory, we assume all subdirectories are also
140 * Umsdos directories, so we check the EMD file first.
142 /* #Specification: pseudo root / rmdir /DOS
143 * The pseudo sub-directory /DOS can't be removed!
144 * This is done even if the pseudo root is not a Umsdos
145 * directory anymore (very unlikely), but an accident (under
146 * MS-DOS) is always possible.
148 * EPERM is returned.
150 static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
152 int ret, empty;
154 ret = -EPERM;
155 if (umsdos_is_pseudodos (dir, dentry))
156 goto out;
158 ret = -EBUSY;
159 if (!list_empty(&dentry->d_hash))
160 goto out;
162 ret = msdos_rmdir (dir, dentry);
163 if (ret != -ENOTEMPTY)
164 goto out;
166 empty = umsdos_isempty (dentry);
167 if (empty == 1) {
168 struct dentry *demd;
169 /* We have to remove the EMD file. */
170 demd = umsdos_get_emd_dentry(dentry);
171 ret = PTR_ERR(demd);
172 if (!IS_ERR(demd)) {
173 ret = 0;
174 if (demd->d_inode)
175 ret = msdos_unlink (dentry->d_inode, demd);
176 dput(demd);
179 if (ret)
180 goto out;
182 /* now retry the original ... */
183 ret = msdos_rmdir (dir, dentry);
185 out:
186 return ret;
189 /* #Specification: dual mode / introduction
190 * One goal of UMSDOS is to allow a practical and simple coexistence
191 * between MS-DOS and Linux in a single partition. Using the EMD file
192 * in each directory, UMSDOS adds Unix semantics and capabilities to
193 * a normal DOS filesystem. To help and simplify coexistence, here is
194 * the logic related to the EMD file.
196 * If it is missing, then the directory is managed by the MS-DOS driver.
197 * The names are limited to DOS limits (8.3). No links, no device special
198 * and pipe and so on.
200 * If it is there, it is the directory. If it is there but empty, then
201 * the directory looks empty. The utility umssync allows synchronisation
202 * of the real DOS directory and the EMD.
204 * Whenever umssync is applied to a directory without EMD, one is
205 * created on the fly. The directory is promoted to full Unix semantics.
206 * Of course, the ls command will show exactly the same content as before
207 * the umssync session.
209 * It is believed that the user/admin will promote directories to Unix
210 * semantics as needed.
212 * The strategy to implement this is to use two function table (struct
213 * inode_operations). One for true UMSDOS directory and one for directory
214 * with missing EMD.
216 * Functions related to the DOS semantic (but aware of UMSDOS) generally
217 * have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
218 * from the one with full UMSDOS semantics.
220 static struct file_operations umsdos_rdir_operations =
222 NULL, /* lseek - default */
223 dummy_dir_read, /* read */
224 NULL, /* write - bad */
225 UMSDOS_rreaddir, /* readdir */
226 NULL, /* poll - default */
227 UMSDOS_ioctl_dir, /* ioctl - default */
228 NULL, /* mmap */
229 NULL, /* no special open code */
230 NULL, /* flush */
231 NULL, /* no special release code */
232 NULL /* fsync */
235 struct inode_operations umsdos_rdir_inode_operations =
237 &umsdos_rdir_operations, /* default directory file-ops */
238 msdos_create, /* create */
239 UMSDOS_rlookup, /* lookup */
240 NULL, /* link */
241 msdos_unlink, /* unlink */
242 NULL, /* symlink */
243 msdos_mkdir, /* mkdir */
244 UMSDOS_rrmdir, /* rmdir */
245 NULL, /* mknod */
246 msdos_rename, /* rename */
247 NULL, /* readlink */
248 NULL, /* followlink */
249 NULL, /* readpage */
250 NULL, /* writepage */
251 NULL, /* bmap */
252 NULL, /* truncate */
253 NULL, /* permission */
254 NULL, /* smap */
255 NULL, /* updatepage */
256 NULL, /* revalidate */