int wind_dentries_2_4(struct dentry * dentry, struct vfsmount * vfsmnt, struct dentry * root, struct vfsmount * rootmnt) { struct dentry * d = dentry; struct vfsmount * v = vfsmnt; /* wind the dentries onto the stack pages */ for (;;) { /* deleted ? */ if (!IS_ROOT(d) && list_empty(&d->d_hash)) return 0; /* the root */ if (d == root && v == rootmnt) break; if (d == v->mnt_root || IS_ROOT(d)) { if (v->mnt_parent == v) break; /* cross the mount point */ d = v->mnt_mountpoint; v = v->mnt_parent; } push_dname(&d->d_name); d = d->d_parent; } return 1; }
int pohmelfs_path_length(struct pohmelfs_inode *pi) { struct dentry *d, *root, *first; int len = 1; first = d = d_find_alias(&pi->vfs_inode); if (!d) { dprintk("%s: ino: %llu, mode: %o.\n", __func__, pi->ino, pi->vfs_inode.i_mode); return -ENOENT; } read_lock(¤t->fs->lock); root = dget(current->fs->root.dentry); read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); if (!IS_ROOT(d) && d_unhashed(d)) len += UNHASHED_OBSCURE_STRING_SIZE; while (d && d != root && !IS_ROOT(d)) { len += d->d_name.len + 1; d = d->d_parent; } spin_unlock(&dcache_lock); dput(root); dput(first); return len + 1; }
int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, struct autofs_sb_info *sbi, int when) { struct dentry *dentry; int ret = -EAGAIN; if (autofs_type_trigger(sbi->type)) dentry = autofs4_expire_direct(sb, mnt, sbi, when); else dentry = autofs4_expire_indirect(sb, mnt, sbi, when); if (dentry) { struct autofs_info *ino = autofs4_dentry_ino(dentry); ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); spin_lock(&sbi->fs_lock); ino->flags &= ~AUTOFS_INF_EXPIRING; spin_lock(&dentry->d_lock); if (!ret) { if ((IS_ROOT(dentry) || (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent))) && !(dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) __managed_dentry_set_automount(dentry); } spin_unlock(&dentry->d_lock); complete_all(&ino->expire_complete); spin_unlock(&sbi->fs_lock); dput(dentry); } return ret; }
/* Note: caller must free return buffer */ char * build_path_from_dentry(struct dentry *direntry) { struct dentry *temp; int namelen = 0; char *full_path; char dirsep; if(direntry == NULL) return NULL; /* not much we can do if dentry is freed and we need to reopen the file after it was closed implicitly when the server crashed */ dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); cifs_bp_rename_retry: for (temp = direntry; !IS_ROOT(temp);) { namelen += (1 + temp->d_name.len); temp = temp->d_parent; if(temp == NULL) { cERROR(1,("corrupt dentry")); return NULL; } } full_path = kmalloc(namelen+1, GFP_KERNEL); if(full_path == NULL) return full_path; full_path[namelen] = 0; /* trailing null */ for (temp = direntry; !IS_ROOT(temp);) { namelen -= 1 + temp->d_name.len; if (namelen < 0) { break; } else { full_path[namelen] = dirsep; strncpy(full_path + namelen + 1, temp->d_name.name, temp->d_name.len); cFYI(0, (" name: %s ", full_path + namelen)); } temp = temp->d_parent; if(temp == NULL) { cERROR(1,("corrupt dentry")); kfree(full_path); return NULL; } } if (namelen != 0) { cERROR(1, ("We did not end path lookup where we expected namelen is %d", namelen)); /* presumably this is only possible if we were racing with a rename of one of the parent directories (we can not lock the dentries above us to prevent this, but retrying should be harmless) */ kfree(full_path); namelen = 0; goto cifs_bp_rename_retry; } return full_path; }
/* * if valid returns 1, otherwise 0. */ static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd) { int valid, err; unsigned int sigen; unsigned char do_udba; struct super_block *sb; struct inode *inode; err = -EINVAL; sb = dentry->d_sb; inode = dentry->d_inode; aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW); sigen = au_sigen(sb); if (au_digen(dentry) != sigen) { AuDebugOn(IS_ROOT(dentry)); if (inode) err = au_reval_dpath(dentry, sigen); if (unlikely(err)) goto out_dgrade; AuDebugOn(au_digen(dentry) != sigen); } if (inode && au_iigen(inode) != sigen) { AuDebugOn(IS_ROOT(dentry)); err = au_refresh_hinode(inode, dentry); if (unlikely(err)) goto out_dgrade; AuDebugOn(au_iigen(inode) != sigen); } di_downgrade_lock(dentry, AuLock_IR); AuDebugOn(au_digen(dentry) != sigen); AuDebugOn(inode && au_iigen(inode) != sigen); err = -EINVAL; do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); if (do_udba && inode) { aufs_bindex_t bstart = au_ibstart(inode); if (bstart >= 0 && au_test_higen(inode, au_h_iptr(inode, bstart))) goto out; } err = h_d_revalidate(dentry, inode, nd, do_udba); if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) /* both of real entry and whiteout found */ err = -EIO; goto out; out_dgrade: di_downgrade_lock(dentry, AuLock_IR); out: aufs_read_unlock(dentry, AuLock_IR); AuTraceErr(err); valid = !err; if (!valid) AuDbg("%.*s invalid\n", AuDLNPair(dentry)); return valid; }
/* * decide the branch and the parent dir where we will create a new entry. * returns new bindex or an error. * copyup the parent dir if needed. */ int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, struct au_wr_dir_args *args) { int err; aufs_bindex_t bcpup, bstart, src_bstart; const unsigned char add_entry = !!au_ftest_wrdir(args->flags, ADD_ENTRY); struct super_block *sb; struct dentry *parent; struct au_sbinfo *sbinfo; sb = dentry->d_sb; sbinfo = au_sbi(sb); parent = dget_parent(dentry); bstart = au_dbstart(dentry); bcpup = bstart; if (args->force_btgt < 0) { if (src_dentry) { src_bstart = au_dbstart(src_dentry); if (src_bstart < bstart) bcpup = src_bstart; } else if (add_entry) { err = AuWbrCreate(sbinfo, dentry, au_ftest_wrdir(args->flags, ISDIR)); bcpup = err; } if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) { if (add_entry) err = AuWbrCopyup(sbinfo, dentry); else { if (!IS_ROOT(dentry)) { di_read_lock_parent(parent, !AuLock_IR); err = AuWbrCopyup(sbinfo, dentry); di_read_unlock(parent, !AuLock_IR); } else err = AuWbrCopyup(sbinfo, dentry); } bcpup = err; if (unlikely(err < 0)) goto out; } } else { bcpup = args->force_btgt; AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode)); } AuDbg("bstart %d, bcpup %d\n", bstart, bcpup); err = bcpup; if (bcpup == bstart) goto out; /* success */ else if (bstart < bcpup) au_update_dbrange(dentry, /*do_put_zero*/1); /* copyup the new parent into the branch we process */ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart); out: dput(parent); return err; }
/* * our acceptability function. * if NOSUBTREECHECK, accept anything * if not, require that we can walk up to exp->ex_dentry * doing some checks on the 'x' bits */ static int nfsd_acceptable(void *expv, struct dentry *dentry) { struct svc_export *exp = expv; int rv; struct dentry *tdentry; struct dentry *parent; if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) return 1; tdentry = dget(dentry); while (tdentry != exp->ex_dentry && ! IS_ROOT(tdentry)) { /* make sure parents give x permission to user */ int err; parent = dget_parent(tdentry); err = permission(parent->d_inode, MAY_EXEC, NULL); if (err < 0) { dput(parent); break; } dput(tdentry); tdentry = parent; } if (tdentry != exp->ex_dentry) dprintk("nfsd_acceptable failed at %p %s\n", tdentry, tdentry->d_name.name); rv = (tdentry == exp->ex_dentry); dput(tdentry); return rv; }
/* * nfs_follow_mountpoint - handle crossing a mountpoint on the server * @dentry - dentry of mountpoint * @nd - nameidata info * * When we encounter a mountpoint on the server, we want to set up * a mountpoint on the client too, to prevent inode numbers from * colliding, and to allow "df" to work properly. * On NFSv4, we also want to allow for the fact that different * filesystems may be migrated to different servers in a failover * situation, and that different filesystems may want to use * different security flavours. */ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) { struct vfsmount *mnt; struct nfs_server *server = NFS_SERVER(dentry->d_inode); struct dentry *parent; struct nfs_fh fh; struct nfs_fattr fattr; int err; dprintk("--> nfs_follow_mountpoint()\n"); BUG_ON(IS_ROOT(dentry)); dprintk("%s: enter\n", __FUNCTION__); dput(nd->dentry); nd->dentry = dget(dentry); /* Look it up again */ parent = dget_parent(nd->dentry); err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr); dput(parent); if (err != 0) goto out_err; if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) mnt = nfs_do_refmount(nd->mnt, nd->dentry); else mnt = nfs_do_submount(nd->mnt, nd->dentry, &fh, &fattr); err = PTR_ERR(mnt); if (IS_ERR(mnt)) goto out_err; mntget(mnt); err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list); if (err < 0) { mntput(mnt); if (err == -EBUSY) goto out_follow; goto out_err; } mntput(nd->mnt); dput(nd->dentry); nd->mnt = mnt; nd->dentry = dget(mnt->mnt_root); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); out: dprintk("%s: done, returned %d\n", __FUNCTION__, err); dprintk("<-- nfs_follow_mountpoint() = %d\n", err); return ERR_PTR(err); out_err: path_release(nd); goto out; out_follow: while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) ; err = 0; goto out; }
int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, int do_include, au_dpages_test test, void *arg) { int err; err = 0; write_seqlock(&rename_lock); spin_lock(&dentry->d_lock); if (do_include && d_count(dentry) && (!test || test(dentry, arg))) err = au_dpages_append(dpages, dentry, GFP_ATOMIC); spin_unlock(&dentry->d_lock); if (unlikely(err)) goto out; /* * RCU for vfsmount is unnecessary since this is a traverse in a single * mount */ while (!IS_ROOT(dentry)) { dentry = dentry->d_parent; /* rename_lock is locked */ spin_lock(&dentry->d_lock); if (d_count(dentry) && (!test || test(dentry, arg))) err = au_dpages_append(dpages, dentry, GFP_ATOMIC); spin_unlock(&dentry->d_lock); if (unlikely(err)) break; } out: write_sequnlock(&rename_lock); return err; }
int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, int do_include, au_dpages_test test, void *arg) { int err; err = 0; spin_lock(&dcache_lock); if (do_include && (!test || test(dentry, arg))) { err = au_dpages_append(dpages, dentry, GFP_ATOMIC); if (unlikely(err)) goto out; } while (!IS_ROOT(dentry)) { dentry = dentry->d_parent; /* dcache_lock is locked */ if (!test || test(dentry, arg)) { err = au_dpages_append(dpages, dentry, GFP_ATOMIC); if (unlikely(err)) break; } } out: spin_unlock(&dcache_lock); return err; }
/* * Takes a file ptr and checks if any parent is under watch * fileptr can be obtained from an fd and from a file name too and then * passed to this function * Assumes filePtr is a valid file pointer */ unsigned long check_if_any_parent_is_watched_filp(struct file *filePtr) { unsigned long parentInodeNo = 0, tempno = 0; struct dentry *parentPtr = NULL; /* To Prevent the parent dentry loop from going in an infinite loop */ int i = 0; /* Get the dentry of the parent of the open file */ parentPtr = filePtr->f_path.dentry->d_parent; while (parentPtr != NULL && i < 20) { tempno = parentPtr->d_inode->i_ino; if (is_stat(tempno)) { parentInodeNo = tempno; break; } else if (IS_ROOT(parentPtr)) { break; } else { i++; parentPtr = parentPtr->d_parent; } } return parentInodeNo; }
/* main function for updating derived permission */ inline void update_derived_permission(struct dentry *dentry) { struct dentry *parent; struct sdcardfs_sb_info *sbi; int mask = 0; if(!dentry || !dentry->d_inode) { printk(KERN_ERR "sdcardfs: %s: invalid dentry\n", __func__); return; } /* FIXME: * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ if(IS_ROOT(dentry)) { //setup_default_pre_root_state(dentry->d_inode); } else { parent = dget_parent(dentry); if(parent) { get_derived_permission(parent, dentry); dput(parent); } } sbi = SDCARDFS_SB(dentry->d_sb); mask = sbi->options.sdfs_mask; fix_derived_permission(dentry->d_inode, mask); }
/* * nfs_d_automount - Handle crossing a mountpoint on the server * @path - The mountpoint * * When we encounter a mountpoint on the server, we want to set up * a mountpoint on the client too, to prevent inode numbers from * colliding, and to allow "df" to work properly. * On NFSv4, we also want to allow for the fact that different * filesystems may be migrated to different servers in a failover * situation, and that different filesystems may want to use * different security flavours. */ struct vfsmount *nfs_d_automount(struct path *path) { struct vfsmount *mnt; struct nfs_server *server = NFS_SERVER(d_inode(path->dentry)); struct nfs_fh *fh = NULL; struct nfs_fattr *fattr = NULL; if (IS_ROOT(path->dentry)) return ERR_PTR(-ESTALE); mnt = ERR_PTR(-ENOMEM); fh = nfs_alloc_fhandle(); fattr = nfs_alloc_fattr(); if (fh == NULL || fattr == NULL) goto out; mnt = server->nfs_client->rpc_ops->submount(server, path->dentry, fh, fattr); if (IS_ERR(mnt)) goto out; mntget(mnt); /* prevent immediate expiration */ mnt_set_expiry(mnt, &nfs_automount_list); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); out: nfs_free_fattr(fattr); nfs_free_fhandle(fh); return mnt; }
static int smb_dir_open(struct inode *dir, struct file *file) { struct dentry *dentry = file->f_path.dentry; struct smb_sb_info *server; int error = 0; VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name); /* * Directory timestamps in the core protocol aren't updated * when a file is added, so we give them a very short TTL. */ lock_kernel(); server = server_from_dentry(dentry); if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) { unsigned long age = jiffies - SMB_I(dir)->oldmtime; if (age > 2*HZ) smb_invalid_dir_cache(dir); } /* * Note: in order to allow the smbmount process to open the * mount point, we only revalidate if the connection is valid or * if the process is trying to access something other than the root. */ if (server->state == CONN_VALID || !IS_ROOT(dentry)) error = smb_revalidate_inode(dentry); unlock_kernel(); return error; }
void renew_parental_timestamps(struct dentry *direntry) { /* BB check if there is a way to get the kernel to do this or if we really need this */ do { direntry->d_time = jiffies; direntry = direntry->d_parent; } while (!IS_ROOT(direntry)); }
/* * A check for whether or not the parent directory has changed. * In the case it has, we assume that the dentries are untrustworthy * and may need to be looked up again. */ static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry) { if (IS_ROOT(dentry)) return 1; if ((NFS_FLAGS(dir) & NFS_INO_INVALID_ATTR) != 0 || nfs_attribute_timeout(dir)) return 0; return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata); }
static int is_ancestor(const struct dentry *d1, const struct dentry *d2) { do { if (d1 == d2) return 1; d1 = d1->d_parent; } while (!IS_ROOT(d1)); return 0; }
/* * A check for whether or not the parent directory has changed. * In the case it has, we assume that the dentries are untrustworthy * and may need to be looked up again. */ static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry) { if (IS_ROOT(dentry)) return 1; if (nfs_revalidate_inode(NFS_SERVER(dir), dir)) return 0; return time_after(dentry->d_time, NFS_MTIME_UPDATE(dir)); }
/* * nfs_d_automount - Handle crossing a mountpoint on the server * @path - The mountpoint * * When we encounter a mountpoint on the server, we want to set up * a mountpoint on the client too, to prevent inode numbers from * colliding, and to allow "df" to work properly. * On NFSv4, we also want to allow for the fact that different * filesystems may be migrated to different servers in a failover * situation, and that different filesystems may want to use * different security flavours. */ struct vfsmount *nfs_d_automount(struct path *path) { struct vfsmount *mnt; struct nfs_server *server = NFS_SERVER(path->dentry->d_inode); struct dentry *parent; struct nfs_fh *fh = NULL; struct nfs_fattr *fattr = NULL; int err; rpc_authflavor_t flavor = RPC_AUTH_UNIX; dprintk("--> nfs_d_automount()\n"); mnt = ERR_PTR(-ESTALE); if (IS_ROOT(path->dentry)) goto out_nofree; mnt = ERR_PTR(-ENOMEM); fh = nfs_alloc_fhandle(); fattr = nfs_alloc_fattr(); if (fh == NULL || fattr == NULL) goto out; dprintk("%s: enter\n", __func__); /* Look it up again to get its attributes */ parent = dget_parent(path->dentry); err = server->nfs_client->rpc_ops->lookup(server->client, parent->d_inode, &path->dentry->d_name, fh, fattr); if (err == -EPERM && NFS_PROTO(parent->d_inode)->secinfo != NULL) err = nfs_lookup_with_sec(server, parent, path->dentry, path, fh, fattr, &flavor); dput(parent); if (err != 0) { mnt = ERR_PTR(err); goto out; } if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) mnt = nfs_do_refmount(path->dentry); else mnt = nfs_do_submount(path->dentry, fh, fattr, flavor); if (IS_ERR(mnt)) goto out; dprintk("%s: done, success\n", __func__); mntget(mnt); /* prevent immediate expiration */ mnt_set_expiry(mnt, &nfs_automount_list); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); out: nfs_free_fattr(fattr); nfs_free_fhandle(fh); out_nofree: dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt); return mnt; }
/* common functions to regular file and dir */ struct file *hidden_open(struct dentry *dentry, aufs_bindex_t bindex, int flags) { struct dentry *hidden_dentry; struct inode *hidden_inode; struct super_block *sb; struct vfsmount *hidden_mnt; struct file *hidden_file; struct aufs_branch *br; loff_t old_size; int udba; LKTRTrace("%.*s, b%d, flags 0%o\n", DLNPair(dentry), bindex, flags); DEBUG_ON(!dentry); hidden_dentry = au_h_dptr_i(dentry, bindex); DEBUG_ON(!hidden_dentry); hidden_inode = hidden_dentry->d_inode; DEBUG_ON(!hidden_inode); sb = dentry->d_sb; udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY); if (unlikely(udba)) { // test here? } br = stobr(sb, bindex); br_get(br); /* drop flags for writing */ if (test_ro(sb, bindex, dentry->d_inode)) flags = au_file_roflags(flags); flags &= ~O_CREAT; spin_lock(&hidden_inode->i_lock); old_size = i_size_read(hidden_inode); spin_unlock(&hidden_inode->i_lock); //DbgSleep(3); dget(hidden_dentry); hidden_mnt = mntget(br->br_mnt); hidden_file = dentry_open(hidden_dentry, hidden_mnt, flags); //if (LktrCond) {fput(hidden_file); hidden_file = ERR_PTR(-1);} if (!IS_ERR(hidden_file)) { #if 0 // remove this if (/* old_size && */ (flags & O_TRUNC)) { au_direval_dec(dentry); if (!IS_ROOT(dentry)) au_direval_dec(dentry->d_parent); } #endif return hidden_file; } br_put(br); TraceErrPtr(hidden_file); return hidden_file; }
void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen) { struct dentry *parent; parent = dget_parent(dentry); AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)); AuDebugOn(IS_ROOT(dentry)); AuDebugOn(au_digen_test(parent, sigen)); dput(parent); }
struct vfsmount *nfs_d_automount(struct path *path) { struct vfsmount *mnt; struct dentry *parent; struct nfs_fh *fh = NULL; struct nfs_fattr *fattr = NULL; struct rpc_clnt *client; dprintk("--> nfs_d_automount()\n"); mnt = ERR_PTR(-ESTALE); if (IS_ROOT(path->dentry)) goto out_nofree; mnt = ERR_PTR(-ENOMEM); fh = nfs_alloc_fhandle(); fattr = nfs_alloc_fattr(); if (fh == NULL || fattr == NULL) goto out; dprintk("%s: enter\n", __func__); parent = dget_parent(path->dentry); client = nfs_lookup_mountpoint(parent->d_inode, &path->dentry->d_name, fh, fattr); dput(parent); if (IS_ERR(client)) { mnt = ERR_CAST(client); goto out; } if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) mnt = nfs_do_refmount(client, path->dentry); else mnt = nfs_do_submount(path->dentry, fh, fattr, client->cl_auth->au_flavor); rpc_shutdown_client(client); if (IS_ERR(mnt)) goto out; dprintk("%s: done, success\n", __func__); mntget(mnt); mnt_set_expiry(mnt, &nfs_automount_list); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); out: nfs_free_fattr(fattr); nfs_free_fhandle(fh); out_nofree: if (IS_ERR(mnt)) dprintk("<-- %s(): error %ld\n", __func__, PTR_ERR(mnt)); else dprintk("<-- %s() = %p\n", __func__, mnt); return mnt; }
char * build_wildcard_path_from_dentry(struct dentry *direntry) { struct dentry *temp; int namelen = 0; char *full_path; for (temp = direntry; !IS_ROOT(temp);) { namelen += (1 + temp->d_name.len); temp = temp->d_parent; } namelen += 3; /* allow for trailing null and wildcard (slash and *) */ full_path = kmalloc(namelen, GFP_KERNEL); namelen--; full_path[namelen] = 0; /* trailing null */ namelen--; full_path[namelen] = '*'; namelen--; full_path[namelen] = '\\'; for (temp = direntry; !IS_ROOT(temp);) { namelen -= 1 + temp->d_name.len; if (namelen < 0) { break; } else { full_path[namelen] = '\\'; strncpy(full_path + namelen + 1, temp->d_name.name, temp->d_name.len); } temp = temp->d_parent; } if (namelen != 0) cERROR(1, ("We did not end path lookup where we expected namelen is %d", namelen)); return full_path; }
int pohmelfs_path_length(struct pohmelfs_inode *pi) { struct dentry *d, *root, *first; int len; unsigned seq; first = d_find_alias(&pi->vfs_inode); if (!first) { ; return -ENOENT; } spin_lock(¤t->fs->lock); root = dget(current->fs->root.dentry); spin_unlock(¤t->fs->lock); rename_retry: len = 1; /* Root slash */ d = first; seq = read_seqbegin(&rename_lock); rcu_read_lock(); if (!IS_ROOT(d) && d_unhashed(d)) len += UNHASHED_OBSCURE_STRING_SIZE; /* Obscure " (deleted)" string */ while (d && d != root && !IS_ROOT(d)) { len += d->d_name.len + 1; /* Plus slash */ d = d->d_parent; } rcu_read_unlock(); if (read_seqretry(&rename_lock, seq)) goto rename_retry; dput(root); dput(first); return len + 1; /* Including zero-byte */ }
/* this routine links an IS_ROOT dentry into the dcache tree. It gains "parent" * as a parent and "name" as a name * It should possibly go in dcache.c */ int d_splice(struct dentry *target, struct dentry *parent, struct qstr *name) { struct dentry *tdentry; #ifdef NFSD_PARANOIA if (!IS_ROOT(target)) printk("nfsd: d_splice with no-root target: %s/%s\n", parent->d_name.name, name->name); if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED)) printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name); #endif tdentry = d_alloc(parent, name); if (tdentry == NULL) return -ENOMEM; d_move(target, tdentry); /* tdentry will have been made a "child" of target (the parent of target) * make it an IS_ROOT instead */ spin_lock(&dcache_lock); list_del_init(&tdentry->d_child); tdentry->d_parent = tdentry; spin_unlock(&dcache_lock); d_rehash(target); dput(tdentry); /* if parent is properly connected, then we can assert that * the children are connected, but it must be a singluar (non-forking) * branch */ if (!(parent->d_flags & DCACHE_NFSD_DISCONNECTED)) { while (target) { target->d_flags &= ~DCACHE_NFSD_DISCONNECTED; parent = target; spin_lock(&dcache_lock); if (list_empty(&parent->d_subdirs)) target = NULL; else { target = list_entry(parent->d_subdirs.next, struct dentry, d_child); #ifdef NFSD_PARANOIA /* must be only child */ if (target->d_child.next != &parent->d_subdirs || target->d_child.prev != &parent->d_subdirs) printk("nfsd: d_splice found non-singular disconnected branch: %s/%s\n", parent->d_name.name, target->d_name.name); #endif } spin_unlock(&dcache_lock); } } return 0; }
/** * Close file * * @v This File handle * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileClose(EFI_FILE_HANDLE This) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); PrintInfo(L"Close(%llx|'%s') %s\n", (UINT64) This, FileName(File), IS_ROOT(File)?L"<ROOT>":L""); /* Nothing to do it this is the root */ if (IS_ROOT(File)) return EFI_SUCCESS; if (--File->RefCount == 0) { /* Close the file if it's a regular one */ if (!File->IsDir) GrubClose(File); /* NB: basename points into File->path and does not need to be freed */ FreePool(File->path); GrubDestroyFile(File); } return EFI_SUCCESS; }
void *prlfs_get_path(struct dentry *dentry, void *buf, int *plen) { int len; char *p; DPRINTK("ENTER\n"); len = *plen; p = buf; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) if ((dentry->d_name.len > NAME_MAX) || (len < 2)) { p = ERR_PTR(-ENAMETOOLONG); goto out; } p += --len; *p = '\0'; spin_lock(&dcache_lock); while (!IS_ROOT(dentry)) { int nlen; struct dentry *parent; parent = dentry->d_parent; prefetch(parent); nlen = dentry->d_name.len; if (len < nlen + 1) { p = ERR_PTR(-ENAMETOOLONG); goto out_lock; } len -= nlen + 1; p -= nlen; memcpy(p, dentry->d_name.name, nlen); *(--p) = '/'; dentry = parent; } if (*p != '/') { *(--p) = '/'; --len; } out_lock: spin_unlock(&dcache_lock); if (!IS_ERR(p)) *plen -= len; out: #else p = dentry_path_raw(dentry, p, len); *plen = strnlen(p, PAGE_SIZE-1) + 1; #endif DPRINTK("EXIT returning %p\n", p); return p; }
int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, au_dpages_test test, void *arg) { int err; struct dentry *this_parent = root; struct list_head *next; struct super_block *sb = root->d_sb; err = 0; spin_lock(&dcache_lock); repeat: next = this_parent->d_subdirs.next; resume: if (this_parent->d_sb == sb && !IS_ROOT(this_parent) && au_di(this_parent) && (!test || test(this_parent, arg))) { err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); if (unlikely(err)) goto out; } while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); next = tmp->next; if (!list_empty(&dentry->d_subdirs)) { this_parent = dentry; goto repeat; } if (dentry->d_sb == sb && au_di(dentry) && (!test || test(dentry, arg))) { err = au_dpages_append(dpages, dentry, GFP_ATOMIC); if (unlikely(err)) goto out; } } if (this_parent != root) { next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; /* dcache_lock is locked */ goto resume; } out: spin_unlock(&dcache_lock); return err; }
/* Makes an absolute path from nameidata, and allocates a string for it */ static char* absolutePath(struct dentry *dentry, struct vfsmount *mnt) { char* path; size_t path_size = 0; char* absolute = NULL; ISystemRoot* root; char* apath; path = talpa_alloc_path(&path_size); if ( !path ) { return NULL; } root = TALPA_Portability()->systemRoot(); apath = talpa__d_path(dentry, mnt, root->directoryEntry(root->object), root->mountPoint(root->object), path, path_size); if (unlikely( apath == NULL )) { bool isDeleted = false; if ( dentry ) { isDeleted = (!IS_ROOT(dentry) && d_unhashed(dentry)); } critical("talpa__d_path failed for mnt=0x%p fstype=%s, dentry=0x%p deleted=%d", mnt, (const char *)mnt->mnt_sb->s_type->name, dentry, isDeleted); } else if (unlikely (IS_ERR(apath))) { apath = NULL; } else { absolute = talpa_alloc(strlen(apath) + 1); if ( absolute ) { strcpy(absolute, apath); } } talpa_free_path(path); return absolute; }
/*===========================================================================* * make_path * *===========================================================================*/ int make_path(char path[PATH_MAX], struct inode *ino) { /* Given an inode, construct the path identifying that inode. */ char buf[PATH_MAX], *p, *prefix; size_t len, plen, total; p = &buf[sizeof(buf) - 1]; p[0] = 0; dprintf(("%s: make_path: constructing path for inode %d\n", sffs_name, ino->i_num)); /* Get the length of the prefix, skipping any leading slashes. */ for (prefix = sffs_params->p_prefix; prefix[0] == '/'; prefix++); plen = strlen(prefix); /* Construct the path right-to-left in a temporary buffer first. */ for (total = plen; ino != NULL && !IS_ROOT(ino); ino = ino->i_parent) { len = strlen(ino->i_name); total += len + 1; p -= len + 1; if (total >= sizeof(buf)) return ENAMETOOLONG; p[0] = '/'; memcpy(p + 1, ino->i_name, len); } /* If any of the intermediate inodes has no parent, the final inode is no * longer addressable by name. */ if (ino == NULL) return ENOENT; /* Put the result in the actual buffer. We need the leading slash in the * temporary buffer only when the prefix is not empty. */ if (!prefix[0] && p[0] == '/') p++; strlcpy(path, prefix, PATH_MAX); strlcpy(&path[plen], p, PATH_MAX - plen); dprintf(("%s: make_path: resulting path is '%s'\n", sffs_name, path)); return OK; }