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 #ifdef MODULE
11 #include <linux/module.h>
12 #endif
13
14 #include <asm/segment.h>
15
16 #include <linux/sched.h>
17 #include <linux/fs.h>
18 #include <linux/msdos_fs.h>
19 #include <linux/errno.h>
20 #include <linux/stat.h>
21 #include <linux/limits.h>
22 #include <linux/umsdos_fs.h>
23 #include <linux/malloc.h>
24
25 #define PRINTK(x)
26 #define Printk(x) printk x
27
28
29 extern struct inode *pseudo_root;
30
31 struct RDIR_FILLDIR {
32 void *dirbuf;
33 filldir_t filldir;
34 int real_root;
35 };
36
37 static int rdir_filldir(
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
38 void * buf,
39 const char * name,
40 int name_len,
41 off_t offset,
42 ino_t ino)
43 {
44 int ret = 0;
45 struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf;
46 if (d->real_root){
47 /* real root of a pseudo_rooted partition */
48 if (name_len != UMSDOS_PSDROOT_LEN
49 || memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){
50 /* So it is not the /linux directory */
51 if (name_len == 2
52 && name[0] == '.'
53 && name[1] == '.'){
54 /* Make sure the .. entry points back to the pseudo_root */
55 ino = pseudo_root->i_ino;
56 }
57 ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
58 }
59 }else{
60 /* Any DOS directory */
61 ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
62 }
63 return ret;
64 }
65
66
67 static int UMSDOS_rreaddir (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
68 struct inode *dir,
69 struct file *filp,
70 void *dirbuf,
71 filldir_t filldir)
72 {
73 struct RDIR_FILLDIR bufk;
74 bufk.filldir = filldir;
75 bufk.dirbuf = dirbuf;
76 bufk.real_root = pseudo_root != NULL
77 && dir == dir->i_sb->s_mounted
78 && dir == pseudo_root->i_sb->s_mounted;
79 return msdos_readdir(dir,filp,&bufk,rdir_filldir);
80 }
81
82 /*
83 Lookup into a non promoted directory.
84 If the result is a directory, make sure we find out if it is
85 a promoted one or not (calling umsdos_setup_dir_inode(inode)).
86 */
87 int umsdos_rlookup_x(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
88 struct inode *dir,
89 const char *name,
90 int len,
91 struct inode **result, /* Will hold inode of the file, if successful */
92 int nopseudo) /* Don't care about pseudo root mode */
93 /* so locating "linux" will work */
94 {
95 int ret;
96 if (pseudo_root != NULL
97 && len == 2
98 && name[0] == '.'
99 && name[1] == '.'
100 && dir == dir->i_sb->s_mounted
101 && dir == pseudo_root->i_sb->s_mounted){
102 *result = pseudo_root;
103 pseudo_root->i_count++;
104 ret = 0;
105 /* #Specification: pseudo root / DOS/..
106 In the real root directory (c:\), the directory ..
107 is the pseudo root (c:\linux).
108 */
109 }else{
110 ret = umsdos_real_lookup (dir,name,len,result);
111 if (ret == 0){
112 struct inode *inode = *result;
113 if (inode == pseudo_root && !nopseudo){
114 /* #Specification: pseudo root / DOS/linux
115 Even in the real root directory (c:\), the directory
116 /linux won't show
117 */
118 ret = -ENOENT;
119 iput (pseudo_root);
120 *result = NULL;
121 }else if (S_ISDIR(inode->i_mode)){
122 /* We must place the proper function table */
123 /* depending if this is a MsDOS directory or an UMSDOS directory */
124 umsdos_setup_dir_inode(inode);
125 }
126 }
127 }
128 iput (dir);
129 return ret;
130 }
131 int UMSDOS_rlookup(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
132 struct inode *dir,
133 const char *name,
134 int len,
135 struct inode **result) /* Will hold inode of the file, if successful */
136 {
137 return umsdos_rlookup_x(dir,name,len,result,0);
138 }
139
140 static int UMSDOS_rrmdir (
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
141 struct inode *dir,
142 const char *name,
143 int len)
144 {
145 /* #Specification: dual mode / rmdir in a DOS directory
146 In a DOS (not EMD in it) directory, we use a reverse strategy
147 compared with an Umsdos directory. We assume that a subdirectory
148 of a DOS directory is also a DOS directory. This is not always
149 true (umssync may be used anywhere), but make sense.
150
151 So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
152 then we check if it is a Umsdos directory. We check if it is
153 really empty (only . .. and --linux-.--- in it). If it is true
154 we remove the EMD and do a msdos_rmdir() again.
155
156 In a Umsdos directory, we assume all subdirectory are also
157 Umsdos directory, so we check the EMD file first.
158 */
159 int ret;
160 if (umsdos_is_pseudodos(dir,name,len)){
161 /* #Specification: pseudo root / rmdir /DOS
162 The pseudo sub-directory /DOS can't be removed!
163 This is done even if the pseudo root is not a Umsdos
164 directory anymore (very unlikely), but an accident (under
165 MsDOS) is always possible.
166
167 EPERM is returned.
168 */
169 ret = -EPERM;
170 }else{
171 umsdos_lockcreate (dir);
172 dir->i_count++;
173 ret = msdos_rmdir (dir,name,len);
174 if (ret == -ENOTEMPTY){
175 struct inode *sdir;
176 dir->i_count++;
177 ret = UMSDOS_rlookup (dir,name,len,&sdir);
178 PRINTK (("rrmdir lookup %d ",ret));
179 if (ret == 0){
180 int empty;
181 if ((empty = umsdos_isempty (sdir)) != 0){
182 PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
183 if (empty == 2){
184 /*
185 Not a Umsdos directory, so the previous msdos_rmdir
186 was not lying :-)
187 */
188 ret = -ENOTEMPTY;
189 }else if (empty == 1){
190 /* We have to removed the EMD file */
191 ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
192 ,UMSDOS_EMD_NAMELEN);
193 sdir = NULL;
194 if (ret == 0){
195 dir->i_count++;
196 ret = msdos_rmdir (dir,name,len);
197 }
198 }
199 }else{
200 ret = -ENOTEMPTY;
201 }
202 iput (sdir);
203 }
204 }
205 umsdos_unlockcreate (dir);
206 }
207 iput (dir);
208 return ret;
209 }
210
211 /* #Specification: dual mode / introduction
212 One goal of UMSDOS is to allow a practical and simple coexistence
213 between MsDOS and Linux in a single partition. Using the EMD file
214 in each directory, UMSDOS add Unix semantics and capabilities to
215 normal DOS file system. To help and simplify coexistence, here is
216 the logic related to the EMD file.
217
218 If it is missing, then the directory is managed by the MsDOS driver.
219 The names are limited to DOS limits (8.3). No links, no device special
220 and pipe and so on.
221
222 If it is there, it is the directory. If it is there but empty, then
223 the directory looks empty. The utility umssync allows synchronisation
224 of the real DOS directory and the EMD.
225
226 Whenever umssync is applied to a directory without EMD, one is
227 created on the fly. The directory is promoted to full unix semantic.
228 Of course, the ls command will show exactly the same content as before
229 the umssync session.
230
231 It is believed that the user/admin will promote directories to unix
232 semantic as needed.
233
234 The strategy to implement this is to use two function table (struct
235 inode_operations). One for true UMSDOS directory and one for directory
236 with missing EMD.
237
238 Functions related to the DOS semantic (but aware of UMSDOS) generally
239 have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
240 from the one with full UMSDOS semantic.
241 */
242 static struct file_operations umsdos_rdir_operations = {
243 NULL, /* lseek - default */
244 UMSDOS_dir_read, /* read */
245 NULL, /* write - bad */
246 UMSDOS_rreaddir, /* readdir */
247 NULL, /* select - default */
248 UMSDOS_ioctl_dir, /* ioctl - default */
249 NULL, /* mmap */
250 NULL, /* no special open code */
251 NULL, /* no special release code */
252 NULL /* fsync */
253 };
254
255 struct inode_operations umsdos_rdir_inode_operations = {
256 &umsdos_rdir_operations, /* default directory file-ops */
257 msdos_create, /* create */
258 UMSDOS_rlookup, /* lookup */
259 NULL, /* link */
260 msdos_unlink, /* unlink */
261 NULL, /* symlink */
262 msdos_mkdir, /* mkdir */
263 UMSDOS_rrmdir, /* rmdir */
264 NULL, /* mknod */
265 msdos_rename, /* rename */
266 NULL, /* readlink */
267 NULL, /* follow_link */
268 NULL, /* bmap */
269 NULL, /* truncate */
270 NULL /* permission */
271 };
272
273