Import 2.1.118
[davej-history.git] / fs / umsdos / rdir.c
blob5d5cd55af86b3ba2517274d66a008d9b5322edee
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>
21 #define PRINTK(x)
22 #define Printk(x) printk x
25 extern struct inode *pseudo_root;
27 struct RDIR_FILLDIR {
28 void *dirbuf;
29 filldir_t filldir;
30 int real_root;
33 static int rdir_filldir (
34 void *buf,
35 const char *name,
36 int name_len,
37 off_t offset,
38 ino_t ino)
40 int ret = 0;
41 struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf;
43 PRINTK ((KERN_DEBUG "rdir_filldir /mn/: entering\n"));
44 if (d->real_root) {
45 PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n"));
46 /* real root of a pseudo_rooted partition */
47 if (name_len != UMSDOS_PSDROOT_LEN
48 || memcmp (name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) != 0) {
49 /* So it is not the /linux directory */
50 if (name_len == 2
51 && name[0] == '.'
52 && name[1] == '.') {
53 /* Make sure the .. entry points back to the pseudo_root */
54 ino = pseudo_root->i_ino;
56 ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
58 } else {
59 /* Any DOS directory */
60 PRINTK ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %.*s (%lu)\n", d->filldir, name_len, name, ino));
61 ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
63 return ret;
67 static int UMSDOS_rreaddir (
68 struct file *filp,
69 void *dirbuf,
70 filldir_t filldir)
72 struct RDIR_FILLDIR bufk;
73 struct inode *dir = filp->f_dentry->d_inode;
75 PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf));
78 bufk.filldir = filldir;
79 bufk.dirbuf = dirbuf;
80 bufk.real_root = pseudo_root
81 && dir == iget (dir->i_sb, UMSDOS_ROOT_INO)
82 && dir == iget (pseudo_root->i_sb, UMSDOS_ROOT_INO);
83 PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n", filldir));
84 return fat_readdir (filp, &bufk, rdir_filldir);
89 * Lookup into a non promoted directory.
90 * If the result is a directory, make sure we find out if it is
91 * a promoted one or not (calling umsdos_setup_dir_inode(inode)).
93 int umsdos_rlookup_x (
94 struct inode *dir,
95 struct dentry *dentry,
96 int nopseudo)
97 { /* Don't care about pseudo root mode */
98 /* so locating "linux" will work */
99 int len = dentry->d_name.len;
100 const char *name = dentry->d_name.name;
101 struct inode *inode;
102 int ret;
104 if (pseudo_root
105 && len == 2
106 && name[0] == '.'
107 && name[1] == '.'
108 && dir == iget (dir->i_sb, UMSDOS_ROOT_INO)
109 && dir == iget (pseudo_root->i_sb, UMSDOS_ROOT_INO)) {
110 /* *result = pseudo_root; */
111 Printk ((KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n"));
112 inc_count (pseudo_root);
113 ret = 0;
114 /* #Specification: pseudo root / DOS/..
115 * In the real root directory (c:\), the directory ..
116 * is the pseudo root (c:\linux).
118 } else {
119 ret = umsdos_real_lookup (dir, dentry);
120 inode = dentry->d_inode;
122 #if 0
123 Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %.*s in %lu returned %d\n", len, name, dir->i_ino, ret));
124 Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode));
125 if (inode) { /* /mn/ FIXME: DEL_ME */
126 Printk ((KERN_DEBUG "i_ino=%lu\n", inode->i_ino));
127 } else {
128 Printk ((KERN_DEBUG "NONE!\n"));
130 #endif
132 if ((ret == 0) && inode) {
134 if (pseudo_root && inode == pseudo_root && !nopseudo) {
135 /* #Specification: pseudo root / DOS/linux
136 * Even in the real root directory (c:\), the directory
137 * /linux won't show
139 Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n"));
140 ret = -ENOENT;
141 iput (pseudo_root); /* FIXME? */
143 } else if (S_ISDIR (inode->i_mode)) {
144 /* We must place the proper function table */
145 /* depending if this is a MsDOS directory or an UMSDOS directory */
146 Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", inode->i_ino));
147 umsdos_setup_dir_inode (inode);
151 iput (dir); /* FIXME? */
152 PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
153 return ret;
157 int UMSDOS_rlookup (
158 struct inode *dir,
159 struct dentry *dentry
162 PRINTK ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%lu in %.*s\n", dir->i_ino, (int) dentry->d_name.len, dentry->d_name.name));
163 return umsdos_rlookup_x (dir, dentry, 0);
167 static int UMSDOS_rrmdir (
168 struct inode *dir,
169 struct dentry *dentry)
171 /* #Specification: dual mode / rmdir in a DOS directory
172 * In a DOS (not EMD in it) directory, we use a reverse strategy
173 * compared with an Umsdos directory. We assume that a subdirectory
174 * of a DOS directory is also a DOS directory. This is not always
175 * true (umssync may be used anywhere), but make sense.
177 * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
178 * then we check if it is a Umsdos directory. We check if it is
179 * really empty (only . .. and --linux-.--- in it). If it is true
180 * we remove the EMD and do a msdos_rmdir() again.
182 * In a Umsdos directory, we assume all subdirectory are also
183 * Umsdos directory, so we check the EMD file first.
185 int ret;
187 if (umsdos_is_pseudodos (dir, dentry)) {
188 /* #Specification: pseudo root / rmdir /DOS
189 * The pseudo sub-directory /DOS can't be removed!
190 * This is done even if the pseudo root is not a Umsdos
191 * directory anymore (very unlikely), but an accident (under
192 * MsDOS) is always possible.
194 * EPERM is returned.
196 ret = -EPERM;
197 } else {
198 umsdos_lockcreate (dir);
199 inc_count (dir);
200 ret = msdos_rmdir (dir, dentry);
201 if (ret == -ENOTEMPTY) {
202 struct inode *sdir;
204 inc_count (dir);
206 ret = UMSDOS_rlookup (dir, dentry);
207 sdir = dentry->d_inode;
208 PRINTK (("rrmdir lookup %d ", ret));
209 if (ret == 0) {
210 int empty;
212 if ((empty = umsdos_isempty (sdir)) != 0) {
213 PRINTK (("isempty %d i_count %d ", empty,
214 atomic_read (&sdir->i_count)));
215 if (empty == 2) {
217 * Not a Umsdos directory, so the previous msdos_rmdir
218 * was not lying :-)
220 ret = -ENOTEMPTY;
221 } else if (empty == 1) {
222 /* We have to removed the EMD file */
223 struct dentry *temp;
225 Printk ((KERN_WARNING "UMSDOS_rmdir: hmmm... whatabout inode ? FIXME\n"));
226 temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL); /* FIXME: prolly should fill inode part ? */
227 ret = msdos_unlink (sdir, temp);
228 sdir = NULL;
229 if (ret == 0) {
230 inc_count (dir);
231 ret = msdos_rmdir (dir, dentry);
234 } else {
235 ret = -ENOTEMPTY;
237 /* iput (sdir); FIXME */
240 umsdos_unlockcreate (dir);
242 /* iput (dir); FIXME */
243 return ret;
246 /* #Specification: dual mode / introduction
247 * One goal of UMSDOS is to allow a practical and simple coexistence
248 * between MsDOS and Linux in a single partition. Using the EMD file
249 * in each directory, UMSDOS add Unix semantics and capabilities to
250 * normal DOS file system. To help and simplify coexistence, here is
251 * the logic related to the EMD file.
253 * If it is missing, then the directory is managed by the MsDOS driver.
254 * The names are limited to DOS limits (8.3). No links, no device special
255 * and pipe and so on.
257 * If it is there, it is the directory. If it is there but empty, then
258 * the directory looks empty. The utility umssync allows synchronisation
259 * of the real DOS directory and the EMD.
261 * Whenever umssync is applied to a directory without EMD, one is
262 * created on the fly. The directory is promoted to full unix semantic.
263 * Of course, the ls command will show exactly the same content as before
264 * the umssync session.
266 * It is believed that the user/admin will promote directories to unix
267 * semantic as needed.
269 * The strategy to implement this is to use two function table (struct
270 * inode_operations). One for true UMSDOS directory and one for directory
271 * with missing EMD.
273 * Functions related to the DOS semantic (but aware of UMSDOS) generally
274 * have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
275 * from the one with full UMSDOS semantic.
277 static struct file_operations umsdos_rdir_operations =
279 NULL, /* lseek - default */
280 UMSDOS_dir_read, /* read */
281 NULL, /* write - bad */
282 UMSDOS_rreaddir, /* readdir */
283 NULL, /* poll - default */
284 UMSDOS_ioctl_dir, /* ioctl - default */
285 NULL, /* mmap */
286 NULL, /* no special open code */
287 NULL, /* flush */
288 NULL, /* no special release code */
289 NULL /* fsync */
292 struct inode_operations umsdos_rdir_inode_operations =
294 &umsdos_rdir_operations, /* default directory file-ops */
295 msdos_create, /* create */
296 UMSDOS_rlookup, /* lookup */
297 NULL, /* link */
298 msdos_unlink, /* unlink */
299 NULL, /* symlink */
300 msdos_mkdir, /* mkdir */
301 UMSDOS_rrmdir, /* rmdir */
302 NULL, /* mknod */
303 msdos_rename, /* rename */
304 NULL, /* readlink */
305 NULL, /* followlink */
306 NULL, /* readpage */
307 NULL, /* writepage */
308 NULL, /* bmap */
309 NULL, /* truncate */
310 NULL, /* permission */
311 NULL, /* smap */
312 NULL, /* updatepage */
313 NULL, /* revalidate */