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