~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/umsdos/namei.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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   * You are in the maze of twisted functions - half of them shouldn't
 11   * be here...
 12   */
 13 
 14 #include <linux/errno.h>
 15 #include <linux/kernel.h>
 16 #include <linux/sched.h>
 17 #include <linux/types.h>
 18 #include <linux/fcntl.h>
 19 #include <linux/stat.h>
 20 #include <linux/string.h>
 21 #include <linux/msdos_fs.h>
 22 #include <linux/umsdos_fs.h>
 23 #include <linux/malloc.h>
 24 
 25 #define UMSDOS_DIR_LOCK
 26 
 27 #ifdef UMSDOS_DIR_LOCK
 28 
 29 static inline void u_sleep_on (struct inode *dir)
 30 {
 31         sleep_on (&dir->u.umsdos_i.dir_info.p);
 32 }
 33 
 34 static inline void u_wake_up (struct inode *dir)
 35 {
 36         wake_up (&dir->u.umsdos_i.dir_info.p);
 37 }
 38 
 39 /*
 40  * Wait for creation exclusivity.
 41  * Return 0 if the dir was already available.
 42  * Return 1 if a wait was necessary.
 43  * When 1 is return, it means a wait was done. It does not
 44  * mean the directory is available.
 45  */
 46 static int umsdos_waitcreate (struct inode *dir)
 47 {
 48         int ret = 0;
 49 
 50         if (dir->u.umsdos_i.dir_info.creating
 51             && dir->u.umsdos_i.dir_info.pid != current->pid) {
 52                 PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", dir->u.umsdos_i.dir_info.pid, current->pid));
 53                 u_sleep_on (dir);
 54                 ret = 1;
 55         }
 56         return ret;
 57 }
 58 
 59 /*
 60  * Wait for any lookup process to finish
 61  */
 62 static void umsdos_waitlookup (struct inode *dir)
 63 {
 64         while (dir->u.umsdos_i.dir_info.looking) {
 65                 u_sleep_on (dir);
 66         }
 67 }
 68 
 69 /*
 70  * Lock all other process out of this directory.
 71  */
 72 /* #Specification: file creation / not atomic
 73  * File creation is a two step process. First we create (allocate)
 74  * an entry in the EMD file and then (using the entry offset) we
 75  * build a unique name for MSDOS. We create this name in the msdos
 76  * space.
 77  * 
 78  * We have to use semaphore (sleep_on/wake_up) to prevent lookup
 79  * into a directory when we create a file or directory and to
 80  * prevent creation while a lookup is going on. Since many lookup
 81  * may happen at the same time, the semaphore is a counter.
 82  * 
 83  * Only one creation is allowed at the same time. This protection
 84  * may not be necessary. The problem arise mainly when a lookup
 85  * or a readdir is done while a file is partially created. The
 86  * lookup process see that as a "normal" problem and silently
 87  * erase the file from the EMD file. Normal because a file
 88  * may be erased during a MSDOS session, but not removed from
 89  * the EMD file.
 90  * 
 91  * The locking is done on a directory per directory basis. Each
 92  * directory inode has its wait_queue.
 93  * 
 94  * For some operation like hard link, things even get worse. Many
 95  * creation must occur at once (atomic). To simplify the design
 96  * a process is allowed to recursively lock the directory for
 97  * creation. The pid of the locking process is kept along with
 98  * a counter so a second level of locking is granted or not.
 99  */
100 void umsdos_lockcreate (struct inode *dir)
101 {
102         /*
103          * Wait for any creation process to finish except
104          * if we (the process) own the lock
105          */
106         while (umsdos_waitcreate (dir) != 0);
107         dir->u.umsdos_i.dir_info.creating++;
108         dir->u.umsdos_i.dir_info.pid = current->pid;
109         umsdos_waitlookup (dir);
110 }
111 
112 /*
113  * Lock all other process out of those two directories.
114  */
115 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
116 {
117         /*
118          * We must check that both directory are available before
119          * locking anyone of them. This is to avoid some deadlock.
120          * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
121          * this to me.
122          */
123         while (1) {
124                 if (umsdos_waitcreate (dir1) == 0
125                     && umsdos_waitcreate (dir2) == 0) {
126                         /* We own both now */
127                         dir1->u.umsdos_i.dir_info.creating++;
128                         dir1->u.umsdos_i.dir_info.pid = current->pid;
129                         dir2->u.umsdos_i.dir_info.creating++;
130                         dir2->u.umsdos_i.dir_info.pid = current->pid;
131                         break;
132                 }
133         }
134         umsdos_waitlookup (dir1);
135         umsdos_waitlookup (dir2);
136 }
137 
138 /*
139  * Wait until creation is finish in this directory.
140  */
141 void umsdos_startlookup (struct inode *dir)
142 {
143         while (umsdos_waitcreate (dir) != 0);
144         dir->u.umsdos_i.dir_info.looking++;
145 }
146 
147 /*
148  * Unlock the directory.
149  */
150 void umsdos_unlockcreate (struct inode *dir)
151 {
152         dir->u.umsdos_i.dir_info.creating--;
153         if (dir->u.umsdos_i.dir_info.creating < 0) {
154                 printk ("UMSDOS: dir->u.umsdos_i.dir_info.creating < 0: %d"
155                         ,dir->u.umsdos_i.dir_info.creating);
156         }
157         u_wake_up (dir);
158 }
159 
160 /*
161  * Tell directory lookup is over.
162  */
163 void umsdos_endlookup (struct inode *dir)
164 {
165         dir->u.umsdos_i.dir_info.looking--;
166         if (dir->u.umsdos_i.dir_info.looking < 0) {
167                 printk ("UMSDOS: dir->u.umsdos_i.dir_info.looking < 0: %d"
168                         ,dir->u.umsdos_i.dir_info.looking);
169         }
170         u_wake_up (dir);
171 }
172 
173 #else
174 static void umsdos_lockcreate (struct inode *dir)
175 {
176 }
177 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
178 {
179 }
180 void umsdos_startlookup (struct inode *dir)
181 {
182 }
183 static void umsdos_unlockcreate (struct inode *dir)
184 {
185 }
186 void umsdos_endlookup (struct inode *dir)
187 {
188 }
189 
190 #endif
191 
192 static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
193                                 int errcod)
194 {
195         int ret = 0;
196 
197         if (umsdos_is_pseudodos (dir, dentry)) {
198                 /* #Specification: pseudo root / any file creation /DOS
199                  * The pseudo sub-directory /DOS can't be created!
200                  * EEXIST is returned.
201                  * 
202                  * The pseudo sub-directory /DOS can't be removed!
203                  * EPERM is returned.
204                  */
205                 ret = errcod;
206         }
207         return ret;
208 }
209 
210 /*
211  * Add a new file (ordinary or special) into the alternate directory.
212  * The file is added to the real MSDOS directory. If successful, it
213  * is then added to the EMD file.
214  * 
215  * Return the status of the operation. 0 mean success.
216  *
217  * #Specification: create / file exists in DOS
218  * Here is a situation: we are trying to create a file with
219  * UMSDOS. The file is unknown to UMSDOS but already
220  * exists in the DOS directory.
221  * 
222  * Here is what we are NOT doing:
223  * 
224  * We could silently assume that everything is fine
225  * and allows the creation to succeed.
226  * 
227  * It is possible not all files in the partition
228  * are meant to be visible from linux. By trying to create
229  * those file in some directory, one user may get access
230  * to those file without proper permissions. Looks like
231  * a security hole to me. Off course sharing a file system
232  * with DOS is some kind of security hole :-)
233  * 
234  * So ?
235  * 
236  * We return EEXIST in this case.
237  * The same is true for directory creation.
238  */
239 static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
240                                 int mode, int rdev, char flags)
241 {
242         struct dentry *fake;
243         struct inode *inode;
244         int ret;
245         struct umsdos_info info;
246 
247         ret = umsdos_nevercreat (dir, dentry, -EEXIST);
248         if (ret)
249                 goto out;
250 
251         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
252         if (ret)
253                 goto out;
254 
255         info.entry.mode = mode;
256         info.entry.rdev = rdev;
257         info.entry.flags = flags;
258         info.entry.uid = current->fsuid;
259         info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
260         info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
261         info.entry.nlink = 1;
262         ret = umsdos_newentry (dentry->d_parent, &info);
263         if (ret)
264                 goto out;
265 
266         /* do a real lookup to get the short name dentry */
267         fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
268         ret = PTR_ERR(fake);
269         if (IS_ERR(fake))
270                 goto out_remove;
271 
272         /* should not exist yet ... */
273         ret = -EEXIST;
274         if (fake->d_inode)
275                 goto out_remove_dput;
276 
277         ret = msdos_create (dir, fake, S_IFREG | 0777);
278         if (ret)
279                 goto out_remove_dput;
280 
281         inode = fake->d_inode;
282         atomic_inc(&inode->i_count);
283         d_instantiate (dentry, inode);
284         dput(fake);
285         if (atomic_read(&inode->i_count) > 1) {
286                 printk(KERN_WARNING
287                         "umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n",
288                         dentry->d_parent->d_name.name, dentry->d_name.name,
289                         inode->i_ino, atomic_read(&inode->i_count));
290         }
291         umsdos_lookup_patch_new(dentry, &info);
292 
293 out:
294         return ret;
295 
296         /* Creation failed ... remove the EMD entry */
297 out_remove_dput:
298         dput(fake);
299 out_remove:
300         if (ret == -EEXIST)
301                 printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
302                         dentry->d_parent->d_name.name, info.fake.fname);
303         umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
304         goto out;
305 }
306 
307 /*
308  * Add a new file into the alternate directory.
309  * The file is added to the real MSDOS directory. If successful, it
310  * is then added to the EMD file.
311  * 
312  * Return the status of the operation. 0 mean success.
313  */
314 int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
315 {
316         return umsdos_create_any (dir, dentry, mode, 0, 0);
317 }
318 
319 
320 /*
321  * Initialise the new_entry from the old for a rename operation.
322  * (Only useful for umsdos_rename_f() below).
323  */
324 static void umsdos_ren_init (struct umsdos_info *new_info,
325                              struct umsdos_info *old_info)
326 {
327         new_info->entry.mode = old_info->entry.mode;
328         new_info->entry.rdev = old_info->entry.rdev;
329         new_info->entry.uid = old_info->entry.uid;
330         new_info->entry.gid = old_info->entry.gid;
331         new_info->entry.ctime = old_info->entry.ctime;
332         new_info->entry.atime = old_info->entry.atime;
333         new_info->entry.mtime = old_info->entry.mtime;
334         new_info->entry.flags = old_info->entry.flags;
335         new_info->entry.nlink = old_info->entry.nlink;
336 }
337 
338 /*
339  * Rename a file (move) in the file system.
340  */
341  
342 static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
343                             struct inode *new_dir, struct dentry *new_dentry,
344                             int flags)
345 {
346         struct inode *old_inode = old_dentry->d_inode;
347         struct dentry *old, *new, *old_emd;
348         int err, ret;
349         struct umsdos_info old_info;
350         struct umsdos_info new_info;
351 
352         ret = -EPERM;
353         err = umsdos_parse (old_dentry->d_name.name,
354                                 old_dentry->d_name.len, &old_info);
355         if (err)
356                 goto out;
357         err = umsdos_parse (new_dentry->d_name.name,
358                                 new_dentry->d_name.len, &new_info);
359         if (err)
360                 goto out;
361 
362         /* Get the EMD dentry for the old parent */
363         old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
364         ret = PTR_ERR(old_emd);
365         if (IS_ERR(old_emd))
366                 goto out;
367 
368         umsdos_lockcreate2 (old_dir, new_dir);
369 
370         ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
371         if (ret)
372                 goto out_unlock;
373 
374         err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
375         if (err == 0) {
376                 /* check whether it _really_ exists ... */
377                 ret = -EEXIST;
378                 if (new_dentry->d_inode)
379                         goto out_unlock;
380 
381                 /* bogus lookup? complain and fix up the EMD ... */
382                 printk(KERN_WARNING
383                         "umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
384                         new_dentry->d_parent->d_name.name, new_info.entry.name);
385                 err = umsdos_delentry(new_dentry->d_parent, &new_info,
386                                         S_ISDIR(new_info.entry.mode));
387         }
388 
389         umsdos_ren_init (&new_info, &old_info);
390         if (flags)
391                 new_info.entry.flags = flags;
392         ret = umsdos_newentry (new_dentry->d_parent, &new_info);
393         if (ret)
394                 goto out_unlock;
395 
396         /* If we're moving a hardlink, drop it first */
397         if (old_info.entry.flags & UMSDOS_HLINK) {
398                 d_drop(old_dentry);
399         }
400 
401         old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname, 
402                                         old_info.fake.len);
403         ret = PTR_ERR(old);
404         if (IS_ERR(old))
405                 goto out_unlock;
406         /* make sure it's the same inode! */
407         ret = -ENOENT;
408         if (old->d_inode != old_inode)
409                 goto out_dput;
410 
411         new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, 
412                                         new_info.fake.len);
413         ret = PTR_ERR(new);
414         if (IS_ERR(new))
415                 goto out_dput;
416 
417         /* Do the msdos-level rename */
418         ret = msdos_rename (old_dir, old, new_dir, new);
419 
420         dput(new);
421 
422         /* If the rename failed, remove the new EMD entry */
423         if (ret != 0) {
424                 umsdos_delentry (new_dentry->d_parent, &new_info,
425                                  S_ISDIR (new_info.entry.mode));
426                 goto out_dput;
427         }
428 
429         /*
430          * Rename successful ... remove the old name from the EMD.
431          * Note that we use the EMD parent here, as the old dentry
432          * may have moved to a new parent ...
433          */
434         err = umsdos_delentry (old_emd->d_parent, &old_info,
435                                 S_ISDIR (old_info.entry.mode));
436         if (err) {
437                 /* Failed? Complain a bit, but don't fail the operation */
438                 printk(KERN_WARNING 
439                         "umsdos_rename_f: delentry %s/%s failed, error=%d\n",
440                         old_emd->d_parent->d_name.name, old_info.entry.name,
441                         err);
442         }
443 
444         /*
445          * Update f_pos so notify_change will succeed
446          * if the file was already in use.
447          */
448         umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
449 
450         /* dput() the dentry if we haven't already */
451 out_dput:
452         dput(old);
453 
454 out_unlock:
455         dput(old_emd);
456         umsdos_unlockcreate (old_dir);
457         umsdos_unlockcreate (new_dir);
458 
459 out:
460         Printk ((" _ret=%d\n", ret));
461         return ret;
462 }
463 
464 /*
465  * Setup a Symbolic link or a (pseudo) hard link
466  * Return a negative error code or 0 if OK.
467  */
468 /* #Specification: symbolic links / strategy
469  * A symbolic link is simply a file which holds a path. It is
470  * implemented as a normal MSDOS file (not very space efficient :-()
471  * 
472  * I see two different ways to do this: One is to place the link data
473  * in unused entries of the EMD file; the other is to have a separate
474  * file dedicated to hold all symbolic links data.
475  * 
476  * Let's go for simplicity...
477  */
478 
479 /*
480  * AV. Should be called with dir->i_sem down.
481  */
482 static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
483                         const char *symname, int mode, char flags)
484 {
485         int ret, len;
486 
487         ret = umsdos_create_any (dir, dentry, mode, 0, flags);
488         if (ret) {
489                 printk(KERN_WARNING
490                         "umsdos_symlink: create failed, ret=%d\n", ret);
491                 goto out;
492         }
493 
494         len = strlen (symname);
495         ret = block_symlink(dentry->d_inode, symname, len);
496         if (ret < 0)
497                 goto out_unlink;
498 out:
499         return ret;
500 
501 out_unlink:
502         printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");
503         UMSDOS_unlink (dir, dentry);
504         d_drop(dentry);
505         goto out;
506 }
507 
508 /*
509  * Setup a Symbolic link.
510  * Return a negative error code or 0 if OK.
511  */
512 int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
513                  const char *symname)
514 {
515         return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
516 }
517 
518 /*
519  * Add a link to an inode in a directory
520  */
521 int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
522                  struct dentry *dentry)
523 {
524         struct inode *oldinode = olddentry->d_inode;
525         struct inode *olddir = olddentry->d_parent->d_inode;
526         struct dentry *temp;
527         char *path;
528         unsigned long buffer;
529         int ret;
530         struct umsdos_info old_info;
531         struct umsdos_info hid_info;
532 
533 #ifdef UMSDOS_DEBUG_VERBOSE
534 printk("umsdos_link: new %s%s -> %s/%s\n",
535 dentry->d_parent->d_name.name, dentry->d_name.name, 
536 olddentry->d_parent->d_name.name, olddentry->d_name.name);
537 #endif
538  
539         ret = -EPERM;
540         if (S_ISDIR (oldinode->i_mode))
541                 goto out;
542 
543         ret = umsdos_nevercreat (dir, dentry, -EPERM);
544         if (ret)
545                 goto out;
546 
547         ret = -ENOMEM;
548         buffer = get_free_page(GFP_KERNEL);
549         if (!buffer)
550                 goto out;
551 
552         /*
553          * Lock the link parent if it's not the same directory.
554          */
555         ret = -EDEADLOCK;
556         if (olddir != dir) {
557                 if (atomic_read(&olddir->i_sem.count) < 1)
558                         goto out_free;
559                 down(&olddir->i_sem);
560         }
561 
562         /*
563          * Parse the name and get the visible directory entry.
564          */
565         ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len,
566                                 &old_info);
567         if (ret)
568                 goto out_unlock;
569         ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
570         if (ret) {
571 printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",
572 olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
573                 goto out_unlock;
574         }
575 
576         /*
577          * If the visible dentry is a pseudo-hardlink, the original
578          * file must be already hidden.
579          */
580         if (!(old_info.entry.flags & UMSDOS_HLINK)) {
581                 int err;
582 
583                 /* create a hidden link name */
584                 ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
585                 if (ret) {
586 printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",
587 olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
588                         goto out_unlock;
589                 }
590 
591                 /*
592                  * Make a dentry and rename the original file ...
593                  */
594                 temp = umsdos_lookup_dentry(olddentry->d_parent,
595                                                 hid_info.entry.name,
596                                                 hid_info.entry.name_len, 0); 
597                 ret = PTR_ERR(temp);
598                 if (IS_ERR(temp)) {
599 printk("umsdos_link: lookup %s/%s failed, ret=%d\n",
600 dentry->d_parent->d_name.name, hid_info.entry.name, ret);
601                         goto cleanup;
602                 }
603                 /* rename the link to the hidden location ... */
604                 ret = umsdos_rename_f(olddir, olddentry, olddir, temp,
605                                         UMSDOS_HIDDEN);
606                 d_move(olddentry, temp);
607                 dput(temp);
608                 if (ret) {
609 printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
610 temp->d_parent->d_name.name, temp->d_name.name, ret);
611                         goto cleanup;
612                 }
613                 /* mark the inode as a hardlink */
614                 oldinode->u.umsdos_i.i_is_hlink = 1;
615 
616                 /*
617                  * Capture the path to the hidden link.
618                  */
619                 path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
620 Printk(("umsdos_link: hidden link path=%s\n", path));
621 
622                 /*
623                  * Recreate a dentry for the original name and symlink it,
624                  * then symlink the new dentry. Don't give up if one fails,
625                  * or we'll lose the file completely!
626                  *
627                  * Note: this counts as the "original" reference, so we 
628                  * don't increment i_nlink for this one.
629                  */ 
630                 temp = umsdos_lookup_dentry(olddentry->d_parent,
631                                                 old_info.entry.name,
632                                                 old_info.entry.name_len, 0); 
633                 ret = PTR_ERR(temp);
634                 if (!IS_ERR(temp)) {
635                         ret = umsdos_symlink_x (olddir, temp, path, 
636                                                 S_IFREG | 0777, UMSDOS_HLINK);
637                         dput(temp);
638                 }
639 
640                 /* This symlink increments i_nlink (see below.) */
641                 err = umsdos_symlink_x (dir, dentry, path,
642                                         S_IFREG | 0777, UMSDOS_HLINK);
643                 /* fold the two errors */
644                 if (!ret)
645                         ret = err;
646                 goto out_unlock;
647 
648                 /* creation failed ... remove the link entry */
649         cleanup:
650 printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
651 ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
652                 err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
653                 goto out_unlock;
654         }
655 
656 Printk(("UMSDOS_link: %s/%s already hidden\n",
657 olddentry->d_parent->d_name.name, olddentry->d_name.name));
658         /*
659          * The original file is already hidden, and we need to get 
660          * the dentry for its real name, not the visible name.
661          * N.B. make sure it's the hidden inode ...
662          */
663         if (!oldinode->u.umsdos_i.i_is_hlink)
664                 printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
665                         olddentry->d_parent->d_name.name,
666                         olddentry->d_name.name, oldinode->i_ino);
667 
668         /*
669          * In order to get the correct (real) inode, we just drop
670          * the original dentry.
671          */ 
672         d_drop(olddentry);
673 Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
674 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
675 
676         /* Do a real lookup to get the short name dentry */
677         temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, 
678                                         old_info.fake.len);
679         ret = PTR_ERR(temp);
680         if (IS_ERR(temp))
681                 goto out_unlock;
682 
683         /* now resolve the link ... */
684         temp = umsdos_solve_hlink(temp);
685         ret = PTR_ERR(temp);
686         if (IS_ERR(temp))
687                 goto out_unlock;
688         path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
689         dput(temp);
690 Printk(("umsdos_link: %s/%s already hidden, path=%s\n",
691 olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
692 
693         /* finally we can symlink it ... */
694         ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
695 
696 out_unlock:
697         /* remain locked for the call to notify_change ... */
698         if (ret == 0) {
699                 struct iattr newattrs;
700 
701 #ifdef UMSDOS_PARANOIA
702 if (!oldinode->u.umsdos_i.i_is_hlink)
703 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
704 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
705 #endif
706                 oldinode->i_nlink++;
707 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
708 olddentry->d_parent->d_name.name, olddentry->d_name.name,
709 oldinode->i_ino, oldinode->i_nlink));
710                 newattrs.ia_valid = 0;
711                 ret = umsdos_notify_change_locked(olddentry, &newattrs);
712                 if (ret == 0)
713                         mark_inode_dirty(olddentry->d_inode);
714         }
715         if (olddir != dir)
716                 up(&olddir->i_sem);
717 
718 out_free:
719         free_page(buffer);
720 out:
721         Printk (("umsdos_link %d\n", ret));
722         return ret;
723 }
724 
725 
726 /*
727  * Add a sub-directory in a directory
728  */
729 /* #Specification: mkdir / Directory already exist in DOS
730  * We do the same thing as for file creation.
731  * For all user it is an error.
732  */
733 /* #Specification: mkdir / umsdos directory / create EMD
734  * When we created a new sub-directory in a UMSDOS
735  * directory (one with full UMSDOS semantics), we
736  * create immediately an EMD file in the new
737  * sub-directory so it inherits UMSDOS semantics.
738  */
739 int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
740 {
741         struct dentry *temp;
742         struct inode *inode;
743         int ret, err;
744         struct umsdos_info info;
745 
746         ret = umsdos_nevercreat (dir, dentry, -EEXIST);
747         if (ret)
748                 goto out;
749 
750         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
751         if (ret)
752                 goto out;
753 
754         info.entry.mode = mode | S_IFDIR;
755         info.entry.rdev = 0;
756         info.entry.uid = current->fsuid;
757         info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
758         info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
759         info.entry.flags = 0;
760         info.entry.nlink = 1;
761         ret = umsdos_newentry (dentry->d_parent, &info);
762         if (ret)
763                 goto out;
764 
765         /* lookup the short name dentry */
766         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
767         ret = PTR_ERR(temp);
768         if (IS_ERR(temp))
769                 goto out_remove;
770 
771         /* Make sure the short name doesn't exist */
772         ret = -EEXIST;
773         if (temp->d_inode) {
774 printk("umsdos_mkdir: short name %s/%s exists\n",
775 dentry->d_parent->d_name.name, info.fake.fname);
776                 goto out_remove_dput;
777         }
778 
779         ret = msdos_mkdir (dir, temp, mode);
780         if (ret)
781                 goto out_remove_dput;
782 
783         /*
784          * Lock the inode to protect the EMD creation ...
785          */
786         inode = temp->d_inode;
787         down(&inode->i_sem);
788 
789         atomic_inc(&inode->i_count);
790         d_instantiate(dentry, inode);
791 
792         /* N.B. this should have an option to create the EMD ... */
793         umsdos_lookup_patch_new(dentry, &info);
794 
795         /* 
796          * Create the EMD file, and set up the dir so it is
797          * promoted to EMD with the EMD file invisible.
798          *
799          * N.B. error return if EMD fails?
800          */
801         err = umsdos_make_emd(dentry);
802         umsdos_setup_dir(dentry);
803 
804         up(&inode->i_sem);
805         dput(temp);
806 
807 out:
808         Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
809                 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
810         return ret;
811 
812         /* an error occurred ... remove EMD entry. */
813 out_remove_dput:
814         dput(temp);
815 out_remove:
816         umsdos_delentry (dentry->d_parent, &info, 1);
817         goto out;
818 }
819 
820 /*
821  * Add a new device special file into a directory.
822  *
823  * #Specification: Special files / strategy
824  * Device special file, pipes, etc ... are created like normal
825  * file in the msdos file system. Of course they remain empty.
826  * 
827  * One strategy was to create those files only in the EMD file
828  * since they were not important for MSDOS. The problem with
829  * that, is that there were not getting inode number allocated.
830  * The MSDOS filesystems is playing a nice game to fake inode
831  * number, so why not use it.
832  * 
833  * The absence of inode number compatible with those allocated
834  * for ordinary files was causing major trouble with hard link
835  * in particular and other parts of the kernel I guess.
836  */
837 int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
838                  int mode, int rdev)
839 {
840         return umsdos_create_any (dir, dentry, mode, rdev, 0);
841 }
842 
843 /*
844  * Remove a sub-directory.
845  */
846 int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
847 {
848         struct dentry *temp;
849         int ret, err, empty;
850         struct umsdos_info info;
851 
852         ret = umsdos_nevercreat (dir, dentry, -EPERM);
853         if (ret)
854                 goto out;
855 
856         ret = -EBUSY;
857         if (!d_unhashed(dentry))
858                 goto out;
859 
860         /* check whether the EMD is empty */
861         ret = -ENOTEMPTY;
862         empty = umsdos_isempty (dentry);
863 
864         /* Have to remove the EMD file? */
865         if (empty == 1) {
866                 struct dentry *demd;
867 
868                 demd = umsdos_get_emd_dentry(dentry);
869                 if (!IS_ERR(demd)) {
870                         err = -ENOENT;
871                         if (demd->d_inode)
872                                 err = msdos_unlink (dentry->d_inode, demd);
873 Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
874 #ifdef UMSDOS_PARANOIA
875 if (err)
876 printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
877 demd->d_parent->d_name.name, demd->d_name.name, err);
878 #endif
879                         if (!err) {
880                                 d_delete(demd);
881                                 ret = 0;
882                         }
883                         dput(demd);
884                 }
885         } else if (empty == 2)
886                 ret = 0;
887         if (ret)
888                 goto out;
889 
890         umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
891         /* Call findentry to complete the mangling */
892         umsdos_findentry (dentry->d_parent, &info, 2);
893         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
894         ret = PTR_ERR(temp);
895         if (IS_ERR(temp))
896                 goto out;
897         /*
898          * Attempt to remove the msdos name.
899          */
900         ret = msdos_rmdir (dir, temp);
901         if (ret && ret != -ENOENT)
902                 goto out_dput;
903 
904         d_delete(temp);
905         /* OK so far ... remove the name from the EMD */
906         ret = umsdos_delentry (dentry->d_parent, &info, 1);
907 #ifdef UMSDOS_PARANOIA
908 if (ret)
909 printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
910 #endif
911 
912         /* dput() temp if we didn't do it above */
913 out_dput:
914         dput(temp);
915 
916 out:
917         Printk (("umsdos_rmdir %d\n", ret));
918         return ret;
919 }
920 
921 
922 /*
923  * Remove a file from the directory.
924  *
925  * #Specification: hard link / deleting a link
926  * When we delete a file and this file is a link,
927  * we must subtract 1 from the nlink field of the
928  * hidden link.
929  * 
930  * If the count goes to 0, we delete this hidden
931  * link too.
932  */
933 int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
934 {
935         struct dentry *temp, *link = NULL;
936         struct inode *inode;
937         int ret;
938         struct umsdos_info info;
939 
940 Printk(("UMSDOS_unlink: entering %s/%s\n",
941 dentry->d_parent->d_name.name, dentry->d_name.name));
942 
943         ret = umsdos_nevercreat (dir, dentry, -EPERM);
944         if (ret)
945                 goto out;
946 
947         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
948         if (ret)
949                 goto out;
950 
951         umsdos_lockcreate (dir);
952         ret = umsdos_findentry (dentry->d_parent, &info, 1);
953         if (ret) {
954 printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
955 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
956                 goto out_unlock;
957         }
958 
959 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
960 
961         /*
962          * Note! If this is a hardlink and the names are aliased,
963          * the short-name lookup will return the hardlink dentry.
964          * In order to get the correct (real) inode, we just drop
965          * the original dentry.
966          */ 
967         if (info.entry.flags & UMSDOS_HLINK) {
968                 d_drop(dentry);
969         }
970 
971         /* Do a real lookup to get the short name dentry */
972         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
973         ret = PTR_ERR(temp);
974         if (IS_ERR(temp))
975                 goto out_unlock;
976 
977         /*
978          * Resolve hardlinks now, but defer processing until later.
979          */
980         if (info.entry.flags & UMSDOS_HLINK) {
981                 link = umsdos_solve_hlink(dget(temp));
982         }
983 
984         /* Delete the EMD entry */
985         ret = umsdos_delentry (dentry->d_parent, &info, 0);
986         if (ret && ret != -ENOENT) {
987                 printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
988                         info.entry.name, ret);
989                 goto out_dput;
990         }
991 
992         ret = msdos_unlink(dir, temp);
993         if (!ret)
994                 d_delete(temp);
995 #ifdef UMSDOS_PARANOIA
996 if (ret)
997 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
998 temp->d_parent->d_name.name, temp->d_name.name, ret);
999 #endif
1000 
1001         /* dput() temp if we didn't do it above */
1002 out_dput:
1003         dput(temp);
1004 
1005 out_unlock:
1006         umsdos_unlockcreate (dir);
1007 
1008         /*
1009          * Now check for deferred handling of a hardlink.
1010          */
1011         if (!link)
1012                 goto out;
1013 
1014         if (IS_ERR(link)) {
1015 printk("umsdos_unlink: failed to resolve %s/%s\n",
1016 dentry->d_parent->d_name.name, dentry->d_name.name);
1017                 if (!ret)
1018                         ret = PTR_ERR(link);
1019                 goto out;
1020         }
1021 
1022 Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
1023 link->d_parent->d_name.name, link->d_name.name, ret));
1024 
1025         /* already have an error? */
1026         if (ret)
1027                 goto out_cleanup;
1028 
1029         /* make sure the link exists ... */
1030         inode = link->d_inode;
1031         if (!inode) {
1032                 printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
1033                 goto out_cleanup;
1034         }
1035 
1036         /*
1037          * If this was the last linked reference, delete it now.
1038          *
1039          * N.B. Deadlock problem? We should be holding the lock
1040          * for the hardlink's parent, but another process might
1041          * be holding that lock waiting for us to finish ...
1042          */
1043         if (inode->i_nlink <= 1) {
1044                 ret = UMSDOS_unlink (link->d_parent->d_inode, link);
1045                 if (ret) {
1046                         printk(KERN_WARNING
1047                                 "umsdos_unlink: link removal failed, ret=%d\n",
1048                                  ret);
1049                 } else
1050                         d_delete(link);
1051         } else {
1052                 struct iattr newattrs;
1053                 inode->i_nlink--;
1054                 newattrs.ia_valid = 0;
1055                 ret = umsdos_notify_change_locked(link, &newattrs);
1056                 if (!ret)
1057                         mark_inode_dirty(link->d_inode);
1058         }
1059 
1060 out_cleanup:
1061         d_drop(link);
1062         dput(link);
1063 
1064 out:
1065         Printk (("umsdos_unlink %d\n", ret));
1066         return ret;
1067 }
1068 
1069 /*
1070  * Rename (move) a file.
1071  */
1072 int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
1073                    struct inode *new_dir, struct dentry *new_dentry)
1074 {
1075         int ret;
1076 
1077         ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
1078         if (ret)
1079                 return ret;
1080 
1081                 /*
1082                  * If the target already exists, delete it first.
1083                  */
1084         if (new_dentry->d_inode) {
1085                 dget(new_dentry);
1086                 if (S_ISDIR(old_dentry->d_inode->i_mode))
1087                         ret = UMSDOS_rmdir (new_dir, new_dentry);
1088                 else
1089                         ret = UMSDOS_unlink (new_dir, new_dentry);
1090                 if (!ret)
1091                         d_drop(new_dentry);
1092                 dput(new_dentry);
1093                 if (ret)
1094                         return ret;
1095         }
1096         ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
1097         return ret;
1098 }
1099 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.