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