📄 namei.c
字号:
if (atomic_read(&olddir->i_sem.count) < 1) goto out_free; down(&olddir->i_sem); } /* * Parse the name and get the visible directory entry. */ ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len, &old_info); if (ret) goto out_unlock; ret = umsdos_findentry (olddentry->d_parent, &old_info, 1); if (ret) {printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",olddentry->d_parent->d_name.name, olddentry->d_name.name, ret); goto out_unlock; } /* * If the visible dentry is a pseudo-hardlink, the original * file must be already hidden. */ if (!(old_info.entry.flags & UMSDOS_HLINK)) { int err; /* create a hidden link name */ ret = umsdos_newhidden (olddentry->d_parent, &hid_info); if (ret) {printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",olddentry->d_parent->d_name.name, hid_info.entry.name, ret); goto out_unlock; } /* * Make a dentry and rename the original file ... */ temp = umsdos_lookup_dentry(olddentry->d_parent, hid_info.entry.name, hid_info.entry.name_len, 0); ret = PTR_ERR(temp); if (IS_ERR(temp)) {printk("umsdos_link: lookup %s/%s failed, ret=%d\n",dentry->d_parent->d_name.name, hid_info.entry.name, ret); goto cleanup; } /* rename the link to the hidden location ... */ ret = umsdos_rename_f(olddir, olddentry, olddir, temp, UMSDOS_HIDDEN); d_move(olddentry, temp); dput(temp); if (ret) {printk("umsdos_link: rename to %s/%s failed, ret=%d\n",temp->d_parent->d_name.name, temp->d_name.name, ret); goto cleanup; } /* mark the inode as a hardlink */ oldinode->u.umsdos_i.i_is_hlink = 1; /* * Capture the path to the hidden link. */ path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);Printk(("umsdos_link: hidden link path=%s\n", path)); /* * Recreate a dentry for the original name and symlink it, * then symlink the new dentry. Don't give up if one fails, * or we'll lose the file completely! * * Note: this counts as the "original" reference, so we * don't increment i_nlink for this one. */ temp = umsdos_lookup_dentry(olddentry->d_parent, old_info.entry.name, old_info.entry.name_len, 0); ret = PTR_ERR(temp); if (!IS_ERR(temp)) { ret = umsdos_symlink_x (olddir, temp, path, S_IFREG | 0777, UMSDOS_HLINK); dput(temp); } /* This symlink increments i_nlink (see below.) */ err = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777, UMSDOS_HLINK); /* fold the two errors */ if (!ret) ret = err; goto out_unlock; /* creation failed ... remove the link entry */ cleanup:printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",ret, olddentry->d_parent->d_name.name, hid_info.entry.name); err = umsdos_delentry(olddentry->d_parent, &hid_info, 0); goto out_unlock; }Printk(("UMSDOS_link: %s/%s already hidden\n",olddentry->d_parent->d_name.name, olddentry->d_name.name)); /* * The original file is already hidden, and we need to get * the dentry for its real name, not the visible name. * N.B. make sure it's the hidden inode ... */ if (!oldinode->u.umsdos_i.i_is_hlink) printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n", olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino); /* * In order to get the correct (real) inode, we just drop * the original dentry. */ d_drop(olddentry);Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname)); /* Do a real lookup to get the short name dentry */ temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, old_info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock; /* now resolve the link ... */ temp = umsdos_solve_hlink(temp); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock; path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE); dput(temp);Printk(("umsdos_link: %s/%s already hidden, path=%s\n",olddentry->d_parent->d_name.name, olddentry->d_name.name, path)); /* finally we can symlink it ... */ ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);out_unlock: /* remain locked for the call to notify_change ... */ if (ret == 0) { struct iattr newattrs; /* Do a real lookup to get the short name dentry */ temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, old_info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock2; /* now resolve the link ... */ temp = umsdos_solve_hlink(temp); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock2;#ifdef UMSDOS_PARANOIAif (!oldinode->u.umsdos_i.i_is_hlink)printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);#endif temp->d_inode->i_nlink++;Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",olddentry->d_parent->d_name.name, olddentry->d_name.name,oldinode->i_ino, oldinode->i_nlink)); newattrs.ia_valid = 0; ret = umsdos_notify_change_locked(temp, &newattrs); if (ret == 0) mark_inode_dirty(temp->d_inode); dput(temp);out_unlock2: if (ret == 0) mark_inode_dirty(olddentry->d_inode); } if (olddir != dir) up(&olddir->i_sem);out_free: free_page(buffer);out: Printk (("umsdos_link %d\n", ret)); return ret;}/* * Add a sub-directory in a directory *//* #Specification: mkdir / Directory already exist in DOS * We do the same thing as for file creation. * For all user it is an error. *//* #Specification: mkdir / umsdos directory / create EMD * When we created a new sub-directory in a UMSDOS * directory (one with full UMSDOS semantics), we * create immediately an EMD file in the new * sub-directory so it inherits UMSDOS semantics. */int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode){ struct dentry *temp; struct inode *inode; int ret, err; struct umsdos_info info; ret = umsdos_nevercreat (dir, dentry, -EEXIST); if (ret) goto out; ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); if (ret) goto out; info.entry.mode = mode | S_IFDIR; info.entry.rdev = 0; info.entry.uid = current->fsuid; info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME; info.entry.flags = 0; info.entry.nlink = 1; ret = umsdos_newentry (dentry->d_parent, &info); if (ret) goto out; /* lookup the short name dentry */ temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_remove; /* Make sure the short name doesn't exist */ ret = -EEXIST; if (temp->d_inode) {printk("umsdos_mkdir: short name %s/%s exists\n",dentry->d_parent->d_name.name, info.fake.fname); goto out_remove_dput; } ret = msdos_mkdir (dir, temp, mode); if (ret) goto out_remove_dput; /* * Lock the inode to protect the EMD creation ... */ inode = temp->d_inode; down(&inode->i_sem); atomic_inc(&inode->i_count); d_instantiate(dentry, inode); /* N.B. this should have an option to create the EMD ... */ umsdos_lookup_patch_new(dentry, &info); /* * Create the EMD file, and set up the dir so it is * promoted to EMD with the EMD file invisible. * * N.B. error return if EMD fails? */ err = umsdos_make_emd(dentry); umsdos_setup_dir(dentry); up(&inode->i_sem); dput(temp);out: Printk(("umsdos_mkdir: %s/%s, ret=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, ret)); return ret; /* an error occurred ... remove EMD entry. */out_remove_dput: dput(temp);out_remove: umsdos_delentry (dentry->d_parent, &info, 1); goto out;}/* * Add a new device special file into a directory. * * #Specification: Special files / strategy * Device special file, pipes, etc ... are created like normal * file in the msdos file system. Of course they remain empty. * * One strategy was to create those files only in the EMD file * since they were not important for MSDOS. The problem with * that, is that there were not getting inode number allocated. * The MSDOS filesystems is playing a nice game to fake inode * number, so why not use it. * * The absence of inode number compatible with those allocated * for ordinary files was causing major trouble with hard link * in particular and other parts of the kernel I guess. */int UMSDOS_mknod (struct inode *dir, struct dentry *dentry, int mode, int rdev){ return umsdos_create_any (dir, dentry, mode, rdev, 0);}/* * Remove a sub-directory. */int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry){ struct dentry *temp; int ret, err, empty; struct umsdos_info info; ret = umsdos_nevercreat (dir, dentry, -EPERM); if (ret) goto out; ret = -EBUSY; if (!d_unhashed(dentry)) goto out; /* check whether the EMD is empty */ ret = -ENOTEMPTY; empty = umsdos_isempty (dentry); /* Have to remove the EMD file? */ if (empty == 1) { struct dentry *demd; demd = umsdos_get_emd_dentry(dentry); if (!IS_ERR(demd)) { err = -ENOENT; if (demd->d_inode) err = msdos_unlink (dentry->d_inode, demd);Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));#ifdef UMSDOS_PARANOIAif (err)printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",demd->d_parent->d_name.name, demd->d_name.name, err);#endif if (!err) { d_delete(demd); ret = 0; } dput(demd); } } else if (empty == 2) ret = 0; if (ret) goto out; umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); /* Call findentry to complete the mangling */ umsdos_findentry (dentry->d_parent, &info, 2); temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out; /* * Attempt to remove the msdos name. */ ret = msdos_rmdir (dir, temp); if (ret && ret != -ENOENT) goto out_dput; d_delete(temp); /* OK so far ... remove the name from the EMD */ ret = umsdos_delentry (dentry->d_parent, &info, 1);#ifdef UMSDOS_PARANOIAif (ret)printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);#endif /* dput() temp if we didn't do it above */out_dput: dput(temp);out: Printk (("umsdos_rmdir %d\n", ret)); return ret;}/* * Remove a file from the directory. * * #Specification: hard link / deleting a link * When we delete a file and this file is a link, * we must subtract 1 from the nlink field of the * hidden link. * * If the count goes to 0, we delete this hidden * link too. */int UMSDOS_unlink (struct inode *dir, struct dentry *dentry){ struct dentry *temp, *link = NULL; struct inode *inode; int ret; struct umsdos_info info;Printk(("UMSDOS_unlink: entering %s/%s\n",dentry->d_parent->d_name.name, dentry->d_name.name)); ret = umsdos_nevercreat (dir, dentry, -EPERM); if (ret) goto out; ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); if (ret) goto out; umsdos_lockcreate (dir); ret = umsdos_findentry (dentry->d_parent, &info, 1); if (ret) {printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",dentry->d_parent->d_name.name, dentry->d_name.name, ret); goto out_unlock; }Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname)); /* * Note! If this is a hardlink and the names are aliased, * the short-name lookup will return the hardlink dentry. * In order to get the correct (real) inode, we just drop * the original dentry. */ if (info.entry.flags & UMSDOS_HLINK) { d_drop(dentry); } /* Do a real lookup to get the short name dentry */ temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock; /* * Resolve hardlinks now, but defer processing until later. */ if (info.entry.flags & UMSDOS_HLINK) { link = umsdos_solve_hlink(dget(temp)); } /* Delete the EMD entry */ ret = umsdos_delentry (dentry->d_parent, &info, 0); if (ret && ret != -ENOENT) { printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n", info.entry.name, ret); goto out_dput; } ret = msdos_unlink(dir, temp); if (!ret) d_delete(temp);#ifdef UMSDOS_PARANOIAif (ret)printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",temp->d_parent->d_name.name, temp->d_name.name, ret);#endif /* dput() temp if we didn't do it above */out_dput: dput(temp);out_unlock: umsdos_unlockcreate (dir); /* * Now check for deferred handling of a hardlink. */ if (!link) goto out; if (IS_ERR(link)) {printk("umsdos_unlink: failed to resolve %s/%s\n",dentry->d_parent->d_name.name, dentry->d_name.name); if (!ret) ret = PTR_ERR(link); goto out; }Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",link->d_parent->d_name.name, link->d_name.name, ret)); /* already have an error? */ if (ret) goto out_cleanup; /* make sure the link exists ... */ inode = link->d_inode; if (!inode) { printk(KERN_WARNING "umsdos_unlink: hard link not found\n"); goto out_cleanup; } /* * If this was the last linked reference, delete it now. * * N.B. Deadlock problem? We should be holding the lock * for the hardlink's parent, but another process might * be holding that lock waiting for us to finish ... */ if (inode->i_nlink <= 1) { ret = UMSDOS_unlink (link->d_parent->d_inode, link); if (ret) { printk(KERN_WARNING "umsdos_unlink: link removal failed, ret=%d\n", ret); } else d_delete(link); } else { struct iattr newattrs; inode->i_nlink--; newattrs.ia_valid = 0; ret = umsdos_notify_change_locked(link, &newattrs); if (!ret) mark_inode_dirty(link->d_inode); }out_cleanup: d_drop(link); dput(link);out: Printk (("umsdos_unlink %d\n", ret)); return ret;}/* * Rename (move) a file. */int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ int ret; ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST); if (ret) return ret; /* * If the target already exists, delete it first. */ if (new_dentry->d_inode) { dget(new_dentry); if (S_ISDIR(old_dentry->d_inode->i_mode)) ret = UMSDOS_rmdir (new_dir, new_dentry); else ret = UMSDOS_unlink (new_dir, new_dentry); if (!ret) d_drop(new_dentry); dput(new_dentry); if (ret) return ret; } ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -