main() { CACHE *cache; char cmd[2]; int val, *pval; /* Print some instructions. */ printf("This program demonstrates the various cache manipulation\n"); printf("routines supplied by this package. Although this program\n"); printf("manipulates a cache of integers, data of any type and size\n"); printf("(and not just integers) are supported by the routines. See\n"); printf("the man page for more information.\n\n"); printf("We illustrate a cache with a maximum size of 3 entries.\n\n"); /* Allocate a new cache. */ cache = cache_init(MAX_ELEMENTS); print_cache(cache); /* Get some commands. */ printf("\n(e)nter new element, (c)heck for element; (q)uit: "); while (scanf("%1s", cmd) != EOF) { switch (cmd[0]) { case 'e': printf("Value (int) to enter: "); if (scanf("%d", &val)) { /* We ignore the return code here, but in practice, * we may fail (with a return code of NULL). */ cache_enter(cache, &val, sizeof(val), &pval); if (pval != NULL) { printf("%d was removed to make room.\n", *pval); } } break; case 'c': printf("Value (int) to check for: "); if (scanf("%d", &val)) { pval = (int *) cache_check(cache, (char *) &val, match); if (pval != NULL) { printf("%d found!\n", *pval); } else { printf("Not found.\n"); } } break; case 'q': cache_free(cache, CACHE_DEALLOC); exit(0); break; default: printf("'%s' not a recognized command!\n", cmd); break; } print_cache(cache); printf("\n(e)nter new element, (c)heck for element; (q)uit: "); } exit(0); }
int fuse_vnode_get(struct mount *mp, uint64_t nodeid, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, enum vtype vtyp) { struct thread *td = (cnp != NULL ? cnp->cn_thread : curthread); int err = 0; debug_printf("dvp=%p\n", dvp); err = fuse_vnode_alloc(mp, td, nodeid, vtyp, vpp); if (err) { return err; } if (dvp != NULL) { MPASS((cnp->cn_flags & ISDOTDOT) == 0); MPASS(!(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')); fuse_vnode_setparent(*vpp, dvp); } if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0) { ASSERT_VOP_LOCKED(*vpp, "fuse_vnode_get"); ASSERT_VOP_LOCKED(dvp, "fuse_vnode_get"); cache_enter(dvp, *vpp, cnp); } VTOFUD(*vpp)->nlookup++; return 0; }
static void safe_event_disassemble(void * x) { DisassembleCmdArgs * args = (DisassembleCmdArgs *)x; if (!is_channel_closed(args->c)) { cache_enter(disassemble_cache_client, args->c, args, sizeof(DisassembleCmdArgs)); } channel_unlock(args->c); loc_free(args); }
static void command_list(char * token, Channel * c) { CommandListArgs args; json_read_string(&c->inp, args.id, sizeof(args.id)); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_list_cache_client, c, &args, sizeof(args)); }
static void command_getm(char * token, Channel * c) { GetmArgs args; args.locs = read_location_list(&c->inp, &args.locs_cnt); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_getm_cache_client, c, &args, sizeof(args)); }
static void command_get_location_info(char * token, Channel * c) { CommandGetLocationInfo args; json_read_string(&c->inp, args.id, sizeof(args.id)); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_get_location_info_cache_client, c, &args, sizeof(args)); }
static void command_get_capabilities(char * token, Channel * c) { GetCapabilitiesCmdArgs args; json_read_string(&c->inp, args.id, sizeof(args.id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_get_capabilities_cache_client, c, &args, sizeof(args)); }
static void command_setm(char * token, Channel * c) { SetmArgs args; args.locs = read_location_list(&c->inp, &args.locs_cnt); json_test_char(&c->inp, MARKER_EOA); args.data = (uint8_t *)json_read_alloc_binary(&c->inp, &args.data_len); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_setm_cache_client, c, &args, sizeof(args)); }
static void command_set(char * token, Channel * c) { SetArgs args; json_read_string(&c->inp, args.id, sizeof(args.id)); json_test_char(&c->inp, MARKER_EOA); args.data = (uint8_t *)json_read_alloc_binary(&c->inp, &args.data_len); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_set_cache_client, c, &args, sizeof(args)); }
static void command_find_by_addr(char * token, Channel * c) { CommandFindByAddrArgs args; json_read_string(&c->inp, args.id, sizeof(args.id)); json_test_char(&c->inp, MARKER_EOA); args.addr = (ContextAddress)json_read_uint64(&c->inp); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_find_by_addr_cache_client, c, &args, sizeof(args)); }
static void command_get_sym_file_info(char * token, Channel * c) { CommandSymFileInfo args; json_read_string(&c->inp, args.id, sizeof(args.id)); json_test_char(&c->inp, MARKER_EOA); args.addr = (ContextAddress)json_read_uint64(&c->inp); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_get_sym_file_info_cache_client, c, &args, sizeof(args)); }
static void command_get_array_type(char * token, Channel * c) { CommandGetArrayTypeArgs args; json_read_string(&c->inp, args.id, sizeof(args.id)); json_test_char(&c->inp, MARKER_EOA); args.length = json_read_uint64(&c->inp); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_get_array_type_cache_client, c, &args, sizeof(args)); }
HEADER *headersDepth(const char *t, time_t time, int depth) { HEADER hdr, *h = &hdr; LIST *l; const char* cachekey=t; /* D support (doesn't affect C(++), because a source file is never included) */ if(depth == 0) { cachekey=malloc(strlen(t)+sizeof("source:")); strcpy((char*)cachekey,"source:"); strcpy((char*)cachekey+7,t); } if (!headerhash) headerhash = hashinit(sizeof(HEADER), "headers"); h->key = cachekey; h->includes = 0; h->time = time; h->headers = 0; h->newest = 0; if (!hashenter(headerhash, (HASHDATA **)&h)) return h; h->key = newstr(t); #ifdef USE_CACHE if (!cache_check(cachekey, time, &h->includes)) { h->includes = headers1(t, depth); cache_enter(cachekey, time, h->includes); } #else h->includes = headers1(t, depth); #endif if(depth == 0) free((char*)cachekey); l = h->includes; while (l) { const char *t2 = search(t, l->string, &time); if (time) h->headers = headerentry(h->headers, headersDepth(t2, time, depth+1)); l = list_next(l); } return h; }
static void command_find_by_name_args(char * token, Channel * c, CommandFindByNameArgs * args) { args->ip = 0; json_read_string(&c->inp, args->id, sizeof(args->id)); json_test_char(&c->inp, MARKER_EOA); if (json_peek(&c->inp) != '"' && json_peek(&c->inp) != 'n') { args->ip = (ContextAddress)json_read_uint64(&c->inp); json_test_char(&c->inp, MARKER_EOA); } args->name = json_read_alloc_string(&c->inp); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args->token, token, sizeof(args->token)); cache_enter(command_find_by_name_cache_client, c, args, sizeof(CommandFindByNameArgs)); }
static void command_reset(char * token, Channel * c) { CommandResetArgs args; memset(&args, 0, sizeof(args)); json_read_string(&c->inp, args.id, sizeof(args.id)); json_test_char(&c->inp, MARKER_EOA); json_read_string(&c->inp, args.type, sizeof(args.type)); json_test_char(&c->inp, MARKER_EOA); json_read_struct(&c->inp, read_reset_params, &args.params); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_reset_cache_client, c, &args, sizeof(args)); }
static int tmpfs_create(struct vop_create_args *v) { struct vnode *dvp = v->a_dvp; struct vnode **vpp = v->a_vpp; struct componentname *cnp = v->a_cnp; struct vattr *vap = v->a_vap; int error; MPASS(vap->va_type == VREG || vap->va_type == VSOCK); error = tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); if (error == 0 && (cnp->cn_flags & MAKEENTRY) != 0) cache_enter(dvp, *vpp, cnp); return (error); }
static void command_find_in_scope(char * token, Channel * c) { CommandFindInScopeArgs args; json_read_string(&c->inp, args.frame_id, sizeof(args.frame_id)); json_test_char(&c->inp, MARKER_EOA); args.ip = (ContextAddress)json_read_uint64(&c->inp); json_test_char(&c->inp, MARKER_EOA); json_read_string(&c->inp, args.scope_id, sizeof(args.scope_id)); json_test_char(&c->inp, MARKER_EOA); args.name = json_read_alloc_string(&c->inp); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_find_in_scope_cache_client, c, &args, sizeof(args)); }
static void command_disassemble(char * token, Channel * c) { DisassembleCmdArgs args; memset(&args, 0, sizeof(args)); json_read_string(&c->inp, args.id, sizeof(args.id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); args.addr = (ContextAddress)json_read_uint64(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); args.size = (ContextAddress)json_read_uint64(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); json_read_struct(&c->inp, read_disassembly_params, &args); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); strlcpy(args.token, token, sizeof(args.token)); cache_enter(disassemble_cache_client, c, &args, sizeof(DisassembleCmdArgs)); }
/* * smbfs_create call * Create a regular file. On entry the directory to contain the file being * created is locked. We must release before we return. */ int smbfs_create(void *v) { struct vop_create_v3_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; } */ *ap = v; struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct componentname *cnp = ap->a_cnp; struct smbnode *dnp = VTOSMB(dvp); struct smbfattr fattr; struct smb_cred scred; const char *name = cnp->cn_nameptr; int nmlen = cnp->cn_namelen; int error = EINVAL; if (vap->va_type != VREG) goto out; smb_makescred(&scred, curlwp, cnp->cn_cred); error = smbfs_smb_create(dnp, name, nmlen, &scred); if (error) goto out; error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); if (error) goto out; error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, ap->a_vpp); if (error) goto out; VOP_UNLOCK(*ap->a_vpp); cache_enter(dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); out: VN_KNOTE(dvp, NOTE_WRITE); return (error); }
void dnlc_update(struct vnode *vp, char *name, struct vnode *tp) { #if 0 // If tp is NULL, it is a negative-cache entry struct componentname cn; // OSX panics if you give empty(non-NULL) name if (!name || !*name || !strlen(name)) return; bzero(&cn, sizeof (cn)); cn.cn_nameiop = CREATE; cn.cn_flags = ISLASTCN; cn.cn_nameptr = (char *)name; cn.cn_namelen = strlen(name); cache_enter(vp, tp==DNLC_NO_VNODE?NULL:tp, &cn); #endif return; }
int fuse_vnode_get(struct mount *mp, struct fuse_entry_out *feo, uint64_t nodeid, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, enum vtype vtyp) { struct thread *td = (cnp != NULL ? cnp->cn_thread : curthread); int err = 0; err = fuse_vnode_alloc(mp, td, nodeid, vtyp, vpp); if (err) { return err; } if (dvp != NULL) { MPASS((cnp->cn_flags & ISDOTDOT) == 0); MPASS(!(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')); fuse_vnode_setparent(*vpp, dvp); } if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0 && feo != NULL && (feo->entry_valid != 0 || feo->entry_valid_nsec != 0)) { ASSERT_VOP_LOCKED(*vpp, "fuse_vnode_get"); ASSERT_VOP_LOCKED(dvp, "fuse_vnode_get"); cache_enter(dvp, *vpp, cnp); } /* * In userland, libfuse uses cached lookups for dot and dotdot entries, * thus it does not really bump the nlookup counter for forget. * Follow the same semantic and avoid tu bump it in order to keep * nlookup counters consistent. */ if (cnp == NULL || ((cnp->cn_flags & ISDOTDOT) == 0 && (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.'))) VTOFUD(*vpp)->nlookup++; return 0; }
void fuse_vncache_enter(vnode_t dvp, vnode_t vp, struct componentname *cnp) { #if FUSE_TRACE_VNCACHE IOLog("osxfuse: cache enter dvp=%p, vp=%p, %s\n", dvp, vp, cnp->cn_nameptr); #endif #if M_OSXFUSE_ENABLE_BIG_LOCK struct fuse_data *data = fuse_get_mpdata(vnode_mount(dvp)); bool biglock_locked = fuse_biglock_have_lock(data->biglock); if (biglock_locked) { fuse_biglock_unlock(data->biglock); } #endif /* M_OSXFUSE_ENABLE_BIG_LOCK */ cache_enter(dvp, vp, cnp); #if M_OSXFUSE_ENABLE_BIG_LOCK if (biglock_locked) { fuse_biglock_lock(data->biglock); } #endif }
void load_name_cache(kvm_t *kd) { struct namecache _ncp, *ncp, *oncp; struct nchashhead _ncpp, *ncpp; u_long lnchash; size_t nchash, i; LIST_INIT(&lcache); _KDEREF(kd, nchash_addr, &lnchash, sizeof(lnchash)); nchash = (size_t)lnchash + 1; nchashtbl = ecalloc(nchash, sizeof(*nchashtbl)); _KDEREF(kd, nchashtbl_addr, nchashtbl, sizeof(*nchashtbl) * nchash); ncpp = &_ncpp; for (i = 0; i < nchash; i++) { ncpp = &nchashtbl[i]; oncp = NULL; LIST_FOREACH(ncp, ncpp, nc_hash) { if (ncp == oncp || ncp == (void*)0xdeadbeef) break; oncp = ncp; _KDEREF(kd, (u_long)ncp, &_ncp, sizeof(*ncp)); ncp = &_ncp; if (ncp->nc_nlen > 0) { if (ncp->nc_nlen > 2 || ncp->nc_name[0] != '.' || (ncp->nc_name[1] != '.' && ncp->nc_nlen != 1)) cache_enter(i, ncp); } } } }
/* * Convert a component of a pathname into a pointer to a locked inode. * This is a very central and rather complicated routine. * If the file system is not maintained in a strict tree hierarchy, * this can result in a deadlock situation (see comments in code below). * * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending * on whether the name is to be looked up, created, renamed, or deleted. * When CREATE, RENAME, or DELETE is specified, information usable in * creating, renaming, or deleting a directory entry may be calculated. * If flag has LOCKPARENT or'ed into it and the target of the pathname * exists, lookup returns both the target and its parent directory locked. * When creating or renaming and LOCKPARENT is specified, the target may * not be ".". When deleting and LOCKPARENT is specified, the target may * be "."., but the caller must check to ensure it does an vrele and vput * instead of two vputs. * * Overall outline of ufs_lookup: * * check accessibility of directory * look for name in cache, if found, then if at end of path * and deleting or creating, drop it, else return name * search for name in directory, to found or notfound * notfound: * if creating, return locked directory, leaving info on available slots * else return error * found: * if at end of path and deleting, return information to allow delete * if at end of path and rewriting (RENAME and LOCKPARENT), lock target * inode and return info to allow rewrite * if not at end, add name to cache; if at end and neither creating * nor deleting, add name to cache */ int ufs_lookup(void *v) { struct vop_lookup_args *ap = v; struct vnode *vdp; /* vnode for directory being searched */ struct inode *dp; /* inode for directory being searched */ struct buf *bp; /* a buffer of directory entries */ struct direct *ep; /* the current directory entry */ int entryoffsetinblock; /* offset of ep in bp's buffer */ enum {NONE, COMPACT, FOUND} slotstatus; doff_t slotoffset; /* offset of area with free space */ int slotsize; /* size of area at slotoffset */ int slotfreespace; /* amount of space free in slot */ int slotneeded; /* size of the entry we're seeking */ int numdirpasses; /* strategy for directory search */ doff_t endsearch; /* offset to end directory search */ doff_t prevoff; /* prev entry dp->i_offset */ struct vnode *pdp; /* saved dp during symlink work */ struct vnode *tdp; /* returned by VFS_VGET */ doff_t enduseful; /* pointer past last used dir slot */ u_long bmask; /* block offset mask */ int lockparent; /* 1 => lockparent flag is set */ int wantparent; /* 1 => wantparent or lockparent flag */ int namlen, error; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; struct ucred *cred = cnp->cn_cred; int flags; int nameiop = cnp->cn_nameiop; struct proc *p = cnp->cn_proc; cnp->cn_flags &= ~PDIRUNLOCK; flags = cnp->cn_flags; bp = NULL; slotoffset = -1; *vpp = NULL; vdp = ap->a_dvp; dp = VTOI(vdp); lockparent = flags & LOCKPARENT; wantparent = flags & (LOCKPARENT|WANTPARENT); /* * Check accessiblity of directory. */ if ((DIP(dp, mode) & IFMT) != IFDIR) return (ENOTDIR); if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0) return (error); if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); /* * We now have a segment name to search for, and a directory to search. * * Before tediously performing a linear scan of the directory, * check the name cache to see if the directory/name pair * we are looking for is known already. */ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) return (error); /* * Suppress search for slots unless creating * file and at end of pathname, in which case * we watch for a place to put the new file in * case it doesn't already exist. */ slotstatus = FOUND; slotfreespace = slotsize = slotneeded = 0; if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) { slotstatus = NONE; slotneeded = (sizeof(struct direct) - MAXNAMLEN + cnp->cn_namelen + 3) &~ 3; } /* * If there is cached information on a previous search of * this directory, pick up where we last left off. * We cache only lookups as these are the most common * and have the greatest payoff. Caching CREATE has little * benefit as it usually must search the entire directory * to determine that the entry does not exist. Caching the * location of the last DELETE or RENAME has not reduced * profiling time and hence has been removed in the interest * of simplicity. */ bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; #ifdef UFS_DIRHASH /* * Use dirhash for fast operations on large directories. The logic * to determine whether to hash the directory is contained within * ufsdirhash_build(); a zero return means that it decided to hash * this directory and it successfully built up the hash table. */ if (ufsdirhash_build(dp) == 0) { /* Look for a free slot if needed. */ enduseful = DIP(dp, size); if (slotstatus != FOUND) { slotoffset = ufsdirhash_findfree(dp, slotneeded, &slotsize); if (slotoffset >= 0) { slotstatus = COMPACT; enduseful = ufsdirhash_enduseful(dp); if (enduseful < 0) enduseful = DIP(dp, size); } } /* Look up the component. */ numdirpasses = 1; entryoffsetinblock = 0; /* silence compiler warning */ switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, &dp->i_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) { case 0: ep = (struct direct *)((char *)bp->b_data + (dp->i_offset & bmask)); goto foundentry; case ENOENT: #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ dp->i_offset = roundup2(DIP(dp, size), DIRBLKSIZ); goto notfound; default: /* Something failed; just do a linear search. */ break; } } #endif /* UFS_DIRHASH */ if (nameiop != LOOKUP || dp->i_diroff == 0 || dp->i_diroff >= DIP(dp, size)) { entryoffsetinblock = 0; dp->i_offset = 0; numdirpasses = 1; } else { dp->i_offset = dp->i_diroff; if ((entryoffsetinblock = dp->i_offset & bmask) && (error = UFS_BUFATOFF(dp, (off_t)dp->i_offset, NULL, &bp))) return (error); numdirpasses = 2; nchstats.ncs_2passes++; } prevoff = dp->i_offset; endsearch = roundup(DIP(dp, size), DIRBLKSIZ); enduseful = 0; searchloop: while (dp->i_offset < endsearch) { /* * If necessary, get the next directory block. */ if ((dp->i_offset & bmask) == 0) { if (bp != NULL) brelse(bp); error = UFS_BUFATOFF(dp, (off_t)dp->i_offset, NULL, &bp); if (error) return (error); entryoffsetinblock = 0; } /* * If still looking for a slot, and at a DIRBLKSIZE * boundary, have to start looking for free space again. */ if (slotstatus == NONE && (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { slotoffset = -1; slotfreespace = 0; } /* * Get pointer to next entry. * Full validation checks are slow, so we only check * enough to insure forward progress through the * directory. Complete checks can be run by patching * "dirchk" to be true. */ ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock); if (ep->d_reclen == 0 || (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) { int i; ufs_dirbad(dp, dp->i_offset, "mangled entry"); i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); dp->i_offset += i; entryoffsetinblock += i; continue; } /* * If an appropriate sized slot has not yet been found, * check to see if one is available. Also accumulate space * in the current block so that we can determine if * compaction is viable. */ if (slotstatus != FOUND) { int size = ep->d_reclen; if (ep->d_ino != 0) size -= DIRSIZ(FSFMT(vdp), ep); if (size > 0) { if (size >= slotneeded) { slotstatus = FOUND; slotoffset = dp->i_offset; slotsize = ep->d_reclen; } else if (slotstatus == NONE) { slotfreespace += size; if (slotoffset == -1) slotoffset = dp->i_offset; if (slotfreespace >= slotneeded) { slotstatus = COMPACT; slotsize = dp->i_offset + ep->d_reclen - slotoffset; } } } } /* * Check for a name match. */ if (ep->d_ino) { # if (BYTE_ORDER == LITTLE_ENDIAN) if (vdp->v_mount->mnt_maxsymlinklen > 0) namlen = ep->d_namlen; else namlen = ep->d_type; # else namlen = ep->d_namlen; # endif if (namlen == cnp->cn_namelen && !memcmp(cnp->cn_nameptr, ep->d_name, namlen)) { #ifdef UFS_DIRHASH foundentry: #endif /* * Save directory entry's inode number and * reclen in ndp->ni_ufs area, and release * directory buffer. */ dp->i_ino = ep->d_ino; dp->i_reclen = ep->d_reclen; goto found; } } prevoff = dp->i_offset; dp->i_offset += ep->d_reclen; entryoffsetinblock += ep->d_reclen; if (ep->d_ino) enduseful = dp->i_offset; } #ifdef UFS_DIRHASH notfound: #endif /* * If we started in the middle of the directory and failed * to find our target, we must check the beginning as well. */ if (numdirpasses == 2) { numdirpasses--; dp->i_offset = 0; endsearch = dp->i_diroff; goto searchloop; } if (bp != NULL) brelse(bp); /* * If creating, and at end of pathname and current * directory has not been removed, then can consider * allowing file to be created. */ if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN) && dp->i_effnlink != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. */ error = VOP_ACCESS(vdp, VWRITE, cred); if (error) return (error); /* * Return an indication of where the new directory * entry should be put. If we didn't find a slot, * then set dp->i_count to 0 indicating * that the new slot belongs at the end of the * directory. If we found a slot, then the new entry * can be put in the range from dp->i_offset to * dp->i_offset + dp->i_count. */ if (slotstatus == NONE) { dp->i_offset = roundup(DIP(dp, size), DIRBLKSIZ); dp->i_count = 0; enduseful = dp->i_offset; } else if (nameiop == DELETE) { dp->i_offset = slotoffset; if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) dp->i_count = 0; else dp->i_count = dp->i_offset - prevoff; } else { dp->i_offset = slotoffset; dp->i_count = slotsize; if (enduseful < slotoffset + slotsize) enduseful = slotoffset + slotsize; } dp->i_endoff = roundup(enduseful, DIRBLKSIZ); /* * We return with the directory locked, so that * the parameters we set up above will still be * valid if we actually decide to do a direnter(). * We return ni_vp == NULL to indicate that the entry * does not currently exist; we leave a pointer to * the (locked) directory inode in ndp->ni_dvp. * The pathname buffer is saved so that the name * can be obtained later. * * NB - if the directory is unlocked, then this * information cannot be used. */ cnp->cn_flags |= SAVENAME; if (!lockparent) { VOP_UNLOCK(vdp, 0); cnp->cn_flags |= PDIRUNLOCK; } return (EJUSTRETURN); } /* * Insert name into cache (as non-existent) if appropriate. */ if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) cache_enter(vdp, *vpp, cnp); return (ENOENT); found: if (numdirpasses == 2) nchstats.ncs_pass2++; /* * Check that directory length properly reflects presence * of this entry. */ if (dp->i_offset + DIRSIZ(FSFMT(vdp), ep) > DIP(dp, size)) { ufs_dirbad(dp, dp->i_offset, "i_ffs_size too small"); DIP_ASSIGN(dp, size, dp->i_offset + DIRSIZ(FSFMT(vdp), ep)); dp->i_flag |= IN_CHANGE | IN_UPDATE; UFS_WAPBL_UPDATE(dp, MNT_WAIT); } brelse(bp); /* * Found component in pathname. * If the final component of path name, save information * in the cache as to where the entry was found. */ if ((flags & ISLASTCN) && nameiop == LOOKUP) dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1); /* * If deleting, and at end of pathname, return * parameters which can be used to remove file. * If the wantparent flag isn't set, we return only * the directory (in ndp->ni_dvp), otherwise we go * on and lock the inode, being careful with ".". */ if (nameiop == DELETE && (flags & ISLASTCN)) { /* * Write access to directory required to delete files. */ error = VOP_ACCESS(vdp, VWRITE, cred); if (error) return (error); /* * Return pointer to current entry in dp->i_offset, * and distance past previous entry (if there * is a previous entry in this block) in dp->i_count. * Save directory inode pointer in ndp->ni_dvp for dirremove(). */ if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) dp->i_count = 0; else dp->i_count = dp->i_offset - prevoff; if (dp->i_number == dp->i_ino) { vref(vdp); *vpp = vdp; return (0); } error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) return (error); /* * If directory is "sticky", then user must own * the directory, or the file in it, else she * may not delete it (unless she's root). This * implements append-only directories. */ if ((DIP(dp, mode) & ISVTX) && cred->cr_uid != 0 && cred->cr_uid != DIP(dp, uid) && DIP(VTOI(tdp), uid) != cred->cr_uid) { vput(tdp); return (EPERM); } *vpp = tdp; if (!lockparent) { VOP_UNLOCK(vdp, 0); cnp->cn_flags |= PDIRUNLOCK; } return (0); } /* * If rewriting (RENAME), return the inode and the * information required to rewrite the present directory * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { error = VOP_ACCESS(vdp, VWRITE, cred); if (error) return (error); /* * Careful about locking second inode. * This can only occur if the target is ".". */ if (dp->i_number == dp->i_ino) return (EISDIR); error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) return (error); *vpp = tdp; cnp->cn_flags |= SAVENAME; if (!lockparent) { VOP_UNLOCK(vdp, 0); cnp->cn_flags |= PDIRUNLOCK; } return (0); } /* * Step through the translation in the name. We do not `vput' the * directory because we may need it again if a symbolic link * is relative to the current directory. Instead we save it * unlocked as "pdp". We must get the target inode before unlocking * the directory to insure that the inode will not be removed * before we get it. We prevent deadlock by always fetching * inodes from the root, moving down the directory tree. Thus * when following backward pointers ".." we must unlock the * parent directory before getting the requested directory. * There is a potential race condition here if both the current * and parent directories are removed before the VFS_VGET for the * inode associated with ".." returns. We hope that this occurs * infrequently since we cannot avoid this race condition without * implementing a sophisticated deadlock detection algorithm. * Note also that this simple deadlock detection scheme will not * work if the file system has any hard links other than ".." * that point backwards in the directory structure. */ pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0); /* race to get the inode */ cnp->cn_flags |= PDIRUNLOCK; error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) { if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) cnp->cn_flags &= ~PDIRUNLOCK; return (error); } if (lockparent && (flags & ISLASTCN)) { if ((error = vn_lock(pdp, LK_EXCLUSIVE, p))) { vput(tdp); return (error); } cnp->cn_flags &= ~PDIRUNLOCK; } *vpp = tdp; } else if (dp->i_number == dp->i_ino) { vref(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) return (error); if (!lockparent || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0); cnp->cn_flags |= PDIRUNLOCK; } *vpp = tdp; } /* * Insert name into cache if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); return (0); }
static int nwfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) { struct nwmount *nmp = VTONWFS(vp); int error, count, i; struct dirent dp; struct nwnode *np = VTONW(vp); struct nw_entry_info fattr; struct vnode *newvp; struct componentname cn; ncpfid fid; np = VTONW(vp); NCPVNDEBUG("dirname='%s'\n",np->n_name); if (uio->uio_resid < DE_SIZE || (uio->uio_offset < 0)) return (EINVAL); error = 0; count = 0; i = uio->uio_offset / DE_SIZE; /* offset in directory */ if (i == 0) { error = ncp_initsearch(vp, uio->uio_td, cred); if (error) { NCPVNDEBUG("cannot initialize search, error=%d",error); return( error ); } } for (; uio->uio_resid >= DE_SIZE; i++) { bzero((char *) &dp, DE_SIZE); dp.d_reclen = DE_SIZE; switch (i) { case 0: /* `.' */ case 1: /* `..' */ dp.d_fileno = (i == 0) ? np->n_fid.f_id : np->n_parent.f_id; if (!dp.d_fileno) dp.d_fileno = NWFS_ROOT_INO; dp.d_namlen = i + 1; dp.d_name[0] = '.'; dp.d_name[1] = '.'; dp.d_name[i + 1] = '\0'; dp.d_type = DT_DIR; break; default: error = ncp_search_for_file_or_subdir(nmp, &np->n_seq, &fattr, uio->uio_td, cred); if (error && error < 0x80) break; dp.d_fileno = fattr.dirEntNum; dp.d_type = (fattr.attributes & aDIR) ? DT_DIR : DT_REG; dp.d_namlen = fattr.nameLen; bcopy(fattr.entryName, dp.d_name, dp.d_namlen); dp.d_name[dp.d_namlen] = '\0'; #if 0 if (error && eofflag) { /* *eofflag = 1;*/ break; } #endif break; } if (nwfs_fastlookup && !error && i > 1) { fid.f_id = fattr.dirEntNum; fid.f_parent = np->n_fid.f_id; error = nwfs_nget(vp->v_mount, fid, &fattr, vp, &newvp); if (!error) { VTONW(newvp)->n_ctime = VTONW(newvp)->n_vattr.va_ctime.tv_sec; cn.cn_nameptr = dp.d_name; cn.cn_namelen = dp.d_namlen; cache_enter(vp, newvp, &cn); vput(newvp); } else error = 0; } if (error >= 0x80) { error = 0; break; } if ((error = uiomove(&dp, DE_SIZE, uio))) break; } uio->uio_offset = i * DE_SIZE; return (error); }
static int vboxvfs_vnode_lookup(struct vnop_lookup_args *args) { int rc; vnode_t vnode; vboxvfs_vnode_t *pVnodeData; PDEBUG("Looking up for vnode..."); AssertReturn(args, EINVAL); AssertReturn(args->a_dvp, EINVAL); AssertReturn(vnode_isdir(args->a_dvp), EINVAL); AssertReturn(args->a_cnp, EINVAL); AssertReturn(args->a_cnp->cn_nameptr, EINVAL); AssertReturn(args->a_vpp, EINVAL); pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(args->a_dvp); AssertReturn(pVnodeData, EINVAL); AssertReturn(pVnodeData->pLock, EINVAL); /* todo: take care about args->a_cnp->cn_nameiop */ if (args->a_cnp->cn_nameiop == LOOKUP) PDEBUG("LOOKUP"); else if (args->a_cnp->cn_nameiop == CREATE) PDEBUG("CREATE"); else if (args->a_cnp->cn_nameiop == RENAME) PDEBUG("RENAME"); else if (args->a_cnp->cn_nameiop == DELETE) PDEBUG("DELETE"); else PDEBUG("Unknown cn_nameiop: 0x%X", (int)args->a_cnp->cn_nameiop); lck_rw_lock_exclusive(pVnodeData->pLock); /* Take care about '.' and '..' entries */ if (vboxvfs_vnode_lookup_dot_handler(args, &vnode) == 0) { vnode_get(vnode); *args->a_vpp = vnode; lck_rw_unlock_exclusive(pVnodeData->pLock); return 0; } /* Look into VFS cache and attempt to find previously allocated vnode there. */ rc = cache_lookup(args->a_dvp, &vnode, args->a_cnp); if (rc == -1) /* Record found */ { PDEBUG("Found record in VFS cache"); /* Check if VFS object still exist on a host side */ if (vboxvfs_exist_internal(vnode)) { /* Prepare & return cached vnode */ vnode_get(vnode); *args->a_vpp = vnode; rc = 0; } else { /* If vnode exist in guets VFS cache, but not exist on a host -- just forget it. */ cache_purge(vnode); /* todo: free vnode data here */ rc = ENOENT; } } else { PDEBUG("cache_lookup() returned %d, create new VFS vnode", rc); rc = vboxvfs_vnode_lookup_instantinate_vnode(args->a_dvp, args->a_cnp->cn_nameptr, &vnode); if (rc == 0) { cache_enter(args->a_dvp, vnode, args->a_cnp); *args->a_vpp = vnode; } else { rc = ENOENT; } } lck_rw_unlock_exclusive(pVnodeData->pLock); return rc; }
/* * When we search a directory the blocks containing directory entries are * read and examined. The directory entries contain information that would * normally be in the inode of a unix filesystem. This means that some of * a directory's contents may also be in memory resident denodes (sort of * an inode). This can cause problems if we are searching while some other * process is modifying a directory. To prevent one process from accessing * incompletely modified directory information we depend upon being the * sole owner of a directory block. bread/brelse provide this service. * This being the case, when a process modifies a directory it must first * acquire the disk block that contains the directory entry to be modified. * Then update the disk block and the denode, and then write the disk block * out to disk. This way disk blocks containing directory entries and in * memory denode's will be in synch. */ int msdosfs_lookup(void *v) { struct vop_lookup_v2_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; } */ *ap = v; struct vnode *vdp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; daddr_t bn; int error; int slotcount; int slotoffset = 0; int frcn; u_long cluster; int blkoff; int diroff; int blsize; int isadir; /* ~0 if found direntry is a directory */ u_long scn; /* starting cluster number */ struct vnode *pdp; struct denode *dp; struct denode *tdp; struct msdosfsmount *pmp; struct buf *bp = 0; struct direntry *dep; u_char dosfilename[12]; int flags; int nameiop = cnp->cn_nameiop; int wincnt = 1; int chksum = -1, chksum_ok; int olddos = 1; flags = cnp->cn_flags; #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): looking for %.*s\n", (int)cnp->cn_namelen, cnp->cn_nameptr); #endif dp = VTODE(vdp); pmp = dp->de_pmp; *vpp = NULL; #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n", vdp, dp, dp->de_Attributes); #endif /* * Check accessiblity of directory. */ if ((error = VOP_ACCESS(vdp, VEXEC, cnp->cn_cred)) != 0) return (error); if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); /* * We now have a segment name to search for, and a directory to search. * * Before tediously performing a linear scan of the directory, * check the name cache to see if the directory/name pair * we are looking for is known already. */ if (cache_lookup(vdp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) { return *vpp == NULLVP ? ENOENT: 0; } /* * If they are going after the . or .. entry in the root directory, * they won't find it. DOS filesystems don't have them in the root * directory. So, we fake it. deget() is in on this scam too. */ if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' && (cnp->cn_namelen == 1 || (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { isadir = ATTR_DIRECTORY; scn = MSDOSFSROOT; #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): looking for . or .. in root directory\n"); #endif cluster = MSDOSFSROOT; blkoff = MSDOSFSROOT_OFS; goto foundroot; } switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, cnp->cn_namelen, 0)) { case 0: return (EINVAL); case 1: break; case 2: wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, cnp->cn_namelen) + 1; break; case 3: olddos = 0; wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, cnp->cn_namelen) + 1; break; } if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) wincnt = 1; /* * Suppress search for slots unless creating * file and at end of pathname, in which case * we watch for a place to put the new file in * case it doesn't already exist. */ slotcount = wincnt; if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) slotcount = 0; #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): dos filename: %s\n", dosfilename); #endif /* * Search the directory pointed at by vdp for the name pointed at * by cnp->cn_nameptr. */ tdp = NULL; /* * The outer loop ranges over the clusters that make up the * directory. Note that the root directory is different from all * other directories. It has a fixed number of blocks that are not * part of the pool of allocatable clusters. So, we treat it a * little differently. The root directory starts at "cluster" 0. */ diroff = 0; for (frcn = 0; diroff < dp->de_FileSize; frcn++) { if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) { if (error == E2BIG) break; return (error); } error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 0, &bp); if (error) { return (error); } for (blkoff = 0; blkoff < blsize; blkoff += sizeof(struct direntry), diroff += sizeof(struct direntry)) { dep = (struct direntry *)((char *)bp->b_data + blkoff); /* * If the slot is empty and we are still looking * for an empty then remember this one. If the * slot is not empty then check to see if it * matches what we are looking for. If the slot * has never been filled with anything, then the * remainder of the directory has never been used, * so there is no point in searching it. */ if (dep->deName[0] == SLOT_EMPTY || dep->deName[0] == SLOT_DELETED) { /* * Drop memory of previous long matches */ chksum = -1; if (slotcount < wincnt) { slotcount++; slotoffset = diroff; } if (dep->deName[0] == SLOT_EMPTY) { brelse(bp, 0); goto notfound; } } else { /* * If there wasn't enough space for our * winentries, forget about the empty space */ if (slotcount < wincnt) slotcount = 0; /* * Check for Win95 long filename entry */ if (dep->deAttributes == ATTR_WIN95) { if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) continue; chksum = winChkName((const u_char *)cnp->cn_nameptr, cnp->cn_namelen, (struct winentry *)dep, chksum); continue; } /* * Ignore volume labels (anywhere, not just * the root directory). */ if (dep->deAttributes & ATTR_VOLUME) { chksum = -1; continue; } /* * Check for a checksum or name match */ chksum_ok = (chksum == winChksum(dep->deName)); if (!chksum_ok && ( !olddos || memcmp(&dosfilename[0],dep->deName,8) || memcmp(&dosfilename[8],dep->deExtension,3))) { chksum = -1; continue; } #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): match blkoff %d, diroff %d\n", blkoff, diroff); #endif /* * Remember where this directory * entry came from for whoever did * this lookup. */ dp->de_fndoffset = diroff; if (chksum_ok && nameiop == RENAME) { /* * Target had correct long name * directory entries, reuse them * as needed. */ dp->de_fndcnt = wincnt - 1; } else { /* * Long name directory entries * not present or corrupt, can only * reuse dos directory entry. */ dp->de_fndcnt = 0; } goto found; } } /* for (blkoff = 0; .... */ /* * Release the buffer holding the directory cluster just * searched. */ brelse(bp, 0); } /* for (frcn = 0; ; frcn++) */ notfound: /* * We hold no disk buffers at this point. */ /* * If we get here we didn't find the entry we were looking for. But * that's ok if we are creating or renaming and are at the end of * the pathname and the directory hasn't been removed. */ #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): op %d, refcnt %ld, slotcount %d, slotoffset %d\n", nameiop, dp->de_refcnt, slotcount, slotoffset); #endif if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN) && dp->de_refcnt != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. */ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); if (error) return (error); /* * Fixup the slot description to point to the place where * we might put the new DOS direntry (putting the Win95 * long name entries before that) */ if (!slotcount) { slotcount = 1; slotoffset = diroff; } if (wincnt > slotcount) { slotoffset += sizeof(struct direntry) * (wincnt - slotcount); } /* * Return an indication of where the new directory * entry should be put. */ dp->de_fndoffset = slotoffset; dp->de_fndcnt = wincnt - 1; /* * We return with the directory locked, so that * the parameters we set up above will still be * valid if we actually decide to do a direnter(). * We return ni_vp == NULL to indicate that the entry * does not currently exist; we leave a pointer to * the (locked) directory inode in ndp->ni_dvp. * * NB - if the directory is unlocked, then this * information cannot be used. */ return (EJUSTRETURN); } #if 0 /* * Insert name into cache (as non-existent) if appropriate. * * XXX Negative caching is broken for msdosfs because the name * cache doesn't understand peculiarities such as case insensitivity * and 8.3 filenames. Hence, it may not invalidate all negative * entries if a file with this name is later created. * e.g. creating a file 'foo' won't invalidate a negative entry * for 'FOO'. */ if (nameiop != CREATE) cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); #endif return (ENOENT); found: /* * NOTE: We still have the buffer with matched directory entry at * this point. */ isadir = dep->deAttributes & ATTR_DIRECTORY; scn = getushort(dep->deStartCluster); if (FAT32(pmp)) { scn |= getushort(dep->deHighClust) << 16; if (scn == pmp->pm_rootdirblk) { /* * There should actually be 0 here. * Just ignore the error. */ scn = MSDOSFSROOT; } } if (isadir) { cluster = scn; if (cluster == MSDOSFSROOT) blkoff = MSDOSFSROOT_OFS; else blkoff = 0; } else if (cluster == MSDOSFSROOT) blkoff = diroff; /* * Now release buf to allow deget to read the entry again. * Reserving it here and giving it to deget could result * in a deadlock. */ brelse(bp, 0); foundroot: /* * If we entered at foundroot, then we are looking for the . or .. * entry of the filesystems root directory. isadir and scn were * setup before jumping here. And, bp is already null. */ if (FAT32(pmp) && scn == MSDOSFSROOT) scn = pmp->pm_rootdirblk; /* * If deleting, and at end of pathname, return * parameters which can be used to remove file. * Lock the inode, being careful with ".". */ if (nameiop == DELETE && (flags & ISLASTCN)) { /* * Don't allow deleting the root. */ if (blkoff == MSDOSFSROOT_OFS) return EINVAL; /* * Write access to directory required to delete files. */ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); if (error) return (error); /* * Return pointer to current entry in dp->i_offset. * Save directory inode pointer in ndp->ni_dvp for dirremove(). */ if (dp->de_StartCluster == scn && isadir) { /* "." */ vref(vdp); *vpp = vdp; return (0); } if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) return (error); *vpp = DETOV(tdp); VOP_UNLOCK(*vpp); return (0); } /* * If rewriting (RENAME), return the inode and the * information required to rewrite the present directory * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ if (nameiop == RENAME && (flags & ISLASTCN)) { if (vdp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); if (blkoff == MSDOSFSROOT_OFS) return EINVAL; error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); if (error) return (error); /* * Careful about locking second inode. * This can only occur if the target is ".". */ if (dp->de_StartCluster == scn && isadir) return (EISDIR); if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) return (error); *vpp = DETOV(tdp); VOP_UNLOCK(*vpp); return (0); } /* * Step through the translation in the name. We do not `vput' the * directory because we may need it again if a symbolic link * is relative to the current directory. Instead we save it * unlocked as "pdp". We must get the target inode before unlocking * the directory to insure that the inode will not be removed * before we get it. We prevent deadlock by always fetching * inodes from the root, moving down the directory tree. Thus * when following backward pointers ".." we must unlock the * parent directory before getting the requested directory. * There is a potential race condition here if both the current * and parent directories are removed before the VFS_VGET for the * inode associated with ".." returns. We hope that this occurs * infrequently since we cannot avoid this race condition without * implementing a sophisticated deadlock detection algorithm. * Note also that this simple deadlock detection scheme will not * work if the file system has any hard links other than ".." * that point backwards in the directory structure. */ pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp); /* race to get the inode */ error = deget(pmp, cluster, blkoff, &tdp); vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); if (error) { return error; } *vpp = DETOV(tdp); } else if (dp->de_StartCluster == scn && isadir) { vref(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) return (error); *vpp = DETOV(tdp); } /* * Insert name into cache if appropriate. */ cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); if (*vpp != vdp) VOP_UNLOCK(*vpp); return 0; }
int ntfs_lookup(void *v) { struct vop_lookup_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; } */ *ap = v; struct vnode *dvp = ap->a_dvp; struct ntnode *dip = VTONT(dvp); struct ntfsmount *ntmp = dip->i_mp; struct componentname *cnp = ap->a_cnp; kauth_cred_t cred = cnp->cn_cred; int error; dprintf(("ntfs_lookup: \"%.*s\" (%lld bytes) in %llu\n", (int)cnp->cn_namelen, cnp->cn_nameptr, (long long)cnp->cn_namelen, (unsigned long long)dip->i_number)); error = VOP_ACCESS(dvp, VEXEC, cred); if(error) return (error); if ((cnp->cn_flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); /* * We now have a segment name to search for, and a directory * to search. * * Before tediously performing a linear scan of the directory, * check the name cache to see if the directory/name pair * we are looking for is known already. */ if (cache_lookup(ap->a_dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_nameiop, cnp->cn_flags, NULL, ap->a_vpp)) { return *ap->a_vpp == NULLVP ? ENOENT : 0; } if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { dprintf(("ntfs_lookup: faking . directory in %llu\n", (unsigned long long)dip->i_number)); vref(dvp); *ap->a_vpp = dvp; error = 0; } else if (cnp->cn_flags & ISDOTDOT) { struct ntvattr *vap; dprintf(("ntfs_lookup: faking .. directory in %llu\n", (unsigned long long)dip->i_number)); VOP_UNLOCK(dvp); error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap); if (error) { vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); return (error); } dprintf(("ntfs_lookup: parentdir: %d\n", vap->va_a_name->n_pnumber)); error = VFS_VGET(ntmp->ntm_mountp, vap->va_a_name->n_pnumber,ap->a_vpp); ntfs_ntvattrrele(vap); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); if (error) { return (error); } } else { error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp); if (error) { dprintf(("ntfs_ntlookupfile: returned %d\n", error)); return (error); } dprintf(("ntfs_lookup: found ino: %llu\n", (unsigned long long)VTONT(*ap->a_vpp)->i_number)); } cache_enter(dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); return error; }
int reiserfs_lookup(struct vop_cachedlookup_args *ap) { int error, retval; struct vnode *vdp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; int flags = cnp->cn_flags; struct thread *td = cnp->cn_thread; struct cpu_key *saved_ino; struct vnode *vp; struct vnode *pdp; /* Saved dp during symlink work */ struct reiserfs_node *dp; struct reiserfs_dir_entry de; INITIALIZE_PATH(path_to_entry); char c = cnp->cn_nameptr[cnp->cn_namelen]; cnp->cn_nameptr[cnp->cn_namelen] = '\0'; reiserfs_log(LOG_DEBUG, "looking for `%s', %ld (%s)\n", cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_pnbuf); cnp->cn_nameptr[cnp->cn_namelen] = c; vp = NULL; dp = VTOI(vdp); if (REISERFS_MAX_NAME(dp->i_reiserfs->s_blocksize) < cnp->cn_namelen) return (ENAMETOOLONG); reiserfs_log(LOG_DEBUG, "searching entry\n"); de.de_gen_number_bit_string = 0; retval = reiserfs_find_entry(dp, cnp->cn_nameptr, cnp->cn_namelen, &path_to_entry, &de); pathrelse(&path_to_entry); if (retval == NAME_FOUND) { reiserfs_log(LOG_DEBUG, "found\n"); } else { reiserfs_log(LOG_DEBUG, "not found\n"); } if (retval == NAME_FOUND) { #if 0 /* Hide the .reiserfs_priv directory */ if (reiserfs_xattrs(dp->i_reiserfs) && !old_format_only(dp->i_reiserfs) && REISERFS_SB(dp->i_reiserfs)->priv_root && REISERFS_SB(dp->i_reiserfs)->priv_root->d_inode && de.de_objectid == le32toh(INODE_PKEY(REISERFS_SB( dp->i_reiserfs)->priv_root->d_inode)->k_objectid)) { return (EACCES); } #endif reiserfs_log(LOG_DEBUG, "reading vnode\n"); pdp = vdp; if (flags & ISDOTDOT) { saved_ino = (struct cpu_key *)&(de.de_dir_id); VOP_UNLOCK(pdp, 0); error = reiserfs_iget(vdp->v_mount, saved_ino, &vp, td); vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); if (error != 0) return (error); *vpp = vp; } else if (de.de_objectid == dp->i_number && de.de_dir_id == dp->i_ino) { VREF(vdp); /* We want ourself, ie "." */ *vpp = vdp; } else { if ((error = reiserfs_iget(vdp->v_mount, (struct cpu_key *)&(de.de_dir_id), &vp, td)) != 0) return (error); *vpp = vp; } /* * Propogate the priv_object flag so we know we're in the * priv tree */ /*if (is_reiserfs_priv_object(dir)) REISERFS_I(inode)->i_flags |= i_priv_object;*/ } else { if (retval == IO_ERROR) { reiserfs_log(LOG_DEBUG, "IO error\n"); return (EIO); } return (ENOENT); } /* Insert name into cache if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); reiserfs_log(LOG_DEBUG, "done\n"); return (0); }
/* * Convert a component of a pathname into a pointer to a locked inode. * This is a very central and rather complicated routine. * If the file system is not maintained in a strict tree hierarchy, * this can result in a deadlock situation (see comments in code below). * * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on * whether the name is to be looked up, created, renamed, or deleted. * When CREATE, RENAME, or DELETE is specified, information usable in * creating, renaming, or deleting a directory entry may be calculated. * If flag has LOCKPARENT or'ed into it and the target of the pathname * exists, lookup returns both the target and its parent directory locked. * When creating or renaming and LOCKPARENT is specified, the target may * not be ".". When deleting and LOCKPARENT is specified, the target may * be "."., but the caller must check to ensure it does an vrele and iput * instead of two iputs. * * Overall outline of ufs_lookup: * * check accessibility of directory * look for name in cache, if found, then if at end of path * and deleting or creating, drop it, else return name * search for name in directory, to found or notfound * notfound: * if creating, return locked directory, leaving info on available slots * else return error * found: * if at end of path and deleting, return information to allow delete * if at end of path and rewriting (RENAME and LOCKPARENT), lock target * inode and return info to allow rewrite * if not at end, add name to cache; if at end and neither creating * nor deleting, add name to cache * * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked. */ int cd9660_lookup(struct vnop_lookup_args *ap) { register struct vnode *vdp; /* vnode for directory being searched */ register struct iso_node *dp; /* inode for directory being searched */ register struct iso_mnt *imp; /* file system that directory is in */ struct buf *bp; /* a buffer of directory entries */ struct iso_directory_record *ep = NULL;/* the current directory entry */ int entryoffsetinblock; /* offset of ep in bp's buffer */ int saveoffset = 0; /* offset of last directory entry in dir */ int numdirpasses; /* strategy for directory search */ doff_t endsearch; /* offset to end directory search */ struct vnode *pdp; /* saved dp during symlink work */ struct vnode *tdp; /* returned by cd9660_vget_internal */ u_long bmask; /* block offset mask */ int lockparent; /* 1 => lockparent flag is set */ int wantparent; /* 1 => wantparent or lockparent flag */ int wantassoc; int error; ino_t ino = 0; int reclen; u_short namelen; int isoflags; char altname[ISO_RRIP_NAMEMAX]; int res; int len; char *name; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; vfs_context_t ctx = cnp->cn_context; size_t altlen; bp = NULL; *vpp = NULL; vdp = ap->a_dvp; dp = VTOI(vdp); imp = dp->i_mnt; lockparent = flags & LOCKPARENT; wantparent = flags & (LOCKPARENT|WANTPARENT); wantassoc = 0; /* * We now have a segment name to search for, and a directory to search. * * Before tediously performing a linear scan of the directory, * check the name cache to see if the directory/name pair * we are looking for is known already. */ if ((error = cache_lookup(vdp, vpp, cnp))) { if (error == ENOENT) return (error); return (0); } len = cnp->cn_namelen; name = cnp->cn_nameptr; altname[0] = '\0'; /* * A "._" prefix means, we are looking for an associated file */ if (imp->iso_ftype != ISO_FTYPE_RRIP && *name == ASSOCCHAR1 && *(name+1) == ASSOCCHAR2) { wantassoc = 1; len -= 2; name += 2; } /* * Decode search name into UCS-2 (Unicode) */ if ((imp->iso_ftype == ISO_FTYPE_JOLIET) && !((len == 1 && *name == '.') || (flags & ISDOTDOT))) { int flags1 = UTF_PRECOMPOSED; (void) utf8_decodestr(name, len, (u_int16_t*) altname, &altlen, sizeof(altname), 0, flags1); name = altname; len = altlen; } /* * If there is cached information on a previous search of * this directory, pick up where we last left off. * We cache only lookups as these are the most common * and have the greatest payoff. Caching CREATE has little * benefit as it usually must search the entire directory * to determine that the entry does not exist. Caching the * location of the last DELETE or RENAME has not reduced * profiling time and hence has been removed in the interest * of simplicity. */ bmask = imp->im_sector_size - 1; if (nameiop != LOOKUP || dp->i_diroff == 0 || dp->i_diroff > dp->i_size) { entryoffsetinblock = 0; dp->i_offset = 0; numdirpasses = 1; } else { dp->i_offset = dp->i_diroff; if ((entryoffsetinblock = dp->i_offset & bmask) && (error = cd9660_blkatoff(vdp, SECTOFF(imp, dp->i_offset), NULL, &bp))) return (error); numdirpasses = 2; iso_nchstats.ncs_2passes++; } endsearch = dp->i_size; searchloop: while (dp->i_offset < endsearch) { /* * If offset is on a block boundary, * read the next directory block. * Release previous if it exists. */ if ((dp->i_offset & bmask) == 0) { if (bp != NULL) buf_brelse(bp); if ( (error = cd9660_blkatoff(vdp, SECTOFF(imp,dp->i_offset), NULL, &bp)) ) return (error); entryoffsetinblock = 0; } /* * Get pointer to next entry. */ ep = (struct iso_directory_record *) ((char *)0 + buf_dataptr(bp) + entryoffsetinblock); reclen = isonum_711(ep->length); if (reclen == 0) { /* skip to next block, if any */ dp->i_offset = (dp->i_offset & ~bmask) + imp->im_sector_size; continue; } if (reclen < ISO_DIRECTORY_RECORD_SIZE) { /* illegal entry, stop */ break; } if (entryoffsetinblock + reclen > imp->im_sector_size) { /* entries are not allowed to cross sector boundaries */ break; } namelen = isonum_711(ep->name_len); isoflags = isonum_711(ep->flags); if (reclen < ISO_DIRECTORY_RECORD_SIZE + namelen) /* illegal entry, stop */ break; /* * Check for a name match. */ if (imp->iso_ftype == ISO_FTYPE_RRIP) { if (isoflags & directoryBit) ino = isodirino(ep, imp); else ino = ((daddr_t)buf_blkno(bp) << imp->im_bshift) + entryoffsetinblock; dp->i_ino = ino; cd9660_rrip_getname(ep,altname,&namelen,&dp->i_ino,imp); if (namelen == cnp->cn_namelen && !bcmp(name,altname,namelen)) goto found; ino = 0; } else { if ((!(isoflags & associatedBit)) == !wantassoc) { if ((len == 1 && *name == '.') || (flags & ISDOTDOT)) { if (namelen == 1 && ep->name[0] == ((flags & ISDOTDOT) ? 1 : 0)) { /* * Save directory entry's inode number and * release directory buffer. */ dp->i_ino = isodirino(ep, imp); goto found; } if (namelen != 1 || ep->name[0] != 0) goto notfound; } else if (imp->iso_ftype != ISO_FTYPE_JOLIET && !(res = isofncmp(name, len, ep->name, namelen))) { if ( isoflags & directoryBit ) ino = isodirino(ep, imp); else ino = ((daddr_t)buf_blkno(bp) << imp->im_bshift) + entryoffsetinblock; saveoffset = dp->i_offset; } else if (imp->iso_ftype == ISO_FTYPE_JOLIET && !(res = ucsfncmp((u_int16_t*)name, len, (u_int16_t*) ep->name, namelen))) { if ( isoflags & directoryBit ) ino = isodirino(ep, imp); else ino = ((daddr_t)buf_blkno(bp) << imp->im_bshift) + entryoffsetinblock; saveoffset = dp->i_offset; } else if (ino) goto foundino; #ifdef NOSORTBUG /* On some CDs directory entries are not sorted correctly */ else if (res < 0) goto notfound; else if (res > 0 && numdirpasses == 2) numdirpasses++; #endif } } dp->i_offset += reclen; entryoffsetinblock += reclen; } /* endwhile */ if (ino) { foundino: dp->i_ino = ino; if (saveoffset != dp->i_offset) { if (lblkno(imp, dp->i_offset) != lblkno(imp, saveoffset)) { if (bp != NULL) buf_brelse(bp); if ( (error = cd9660_blkatoff(vdp, SECTOFF(imp, saveoffset), NULL, &bp)) ) return (error); } entryoffsetinblock = saveoffset & bmask; ep = (struct iso_directory_record *) ((char *)0 + buf_dataptr(bp) + entryoffsetinblock); dp->i_offset = saveoffset; } goto found; } notfound: /* * If we started in the middle of the directory and failed * to find our target, we must check the beginning as well. */ if (numdirpasses == 2) { numdirpasses--; dp->i_offset = 0; endsearch = dp->i_diroff; goto searchloop; } if (bp != NULL) buf_brelse(bp); /* * Insert name into cache (as non-existent) if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); return (ENOENT); found: if (numdirpasses == 2) iso_nchstats.ncs_pass2++; /* * Found component in pathname. * If the final component of path name, save information * in the cache as to where the entry was found. */ if ((flags & ISLASTCN) && nameiop == LOOKUP) dp->i_diroff = dp->i_offset; /* * Step through the translation in the name. We do not `iput' the * directory because we may need it again if a symbolic link * is relative to the current directory. Instead we save it * unlocked as "pdp". We must get the target inode before unlocking * the directory to insure that the inode will not be removed * before we get it. We prevent deadlock by always fetching * inodes from the root, moving down the directory tree. Thus * when following backward pointers ".." we must unlock the * parent directory before getting the requested directory. * There is a potential race condition here if both the current * and parent directories are removed before the `iget' for the * inode associated with ".." returns. We hope that this occurs * infrequently since we cannot avoid this race condition without * implementing a sophisticated deadlock detection algorithm. * Note also that this simple deadlock detection scheme will not * work if the file system has any hard links other than ".." * that point backwards in the directory structure. */ pdp = vdp; /* * If ino is different from dp->i_ino, * it's a relocated directory. */ if (flags & ISDOTDOT) { error = cd9660_vget_internal(vnode_mount(vdp), dp->i_ino, &tdp, NULL, NULL, dp->i_ino != ino, ep, vfs_context_proc(ctx)); VTOI(tdp)->i_parent = VTOI(pdp)->i_number; buf_brelse(bp); *vpp = tdp; } else if (dp->i_number == dp->i_ino) { buf_brelse(bp); vnode_get(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { error = cd9660_vget_internal(vnode_mount(vdp), dp->i_ino, &tdp, vdp, cnp, dp->i_ino != ino, ep, vfs_context_proc(ctx)); /* save parent inode number */ VTOI(tdp)->i_parent = VTOI(pdp)->i_number; buf_brelse(bp); if (error) return (error); *vpp = tdp; } return (0); }