1 /*
2 * linux/fs/umsdos/namei.c
3 *
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... by Werner Almesberger
6 *
7 * Maintain and access the --linux alternate directory file.
8 */
9 #ifdef MODULE
10 #include <linux/module.h>
11 #endif
12
13 #include <linux/errno.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/types.h>
17 #include <linux/fcntl.h>
18 #include <linux/stat.h>
19 #include <linux/string.h>
20 #include <linux/msdos_fs.h>
21 #include <linux/umsdos_fs.h>
22 #include <linux/malloc.h>
23
24 #define PRINTK(x)
25 #define Printk(x) printk x
26
27 #if 1
28 /*
29 Wait for creation exclusivity.
30 Return 0 if the dir was already available.
31 Return 1 if a wait was necessary.
32 When 1 is return, it means a wait was done. It does not
33 mean the directory is available.
34 */
35 static int umsdos_waitcreate(struct inode *dir)
/* ![[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)
*/
36 {
37 int ret = 0;
38 if (dir->u.umsdos_i.u.dir_info.creating
39 && dir->u.umsdos_i.u.dir_info.pid != current->pid){
40 sleep_on(&dir->u.umsdos_i.u.dir_info.p);
41 ret = 1;
42 }
43 return ret;
44 }
45 /*
46 Wait for any lookup process to finish
47 */
48 static void umsdos_waitlookup (struct inode *dir)
/* ![[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)
*/
49 {
50 while (dir->u.umsdos_i.u.dir_info.looking){
51 sleep_on(&dir->u.umsdos_i.u.dir_info.p);
52 }
53 }
54 /*
55 Lock all other process out of this directory.
56 */
57 void umsdos_lockcreate (struct inode *dir)
/* ![[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)
*/
58 {
59 /* #Specification: file creation / not atomic
60 File creation is a two step process. First we create (allocate)
61 an entry in the EMD file and then (using the entry offset) we
62 build a unique name for MSDOS. We create this name in the msdos
63 space.
64
65 We have to use semaphore (sleep_on/wake_up) to prevent lookup
66 into a directory when we create a file or directory and to
67 prevent creation while a lookup is going on. Since many lookup
68 may happen at the same time, the semaphore is a counter.
69
70 Only one creation is allowed at the same time. This protection
71 may not be necessary. The problem arise mainly when a lookup
72 or a readdir is done while a file is partially created. The
73 lookup process see that as a "normal" problem and silently
74 erase the file from the EMD file. Normal because a file
75 may be erased during a MSDOS session, but not removed from
76 the EMD file.
77
78 The locking is done on a directory per directory basis. Each
79 directory inode has its wait_queue.
80
81 For some operation like hard link, things even get worse. Many
82 creation must occur at once (atomic). To simplify the design
83 a process is allowed to recursively lock the directory for
84 creation. The pid of the locking process is kept along with
85 a counter so a second level of locking is granted or not.
86 */
87 /*
88 Wait for any creation process to finish except
89 if we (the process) own the lock
90 */
91 while (umsdos_waitcreate(dir)!=0);
92 dir->u.umsdos_i.u.dir_info.creating++;
93 dir->u.umsdos_i.u.dir_info.pid = current->pid;
94 umsdos_waitlookup (dir);
95 }
96 /*
97 Lock all other process out of those two directories.
98 */
99 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
/* ![[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)
*/
100 {
101 /*
102 We must check that both directory are available before
103 locking anyone of them. This is to avoid some deadlock.
104 Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
105 this to me.
106 */
107 while (1){
108 if (umsdos_waitcreate(dir1)==0
109 && umsdos_waitcreate(dir2)==0){
110 /* We own both now */
111 dir1->u.umsdos_i.u.dir_info.creating++;
112 dir1->u.umsdos_i.u.dir_info.pid = current->pid;
113 dir2->u.umsdos_i.u.dir_info.creating++;
114 dir2->u.umsdos_i.u.dir_info.pid = current->pid;
115 break;
116 }
117 }
118 umsdos_waitlookup(dir1);
119 umsdos_waitlookup(dir2);
120 }
121 /*
122 Wait until creation is finish in this directory.
123 */
124 void umsdos_startlookup (struct inode *dir)
/* ![[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)
*/
125 {
126 while (umsdos_waitcreate (dir) != 0);
127 dir->u.umsdos_i.u.dir_info.looking++;
128 }
129 void check_page_tables(void);
130
131 /*
132 Unlock the directory.
133 */
134 void umsdos_unlockcreate (struct inode *dir)
/* ![[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)
*/
135 {
136 dir->u.umsdos_i.u.dir_info.creating--;
137 if (dir->u.umsdos_i.u.dir_info.creating < 0){
138 printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
139 ,dir->u.umsdos_i.u.dir_info.creating);
140 }
141 wake_up (&dir->u.umsdos_i.u.dir_info.p);
142 }
143 /*
144 Tell directory lookup is over.
145 */
146 void umsdos_endlookup (struct inode *dir)
/* ![[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)
*/
147 {
148 dir->u.umsdos_i.u.dir_info.looking--;
149 if (dir->u.umsdos_i.u.dir_info.looking < 0){
150 printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
151 ,dir->u.umsdos_i.u.dir_info.looking);
152 }
153 wake_up (&dir->u.umsdos_i.u.dir_info.p);
154 }
155 #else
156 static void umsdos_lockcreate (struct inode *dir){}
/* ![[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)
*/
157 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}
/* ![[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)
*/
158 void umsdos_startlookup (struct inode *dir){}
/* ![[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)
*/
159 static void umsdos_unlockcreate (struct inode *dir){}
/* ![[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)
*/
160 void umsdos_endlookup (struct inode *dir){}
/* ![[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)
*/
161 #endif
162 static int umsdos_nevercreat(
/* ![[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)
*/
163 struct inode *dir,
164 const char *name, /* Name of the file to add */
165 int len,
166 int errcod) /* Length of the name */
167 {
168 int ret = 0;
169 if (umsdos_is_pseudodos(dir,name,len)){
170 /* #Specification: pseudo root / any file creation /DOS
171 The pseudo sub-directory /DOS can't be created!
172 EEXIST is returned.
173
174 The pseudo sub-directory /DOS can't be removed!
175 EPERM is returned.
176 */
177 ret = -EPERM;
178 ret = errcod;
179 }else if (name[0] == '.'
180 && (len == 1 || (len == 2 && name[1] == '.'))){
181 /* #Specification: create / . and ..
182 If one try to creates . or .., it always fail and return
183 EEXIST.
184
185 If one try to delete . or .., it always fail and return
186 EPERM.
187
188 This should be test at the VFS layer level to avoid
189 duplicating this in all file systems. Any comments ?
190 */
191 ret = errcod;
192 }
193 return ret;
194 }
195
196 /*
197 Add a new file (ordinary or special) into the alternate directory.
198 The file is added to the real MSDOS directory. If successful, it
199 is then added to the EDM file.
200
201 Return the status of the operation. 0 mean success.
202 */
203 static int umsdos_create_any (
/* ![[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)
*/
204 struct inode *dir,
205 const char *name, /* Name of the file to add */
206 int len, /* Length of the name */
207 int mode, /* Permission bit + file type ??? */
208 int rdev, /* major, minor or 0 for ordinary file */
209 /* and symlinks */
210 char flags,
211 struct inode **result) /* Will hold the inode of the newly created */
212 /* file */
213 {
214 int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
215 if (ret == 0){
216 struct umsdos_info info;
217 ret = umsdos_parse (name,len,&info);
218 *result = NULL;
219 if (ret == 0){
220 info.entry.mode = mode;
221 info.entry.rdev = rdev;
222 info.entry.flags = flags;
223 info.entry.uid = current->fsuid;
224 info.entry.gid = (dir->i_mode & S_ISGID)
225 ? dir->i_gid : current->fsgid;
226 info.entry.ctime = info.entry.atime = info.entry.mtime
227 = CURRENT_TIME;
228 info.entry.nlink = 1;
229 umsdos_lockcreate(dir);
230 ret = umsdos_newentry (dir,&info);
231 if (ret == 0){
232 dir->i_count++;
233 ret = msdos_create (dir,info.fake.fname,info.fake.len
234 ,S_IFREG|0777,result);
235 if (ret == 0){
236 struct inode *inode = *result;
237 umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
238 PRINTK (("inode %p[%d] ",inode,inode->i_count));
239 PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
240 ,info.fake.fname,current->pid,info.f_pos));
241 }else{
242 /* #Specification: create / file exist in DOS
243 Here is a situation. Trying to create a file with
244 UMSDOS. The file is unknown to UMSDOS but already
245 exist in the DOS directory.
246
247 Here is what we are NOT doing:
248
249 We could silently assume that everything is fine
250 and allows the creation to succeed.
251
252 It is possible not all files in the partition
253 are mean to be visible from linux. By trying to create
254 those file in some directory, one user may get access
255 to those file without proper permissions. Looks like
256 a security hole to me. Off course sharing a file system
257 with DOS is some kind of security hole :-)
258
259 So ?
260
261 We return EEXIST in this case.
262 The same is true for directory creation.
263 */
264 if (ret == -EEXIST){
265 printk ("UMSDOS: out of sync, Creation error [%ld], "
266 "deleting %s %d %d pos %ld\n",dir->i_ino
267 ,info.fake.fname,-ret,current->pid,info.f_pos);
268 }
269 umsdos_delentry (dir,&info,0);
270 }
271 PRINTK (("umsdos_create %s ret = %d pos %d\n"
272 ,info.fake.fname,ret,info.f_pos));
273 }
274 umsdos_unlockcreate(dir);
275 }
276 }
277 iput (dir);
278 return ret;
279 }
280 /*
281 Initialise the new_entry from the old for a rename operation.
282 (Only useful for umsdos_rename_f() below).
283 */
284 static void umsdos_ren_init(
/* ![[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)
*/
285 struct umsdos_info *new_info,
286 struct umsdos_info *old_info,
287 int flags) /* 0 == copy flags from old_name */
288 /* != 0, this is the value of flags */
289 {
290 new_info->entry.mode = old_info->entry.mode;
291 new_info->entry.rdev = old_info->entry.rdev;
292 new_info->entry.uid = old_info->entry.uid;
293 new_info->entry.gid = old_info->entry.gid;
294 new_info->entry.ctime = old_info->entry.ctime;
295 new_info->entry.atime = old_info->entry.atime;
296 new_info->entry.mtime = old_info->entry.mtime;
297 new_info->entry.flags = flags ? flags : old_info->entry.flags;
298 new_info->entry.nlink = old_info->entry.nlink;
299 }
300
301 #define chkstk() \
302 if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
303 printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
304 , current->comm,STACK_MAGIC \
305 ,*(unsigned long *)current->kernel_stack_page \
306 ,__LINE__); \
307 }
308
309 /*
310 Rename a file (move) in the file system.
311 */
312 static int umsdos_rename_f(
/* ![[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)
*/
313 struct inode * old_dir,
314 const char * old_name,
315 int old_len,
316 struct inode * new_dir,
317 const char * new_name,
318 int new_len,
319 int flags) /* 0 == copy flags from old_name */
320 /* != 0, this is the value of flags */
321 {
322 int ret = -EPERM;
323 struct umsdos_info old_info;
324 int old_ret = umsdos_parse (old_name,old_len,&old_info);
325 struct umsdos_info new_info;
326 int new_ret = umsdos_parse (new_name,new_len,&new_info);
327 chkstk();
328 PRINTK (("umsdos_rename %d %d ",old_ret,new_ret));
329 if (old_ret == 0 && new_ret == 0){
330 umsdos_lockcreate2(old_dir,new_dir);
331 chkstk();
332 PRINTK (("old findentry "));
333 ret = umsdos_findentry(old_dir,&old_info,0);
334 chkstk();
335 PRINTK (("ret %d ",ret));
336 if (ret == 0){
337 /* check sticky bit on old_dir */
338 if ( !(old_dir->i_mode & S_ISVTX) || fsuser() ||
339 current->fsuid == old_info.entry.uid ||
340 current->fsuid == old_dir->i_uid ) {
341 /* Does new_name already exist? */
342 PRINTK(("new findentry "));
343 ret = umsdos_findentry(new_dir,&new_info,0);
344 if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
345 !(new_dir->i_mode & S_ISVTX) || fsuser() ||
346 current->fsuid == new_info.entry.uid ||
347 current->fsuid == new_dir->i_uid ) {
348 PRINTK (("new newentry "));
349 umsdos_ren_init(&new_info,&old_info,flags);
350 ret = umsdos_newentry (new_dir,&new_info);
351 chkstk();
352 PRINTK (("ret %d %d ",ret,new_info.fake.len));
353 if (ret == 0){
354 PRINTK (("msdos_rename "));
355 old_dir->i_count++;
356 new_dir->i_count++; /* Both inode are needed later */
357 ret = msdos_rename (old_dir
358 ,old_info.fake.fname,old_info.fake.len
359 ,new_dir
360 ,new_info.fake.fname,new_info.fake.len);
361 chkstk();
362 PRINTK (("after m_rename ret %d ",ret));
363 if (ret != 0){
364 umsdos_delentry (new_dir,&new_info
365 ,S_ISDIR(new_info.entry.mode));
366 chkstk();
367 }else{
368 ret = umsdos_delentry (old_dir,&old_info
369 ,S_ISDIR(old_info.entry.mode));
370 chkstk();
371 if (ret == 0){
372 /*
373 This UMSDOS_lookup does not look very useful.
374 It makes sure that the inode of the file will
375 be correctly setup (umsdos_patch_inode()) in
376 case it is already in use.
377
378 Not very efficient ...
379 */
380 struct inode *inode;
381 new_dir->i_count++;
382 PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
383 ret = UMSDOS_lookup (new_dir,new_name,new_len
384 ,&inode);
385 chkstk();
386 if (ret != 0){
387 printk ("UMSDOS: partial rename for file %s\n"
388 ,new_info.entry.name);
389 }else{
390 /*
391 Update f_pos so notify_change will succeed
392 if the file was already in use.
393 */
394 umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
395 chkstk();
396 iput (inode);
397 }
398 }
399 }
400 }
401 }else{
402 /* sticky bit set on new_dir */
403 PRINTK(("sticky set on new "));
404 ret = -EPERM;
405 }
406 }else{
407 /* sticky bit set on old_dir */
408 PRINTK(("sticky set on old "));
409 ret = -EPERM;
410 }
411 }
412 umsdos_unlockcreate(old_dir);
413 umsdos_unlockcreate(new_dir);
414 }
415 iput (old_dir);
416 iput (new_dir);
417 PRINTK (("\n"));
418 return ret;
419 }
420 /*
421 Setup un Symbolic link or a (pseudo) hard link
422 Return a negative error code or 0 if ok.
423 */
424 static int umsdos_symlink_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)
*/
425 struct inode * dir,
426 const char * name,
427 int len,
428 const char * symname, /* name will point to this path */
429 int mode,
430 char flags)
431 {
432 /* #Specification: symbolic links / strategy
433 A symbolic link is simply a file which hold a path. It is
434 implemented as a normal MSDOS file (not very space efficient :-()
435
436 I see 2 different way to do it. One is to place the link data
437 in unused entry of the EMD file. The other is to have a separate
438 file dedicated to hold all symbolic links data.
439
440 Lets go for simplicity...
441 */
442 struct inode *inode;
443 int ret;
444 dir->i_count++; /* We keep the inode in case we need it */
445 /* later */
446 ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
447 PRINTK (("umsdos_symlink ret %d ",ret));
448 if (ret == 0){
449 int len = strlen(symname);
450 struct file filp;
451 filp.f_pos = 0;
452 /* Make the inode acceptable to MSDOS */
453 ret = umsdos_file_write_kmem (inode,&filp,(char*)symname,len);
454 iput (inode);
455 if (ret >= 0){
456 if (ret != len){
457 ret = -EIO;
458 printk ("UMSDOS: "
459 "Can't write symbolic link data\n");
460 }else{
461 ret = 0;
462 }
463 }
464 if (ret != 0){
465 UMSDOS_unlink (dir,name,len);
466 dir = NULL;
467 }
468 }
469 iput (dir);
470 PRINTK (("\n"));
471 return ret;
472 }
473 /*
474 Setup un Symbolic link.
475 Return a negative error code or 0 if ok.
476 */
477 int UMSDOS_symlink(
/* ![[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)
*/
478 struct inode * dir,
479 const char * name,
480 int len,
481 const char * symname) /* name will point to this path */
482 {
483 return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
484 }
485 /*
486 Add a link to an inode in a directory
487 */
488 int UMSDOS_link (
/* ![[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)
*/
489 struct inode * oldinode,
490 struct inode * dir,
491 const char * name,
492 int len)
493 {
494 /* #Specification: hard link / strategy
495 Well ... hard link are difficult to implement on top of an
496 MsDOS fat file system. Unlike UNIX file systems, there are no
497 inode. A directory entry hold the functionality of the inode
498 and the entry.
499
500 We will used the same strategy as a normal Unix file system
501 (with inode) except we will do it symbolically (using paths).
502
503 Because anything can happen during a DOS session (defragment,
504 directory sorting, etc...), we can't rely on MsDOS pseudo
505 inode number to record the link. For this reason, the link
506 will be done using hidden symbolic links. The following
507 scenario illustrate how it work.
508
509 Given a file /foo/file
510
511 #
512 ln /foo/file /tmp/file2
513
514 become internally
515
516 mv /foo/file /foo/-LINK1
517 ln -s /foo/-LINK1 /foo/file
518 ln -s /foo/-LINK1 /tmp/file2
519 #
520
521 Using this strategy, we can operate on /foo/file or /foo/file2.
522 We can remove one and keep the other, like a normal Unix hard link.
523 We can rename /foo/file or /tmp/file2 independently.
524
525 The entry -LINK1 will be hidden. It will hold a link count.
526 When all link are erased, the hidden file is erased too.
527 */
528 /* #Specification: weakness / hard link
529 The strategy for hard link introduces a side effect that
530 may or may not be acceptable. Here is the sequence
531
532 #
533 mkdir subdir1
534 touch subdir1/file
535 mkdir subdir2
536 ln subdir1/file subdir2/file
537 rm subdir1/file
538 rmdir subdir1
539 rmdir: subdir1: Directory not empty
540 #
541
542 This happen because there is an invisible file (--link) in
543 subdir1 which is referenced by subdir2/file.
544
545 Any idea ?
546 */
547 /* #Specification: weakness / hard link / rename directory
548 Another weakness of hard link come from the fact that
549 it is based on hidden symbolic links. Here is an example.
550
551 #
552 mkdir /subdir1
553 touch /subdir1/file
554 mkdir /subdir2
555 ln /subdir1/file subdir2/file
556 mv /subdir1 subdir3
557 ls -l /subdir2/file
558 #
559
560 Since /subdir2/file is a hidden symbolic link
561 to /subdir1/..hlinkNNN, accessing it will fail since
562 /subdir1 does not exist anymore (has been renamed).
563 */
564 int ret = 0;
565 if (S_ISDIR(oldinode->i_mode)){
566 /* #Specification: hard link / directory
567 A hard link can't be made on a directory. EPERM is returned
568 in this case.
569 */
570 ret = -EPERM;
571 }else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){
572 struct inode *olddir;
573 ret = umsdos_get_dirowner(oldinode,&olddir);
574 PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
575 ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
576 if (ret == 0){
577 struct umsdos_dirent entry;
578 umsdos_lockcreate2(dir,olddir);
579 ret = umsdos_inode2entry (olddir,oldinode,&entry);
580 if (ret == 0){
581 PRINTK (("umsdos_link :%s: ino %d flags %d "
582 ,entry.name
583 ,oldinode->i_ino,entry.flags));
584 if (!(entry.flags & UMSDOS_HIDDEN)){
585 /* #Specification: hard link / first hard link
586 The first time a hard link is done on a file, this
587 file must be renamed and hidden. Then an internal
588 symbolic link must be done on the hidden file.
589
590 The second link is done after on this hidden file.
591
592 It is expected that the Linux MSDOS file system
593 keeps the same pseudo inode when a rename operation
594 is done on a file in the same directory.
595 */
596 struct umsdos_info info;
597 ret = umsdos_newhidden (olddir,&info);
598 if (ret == 0){
599 olddir->i_count+=2;
600 PRINTK (("olddir[%d] ",olddir->i_count));
601 ret = umsdos_rename_f (olddir,entry.name
602 ,entry.name_len
603 ,olddir,info.entry.name,info.entry.name_len
604 ,UMSDOS_HIDDEN);
605 if (ret == 0){
606 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
607 if (path == NULL){
608 ret = -ENOMEM;
609 }else{
610 PRINTK (("olddir[%d] ",olddir->i_count));
611 ret = umsdos_locate_path (oldinode,path);
612 PRINTK (("olddir[%d] ",olddir->i_count));
613 if (ret == 0){
614 olddir->i_count++;
615 ret = umsdos_symlink_x (olddir
616 ,entry.name
617 ,entry.name_len,path
618 ,S_IFREG|0777,UMSDOS_HLINK);
619 if (ret == 0){
620 dir->i_count++;
621 ret = umsdos_symlink_x (dir,name,len
622 ,path
623 ,S_IFREG|0777,UMSDOS_HLINK);
624 }
625 }
626 kfree (path);
627 }
628 }
629 }
630 }else{
631 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
632 if (path == NULL){
633 ret = -ENOMEM;
634 }else{
635 ret = umsdos_locate_path (oldinode,path);
636 if (ret == 0){
637 dir->i_count++;
638 ret = umsdos_symlink_x (dir,name,len,path
639 ,S_IFREG|0777,UMSDOS_HLINK);
640 }
641 kfree (path);
642 }
643 }
644 }
645 umsdos_unlockcreate(olddir);
646 umsdos_unlockcreate(dir);
647 }
648 iput (olddir);
649 }
650 if (ret == 0){
651 struct iattr newattrs;
652 oldinode->i_nlink++;
653 newattrs.ia_valid = 0;
654 ret = UMSDOS_notify_change(oldinode, &newattrs);
655 }
656 iput (oldinode);
657 iput (dir);
658 PRINTK (("umsdos_link %d\n",ret));
659 return ret;
660 }
661 /*
662 Add a new file into the alternate directory.
663 The file is added to the real MSDOS directory. If successful, it
664 is then added to the EDM file.
665
666 Return the status of the operation. 0 mean success.
667 */
668 int UMSDOS_create (
/* ![[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)
*/
669 struct inode *dir,
670 const char *name, /* Name of the file to add */
671 int len, /* Length of the name */
672 int mode, /* Permission bit + file type ??? */
673 struct inode **result) /* Will hold the inode of the newly created */
674 /* file */
675 {
676 return umsdos_create_any (dir,name,len,mode,0,0,result);
677 }
678 /*
679 Add a sub-directory in a directory
680 */
681 int UMSDOS_mkdir(
/* ![[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)
*/
682 struct inode * dir,
683 const char * name,
684 int len,
685 int mode)
686 {
687 int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
688 if (ret == 0){
689 struct umsdos_info info;
690 ret = umsdos_parse (name,len,&info);
691 PRINTK (("umsdos_mkdir %d\n",ret));
692 if (ret == 0){
693 info.entry.mode = mode | S_IFDIR;
694 info.entry.rdev = 0;
695 info.entry.uid = current->fsuid;
696 info.entry.gid = (dir->i_mode & S_ISGID)
697 ? dir->i_gid : current->fsgid;
698 info.entry.ctime = info.entry.atime = info.entry.mtime
699 = CURRENT_TIME;
700 info.entry.flags = 0;
701 umsdos_lockcreate(dir);
702 info.entry.nlink = 1;
703 ret = umsdos_newentry (dir,&info);
704 PRINTK (("newentry %d ",ret));
705 if (ret == 0){
706 dir->i_count++;
707 ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
708 if (ret != 0){
709 umsdos_delentry (dir,&info,1);
710 /* #Specification: mkdir / Directory already exist in DOS
711 We do the same thing as for file creation.
712 For all user it is an error.
713 */
714 }else{
715 /* #Specification: mkdir / umsdos directory / create EMD
716 When we created a new sub-directory in a UMSDOS
717 directory (one with full UMSDOS semantic), we
718 create immediately an EMD file in the new
719 sub-directory so it inherit UMSDOS semantic.
720 */
721 struct inode *subdir;
722 ret = umsdos_real_lookup (dir,info.fake.fname
723 ,info.fake.len,&subdir);
724 if (ret == 0){
725 struct inode *result;
726 ret = msdos_create (subdir,UMSDOS_EMD_FILE
727 ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
728 subdir = NULL;
729 iput (result);
730 }
731 if (ret < 0){
732 printk ("UMSDOS: Can't create empty --linux-.---\n");
733 }
734 iput (subdir);
735 }
736 }
737 umsdos_unlockcreate(dir);
738 }
739 }
740 PRINTK (("umsdos_mkdir %d\n",ret));
741 iput (dir);
742 return ret;
743 }
744 /*
745 Add a new device special file into a directory.
746 */
747 int UMSDOS_mknod(
/* ![[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)
*/
748 struct inode * dir,
749 const char * name,
750 int len,
751 int mode,
752 int rdev)
753 {
754 /* #Specification: Special files / strategy
755 Device special file, pipes, etc ... are created like normal
756 file in the msdos file system. Of course they remain empty.
757
758 One strategy was to create those files only in the EMD file
759 since they were not important for MSDOS. The problem with
760 that, is that there were not getting inode number allocated.
761 The MSDOS filesystems is playing a nice game to fake inode
762 number, so why not use it.
763
764 The absence of inode number compatible with those allocated
765 for ordinary files was causing major trouble with hard link
766 in particular and other parts of the kernel I guess.
767 */
768 struct inode *inode;
769 int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
770 iput (inode);
771 return ret;
772 }
773
774 /*
775 Remove a sub-directory.
776 */
777 int UMSDOS_rmdir(
/* ![[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)
*/
778 struct inode * dir,
779 const char * name,
780 int len)
781 {
782 /* #Specification: style / iput strategy
783 In the UMSDOS project, I am trying to apply a single
784 programming style regarding inode management. Many
785 entry point are receiving an inode to act on, and must
786 do an iput() as soon as they are finished with
787 the inode.
788
789 For simple case, there is no problem. When you introduce
790 error checking, you end up with many iput placed around the
791 code.
792
793 The coding style I use all around is one where I am trying
794 to provide independent flow logic (I don't know how to
795 name this). With this style, code is easier to understand
796 but you rapidly get iput() all around. Here is an exemple
797 of what I am trying to avoid.
798
799 #
800 if (a){
801 ...
802 if(b){
803 ...
804 }
805 ...
806 if (c){
807 // Complex state. Was b true ?
808 ...
809 }
810 ...
811 }
812 // Weird state
813 if (d){
814 // ...
815 }
816 // Was iput finally done ?
817 return status;
818 #
819
820 Here is the style I am using. Still sometime I do the
821 first when things are very simple (or very complicated :-( )
822
823 #
824 if (a){
825 if (b){
826 ...
827 }else if (c){
828 // A single state gets here
829 }
830 }else if (d){
831 ...
832 }
833 return status;
834 #
835
836 Again, while this help clarifying the code, I often get a lot
837 of iput(), unlike the first style, where I can place few
838 "strategic" iput(). "strategic" also mean, more difficult
839 to place.
840
841 So here is the style I will be using from now on in this project.
842 There is always an iput() at the end of a function (which has
843 to do an iput()). One iput by inode. There is also one iput()
844 at the places where a successful operation is achieved. This
845 iput() is often done by a sub-function (often from the msdos
846 file system). So I get one too many iput() ? At the place
847 where an iput() is done, the inode is simply nulled, disabling
848 the last one.
849
850 #
851 if (a){
852 if (b){
853 ...
854 }else if (c){
855 msdos_rmdir(dir,...);
856 dir = NULL;
857 }
858 }else if (d){
859 ...
860 }
861 iput (dir);
862 return status;
863 #
864
865 Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
866 pair goes against this practice of "forgetting" the inode as soon
867 as possible.
868 */
869 int ret = umsdos_nevercreat(dir,name,len,-EPERM);
870 if (ret == 0){
871 struct inode *sdir;
872 dir->i_count++;
873 ret = UMSDOS_lookup (dir,name,len,&sdir);
874 PRINTK (("rmdir lookup %d ",ret));
875 if (ret == 0){
876 int empty;
877 umsdos_lockcreate(dir);
878 if (sdir->i_count > 1){
879 ret = -EBUSY;
880 }else if ((empty = umsdos_isempty (sdir)) != 0){
881 PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
882 /* check sticky bit */
883 if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
884 current->fsuid == sdir->i_uid ||
885 current->fsuid == dir->i_uid ) {
886 if (empty == 1){
887 /* We have to removed the EMD file */
888 ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
889 ,UMSDOS_EMD_NAMELEN);
890 sdir = NULL;
891 }
892 /* sdir must be free before msdos_rmdir() */
893 iput (sdir);
894 sdir = NULL;
895 PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
896 if (ret == 0){
897 struct umsdos_info info;
898 dir->i_count++;
899 umsdos_parse (name,len,&info);
900 /* The findentry is there only to complete */
901 /* the mangling */
902 umsdos_findentry (dir,&info,2);
903 ret = msdos_rmdir (dir,info.fake.fname
904 ,info.fake.len);
905 if (ret == 0){
906 ret = umsdos_delentry (dir,&info,1);
907 }
908 }
909 }else{
910 /* sticky bit set and we don't have permission */
911 PRINTK(("sticky set "));
912 ret = -EPERM;
913 }
914 }else{
915 /*
916 The subdirectory is not empty, so leave it there
917 */
918 ret = -ENOTEMPTY;
919 }
920 iput(sdir);
921 umsdos_unlockcreate(dir);
922 }
923 }
924 iput (dir);
925 PRINTK (("umsdos_rmdir %d\n",ret));
926 return ret;
927 }
928 /*
929 Remove a file from the directory.
930 */
931 int UMSDOS_unlink (
/* ![[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)
*/
932 struct inode * dir,
933 const char * name,
934 int len)
935 {
936 int ret = umsdos_nevercreat(dir,name,len,-EPERM);
937 if (ret == 0){
938 struct umsdos_info info;
939 ret = umsdos_parse (name,len,&info);
940 if (ret == 0){
941 umsdos_lockcreate(dir);
942 ret = umsdos_findentry(dir,&info,1);
943 if (ret == 0){
944 PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
945 /* check sticky bit */
946 if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
947 current->fsuid == info.entry.uid ||
948 current->fsuid == dir->i_uid ) {
949 if (info.entry.flags & UMSDOS_HLINK){
950 /* #Specification: hard link / deleting a link
951 When we deletes a file, and this file is a link
952 we must subtract 1 to the nlink field of the
953 hidden link.
954
955 If the count goes to 0, we delete this hidden
956 link too.
957 */
958 /*
959 First, get the inode of the hidden link
960 using the standard lookup function.
961 */
962 struct inode *inode;
963 dir->i_count++;
964 ret = UMSDOS_lookup (dir,name,len,&inode);
965 if (ret == 0){
966 PRINTK (("unlink nlink = %d ",inode->i_nlink));
967 inode->i_nlink--;
968 if (inode->i_nlink == 0){
969 struct inode *hdir = iget(inode->i_sb
970 ,inode->u.umsdos_i.i_dir_owner);
971 struct umsdos_dirent entry;
972 ret = umsdos_inode2entry (hdir,inode,&entry);
973 if (ret == 0){
974 ret = UMSDOS_unlink (hdir,entry.name
975 ,entry.name_len);
976 }else{
977 iput (hdir);
978 }
979 }else{
980 struct iattr newattrs;
981 newattrs.ia_valid = 0;
982 ret = UMSDOS_notify_change (inode, &newattrs);
983 }
984 iput (inode);
985 }
986 }
987 if (ret == 0){
988 ret = umsdos_delentry (dir,&info,0);
989 if (ret == 0){
990 PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
991 dir->i_count++;
992 ret = msdos_unlink_umsdos (dir,info.fake.fname
993 ,info.fake.len);
994 PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
995 ,info.entry.mode,ret));
996 }
997 }
998 }else{
999 /* sticky bit set and we've not got permission */
1000 PRINTK(("sticky set "));
1001 ret = -EPERM;
1002 }
1003 }
1004 umsdos_unlockcreate(dir);
1005 }
1006 }
1007 iput (dir);
1008 PRINTK (("umsdos_unlink %d\n",ret));
1009 return ret;
1010 }
1011
1012 /*
1013 Rename a file (move) in the file system.
1014 */
1015 int UMSDOS_rename(
/* ![[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)
*/
1016 struct inode * old_dir,
1017 const char * old_name,
1018 int old_len,
1019 struct inode * new_dir,
1020 const char * new_name,
1021 int new_len)
1022 {
1023 /* #Specification: weakness / rename
1024 There is a case where UMSDOS rename has a different behavior
1025 than normal UNIX file system. Renaming an open file across
1026 directory boundary does not work. Renaming an open file within
1027 a directory does work however.
1028
1029 The problem (not sure) is in the linux VFS msdos driver.
1030 I believe this is not a bug but a design feature, because
1031 an inode number represent some sort of directory address
1032 in the MSDOS directory structure. So moving the file into
1033 another directory does not preserve the inode number.
1034 */
1035 int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
1036 if (ret == 0){
1037 /* umsdos_rename_f eat the inode and we may need those later */
1038 old_dir->i_count++;
1039 new_dir->i_count++;
1040 ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
1041 ,new_len,0);
1042 if (ret == -EEXIST){
1043 /* #Specification: rename / new name exist
1044 If the destination name already exist, it will
1045 silently be removed. EXT2 does it this way
1046 and this is the spec of SUNOS. So does UMSDOS.
1047
1048 If the destination is an empty directory it will
1049 also be removed.
1050 */
1051 /* #Specification: rename / new name exist / possible flaw
1052 The code to handle the deletion of the target (file
1053 and directory) use to be in umsdos_rename_f, surrounded
1054 by proper directory locking. This was insuring that only
1055 one process could achieve a rename (modification) operation
1056 in the source and destination directory. This was also
1057 insuring the operation was "atomic".
1058
1059 This has been changed because this was creating a kernel
1060 stack overflow (stack is only 4k in the kernel). To avoid
1061 the code doing the deletion of the target (if exist) has
1062 been moved to a upper layer. umsdos_rename_f is tried
1063 once and if it fails with EEXIST, the target is removed
1064 and umsdos_rename_f is done again.
1065
1066 This makes the code cleaner and (not sure) solve a
1067 deadlock problem one tester was experiencing.
1068
1069 The point is to mention that possibly, the semantic of
1070 "rename" may be wrong. Anyone dare to check that :-)
1071 Be aware that IF it is wrong, to produce the problem you
1072 will need two process trying to rename a file to the
1073 same target at the same time. Again, I am not sure it
1074 is a problem at all.
1075 */
1076 /* This is not super efficient but should work */
1077 new_dir->i_count++;
1078 ret = UMSDOS_unlink (new_dir,new_name,new_len);
1079 chkstk();
1080 PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
1081 if (ret == -EISDIR){
1082 new_dir->i_count++;
1083 ret = UMSDOS_rmdir (new_dir,new_name,new_len);
1084 chkstk();
1085 PRINTK (("rename rmdir ret %d -- ",ret));
1086 }
1087 if (ret == 0){
1088 ret = umsdos_rename_f (old_dir,old_name,old_len
1089 ,new_dir,new_name,new_len,0);
1090 new_dir = old_dir = NULL;
1091 }
1092 }
1093 }
1094 iput (new_dir);
1095 iput (old_dir);
1096 return ret;
1097 }
1098