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