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