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