/* #Specification: pseudo root / rmdir /DOS * The pseudo sub-directory /DOS can't be removed! * This is done even if the pseudo root is not a Umsdos * directory anymore (very unlikely), but an accident (under * MS-DOS) is always possible. * * EPERM is returned. */ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) { int ret, empty; ret = -EPERM; if (umsdos_is_pseudodos (dir, dentry)) goto out; ret = -EBUSY; if (!d_unhashed(dentry)) goto out; ret = msdos_rmdir (dir, dentry); if (ret != -ENOTEMPTY) goto out; empty = umsdos_isempty (dentry); if (empty == 1) { struct dentry *demd; /* We have to remove the EMD file. */ demd = umsdos_get_emd_dentry(dentry); ret = PTR_ERR(demd); if (!IS_ERR(demd)) { ret = 0; if (demd->d_inode) ret = msdos_unlink (dentry->d_inode, demd); if (!ret) d_delete(demd); dput(demd); } } if (ret) goto out; /* now retry the original ... */ ret = msdos_rmdir (dir, dentry); out: return ret; }
static int UMSDOS_rrmdir ( struct inode *dir, const char *name, int len) { /* #Specification: dual mode / rmdir in a DOS directory In a DOS (not EMD in it) directory, we use a reverse strategy compared with an Umsdos directory. We assume that a subdirectory of a DOS directory is also a DOS directory. This is not always true (umssync may be used anywhere), but make sense. So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY then we check if it is a Umsdos directory. We check if it is really empty (only . .. and --linux-.--- in it). If it is true we remove the EMD and do a msdos_rmdir() again. In a Umsdos directory, we assume all subdirectory are also Umsdos directory, so we check the EMD file first. */ int ret; if (umsdos_is_pseudodos(dir,name,len)){ /* #Specification: pseudo root / rmdir /DOS The pseudo sub-directory /DOS can't be removed! This is done even if the pseudo root is not a Umsdos directory anymore (very unlikely), but an accident (under MsDOS) is always possible. EPERM is returned. */ ret = -EPERM; }else{ umsdos_lockcreate (dir); dir->i_count++; ret = msdos_rmdir (dir,name,len); if (ret == -ENOTEMPTY){ struct inode *sdir; dir->i_count++; ret = UMSDOS_rlookup (dir,name,len,&sdir); PRINTK (("rrmdir lookup %d ",ret)); if (ret == 0){ int empty; if ((empty = umsdos_isempty (sdir)) != 0){ PRINTK (("isempty %d i_count %d ",empty,sdir->i_count)); if (empty == 2){ /* Not a Umsdos directory, so the previous msdos_rmdir was not lying :-) */ ret = -ENOTEMPTY; }else if (empty == 1){ /* We have to removed the EMD file */ ret = msdos_unlink(sdir,UMSDOS_EMD_FILE ,UMSDOS_EMD_NAMELEN); sdir = NULL; if (ret == 0){ dir->i_count++; ret = msdos_rmdir (dir,name,len); } } }else{ ret = -ENOTEMPTY; } iput (sdir); } } umsdos_unlockcreate (dir); } iput (dir); return ret; }
struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo) { struct dentry *dret = NULL; struct inode *inode; int ret = -ENOENT; struct umsdos_info info; #ifdef UMSDOS_DEBUG_VERBOSE printk("umsdos_lookup_x: looking for %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); #endif umsdos_startlookup (dir); if (umsdos_is_pseudodos (dir, dentry)) { /* #Specification: pseudo root / lookup(DOS) * A lookup of DOS in the pseudo root will always succeed * and return the inode of the real root. */ Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOS\n")); inode = saved_root->d_inode; goto out_add; } ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); if (ret) { printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, ret); goto out; } ret = umsdos_findentry (dentry->d_parent, &info, 0); if (ret) { if (ret != -ENOENT) printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, ret); goto out; } Printk (("lookup %.*s pos %lu ret %d len %d ", info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len)); /* do a real lookup to get the short name ... */ dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); ret = PTR_ERR(dret); if (IS_ERR(dret)) { printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, ret); goto out; } inode = dret->d_inode; if (!inode) goto out_remove; umsdos_lookup_patch_new(dret, &info); #ifdef UMSDOS_DEBUG_VERBOSE printk("umsdos_lookup_x: found %s/%s, ino=%ld\n", dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino); #endif /* Check for a hard link */ if ((info.entry.flags & UMSDOS_HLINK) && !inode->u.umsdos_i.i_is_hlink) { dret = umsdos_solve_hlink (dret); ret = PTR_ERR(dret); if (IS_ERR(dret)) goto out; ret = -ENOENT; inode = dret->d_inode; if (!inode) { printk("umsdos_lookup_x: %s/%s negative after link\n", dret->d_parent->d_name.name, dret->d_name.name); goto out_dput; } } if (inode == pseudo_root && !nopseudo) { /* #Specification: pseudo root / dir lookup * For the same reason as readdir, a lookup in /DOS for * the pseudo root directory (linux) will fail. */ /* * This has to be allowed for resolving hard links * which are recorded independently of the pseudo-root * mode. */ printk("umsdos_lookup_x: skipping DOS/linux\n"); ret = -ENOENT; goto out_dput; } /* * We've found it OK. Now hash the dentry with the inode. */ out_add: atomic_inc(&inode->i_count); d_add (dentry, inode); dentry->d_op = &umsdos_dentry_operations; ret = 0; out_dput: if (dret && dret != dentry) d_drop(dret); dput(dret); out: umsdos_endlookup (dir); return ERR_PTR(ret); out_remove: printk(KERN_WARNING "UMSDOS: entry %s/%s out of sync, erased\n", dentry->d_parent->d_name.name, dentry->d_name.name); umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode)); ret = -ENOENT; goto out_dput; }