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