示例#1
0
/*
 * NAME:        pathlookup_pc
 *
 * FUNCTION:    Lookup path, preserving case.
 *              Lookup path, copying each component into output string
 *		preserving its case.
 *
 * PARAMETERS:  vfsp    - pointer to VFS
 *              path    - full path name
 *              path_pc - output - full path name w/preserved case
 *
 * RETURN:      errors from subroutines.
 *
 * NOTES:	We assume path is in canonical form: "X:\<path>" where there
 *		are no extraneous backslashes and . and .. have been removed.
 *
 *		dtFind is not very efficient for finding a directory entry
 *		without wildcards, but infolevel 7 does not seem to actually
 *		be used anywhere, so it must not be too important.
 */
int32	pathlookup_pc(
	struct vfs	*vfsp,
	UniChar		*path,		/* input - Path */
	UniChar		*path_pc)	/* output - path w/preserved case */
{
	int32		comp_len;
	uint32		count;
	UniChar		*component;
	struct dirent	*dbuf;
	inode_t		*ip;
	int32		offset;
	UniChar		*outptr = path_pc;
	component_t	pattern;
	int		rc;
	UniChar		*slash;
	int32		tbytes;
	struct vnode	*vp;

	if (vfsp == NULL)
	{
		jERROR(2,("pathlookup_pc: invalid VPB!\n"));
		return ENOTDIR;
	}
	/* Copy "X:\" to output string */
	UniStrncpy(outptr, path, 3);
	outptr += 3;
	path += 3;

	if (*path == 0)	
	{
		/* Trivial case "X:\" */
		*outptr = 0;
		return NO_ERROR;
	}

	component = (UniChar *)allocpool(unipool, 0);
	if (component == 0)
		return ENOSPC;
	pattern.name = component;

	dbuf = (struct dirent *)allocpool(dirent_pool, 0);
	if (dbuf == 0)
	{
		freepool(unipool, (caddr_t *)component);
		return ENOSPC;
	}

	vp = vfsp->vfs_mntd;	/* vnode of root directory */
	jfs_hold(vp);

	while (path)
	{
		slash = UniStrchr(path, '\\');
		if (slash)
		{
			comp_len = slash - path;
			slash++;
		}
		else
			comp_len = UniStrlen(path);
		UniStrncpy(component, path, comp_len);
		component[comp_len] = 0;
		UniStrupr(component);		/* Convert to upper case */
		pattern.namlen = comp_len;
		path = slash;

		offset = 0;
		count = 1;
		tbytes = 0;
		rc = dtFind(VP2IP(vp), &pattern, 0, &offset, &count, PSIZE,
			    &tbytes, dbuf);
		jfs_rele(vp);
		if (rc || (count == 0))
		{
			freepool(dirent_pool, (caddr_t *)dbuf);
			freepool(unipool, (caddr_t *)component);
			return ENOENT;
		}
		UniStrncpy(outptr, dbuf->d_name, dbuf->d_namlen);
		outptr += dbuf->d_namlen;

		if (path)
		{
			ICACHE_LOCK();
			rc = iget(vfsp, dbuf->d_ino, &ip, 0);
			ICACHE_UNLOCK();
			if (rc)
			{
				freepool(dirent_pool, (caddr_t *)dbuf);
				freepool(unipool, (caddr_t *)component);
				return rc;
			}
			vp = IP2VP(ip);

			*(outptr++) = '\\';
		}
		else
			*outptr = 0;
	}
	freepool(dirent_pool, (caddr_t *)dbuf);
	freepool(unipool, (caddr_t *)component);
	return NO_ERROR;
}
示例#2
0
/*
 * NAME:        jfs_lookup(dvp, vpp, pname, flag, vattrp, crp)
 *
 * FUNCTION:    resolve <pname> in directory <dvp> to vnode <vpp>
 *              with a reference acquired and attribute <vattrp>.
 *
 * PARAMETERS:  dvp     _ directory vnode
 *              vpp     - object vnode (out)
 *              pname   - object name
 *              flag    -
 *              vattrp  - object attribute (out)
 *              crp     - credential
 *
 * RETURN:      errors from subroutines.
 */
jfs_lookup(
        struct vnode    *dvp,
        struct vnode    **vpp,
	UniChar		*pname, /* NULL terminated */
        int32           flag,
        struct vattr    *vattrp,
        struct ucred    *crp)
{
        int32   rc = 0;
        struct vfs      *vfsp = dvp->v_vfsp;
        inode_t *dip = VP2IP(dvp);      /* parent directory inode */
        ino_t   ino;            /* object i_number */
        inode_t *ip;            /* object inode */
        component_t     dname;  /* object name */
        ncookie_t       ncookie;
        btstack_t       btstack;

NOISE(1,("jfs_lookup: dip:0x%08x name:%s\n", dip, pname));

        *vpp = NULL;

        /* <dvp> must be a directory */
        if ((dip->i_mode & IFMT) != IFDIR)
                return ENOTDIR;

        IREAD_LOCK(dip);

        if (dip->i_nlink == 0)
        {
                rc = ENOENT;
                goto out;
        }

        /*
         * resolve name to i_number via dnlc/directory lookup
         */
getInumber:

        /*
         * for "." or "..", lookup directory inode
         */
        if (pname[0] == '.')
        {
                /* looking up ".." */
                if (pname[1] == '.' && pname[2] == '\0')
                {
                        ino = dip->i_parent;
                        goto getInode;
                }
                /* looking up "." */
                else if (pname[1] == '\0')
                {
                        ip = dip;

                        jfs_hold(dvp);

                        *vpp = dvp;
                        goto getAttribute;
                }
        }

        /*
         * search dnlc/directory
         */
        dname.name = pname;
	dname.namlen = UniStrlen(pname);
        if ((ino = ncLookup(dip->i_ipimap, dip->i_number, &dname, &ncookie)) == 0)
        {
                /*
                 * dnlc miss: search directory
                 */
                if (rc = dtSearch(dip, &dname, &ino, &btstack, JFS_LOOKUP))
                        goto out;

                /* insert name entry to dnlc */
                ncEnter(dip->i_ipimap, dip->i_number, &dname, ino, &ncookie);
        }

        /*
         * resolve i_number to inode/vnode with a reference
         */
getInode:
        ICACHE_LOCK();
        rc = iget(vfsp, ino, &ip, 0);
        ICACHE_UNLOCK();
        if (rc)
                goto out;

        *vpp = IP2VP(ip);

        /*
         * get attribute
         */
getAttribute:
        if (vattrp != NULL)
                get_vattr(ip, vattrp);

out:
        IREAD_UNLOCK(dip);

NOISE(1,("jfs_lookup: rc:%d\n", rc));
        return rc;
}
示例#3
0
/*
 * NAME:	readdir
 *
 * FUNCTION:	read directory according to specifications
 *		in directory search structure
 *
 * PARAMETER:
 *
 * RETURN:	EINVAL	- if not a directory
 *		errors from subroutines
 *
 * note:
 * N.B. directory file offset encodes (directory page number,
 * entry index number), and shold NOT be interpreted/modified
 * by caller (lseek()) except that intial offset set to 0.
 *
 * no guarantees can be made that the exact offset
 * requested can be found if directory has been updated
 * by other threads between consecutive readdir()s.
 * transfer length of zero signals start offset beyond eof.
 *
 * unused space in the directory are not returned to the user,
 * i.e., more than requested size may have to be read
 * from directory to fill the user's buffer.
 */
readdir(
    struct vnode	*dvp,		/* inode of directory being read */
    struct fsfd	*fsfp,		/* directory search information */
    char 		*ubuf,		/* user's data area */
    uint32		ubytes,		/* size of user's data area */
    uint32		*matchcnt,	/* count of entries returned */
    uint32		level,		/* level of output struct */
    uint32		flags,		/* offsets needed in output? */
    EAOP		*eaopp,		/* pointer to EAOP */
    struct ucred	*crp)
{
    int32 	rc = 0;
    int32 	ReturnCode = NO_ERROR;
    inode_t	*dip;			/* directory inode */
    inode_t	*ip;			/* object inode */
    uint32	matches;		/* output matches found */
    uint32	dtmatches;		/* matches found per dtFind call */
    uint32	position;		/* offsets in output */
    uint32	count;			/* output buffer count */
    int32 	tbytes;			/* byte count in dirent buffer */
    struct dirent *dbuf;		/* dirent buffer */
    struct dirent *dbufp;		/* dirent buffer */
    uint32 ffhdsize;		/* size of ffbuf header */
    component_t lastmatch;		/* pointer to last matching entry */
    char *ffbuf;			/* output buffer pointer */
    char *nxbuf;			/* output buffer pointer */
    char *bufp;			/* output buffer pointer */

    MMPHPrereaddir();      /* MMPH Performance Hook */

    /* set state from search structure
     */
    dip = VP2IP(dvp);
    position = flags & FF_GETPOS;

    /* validate request */
    if (ubytes == 0)
    {
        rc = EINVAL;
        goto readdir_Exit;
    }

    /* continuous read of empty directory ? */
    if (fsfp->fsd_offset == -1)
    {
        rc = ERROR_NO_MORE_FILES;
        goto readdir_Exit;
    }

    dbuf = (struct dirent *)allocpool(dirent_pool, 0);	// D228565
    if (dbuf == 0)						// D228565
    {
        rc = ENOMEM;
        goto readdir_Exit;
    }

    /* set up variable to manipulate output buffer pointers
     * based on level.
     */
    if (level == 1)
        ffhdsize = FFBUFHD;
    else if (level == 11)
        ffhdsize = FFBUFHD3L;
    else if (level < 11)
        ffhdsize = FFBUFHD2;
    else
        ffhdsize = FFBUFHD4L;
    if (position)
        ffhdsize += sizeof(uint32);

    ffbuf = ubuf;
    count = 0;
    matches = *matchcnt;
    *matchcnt = 0;

    while ((*matchcnt < matches) && (rc == 0))
    {
        IREAD_LOCK(dip);

        /* directory became void when last link was removed */
        if ((dip->i_nlink == 0) || ((dip->i_mode & IFMT) != IFDIR))
        {
            IREAD_UNLOCK(dip);
            freepool(dirent_pool, (caddr_t *)dbuf);
            rc = ENOTDIR;
            goto readdir_Exit;
        }

        /* fill a directory buffer.
        * read on-disk structure (struct ldtentry_t) and
        * translate into readdir() structure (struct dirent).
        */
        tbytes = 0;
        dtmatches = matches - *matchcnt;
        dbufp = dbuf;					// D228565
        rc = dtFind(dip, &fsfp->fsd_pattern, fsfp->fsd_lastmatch,
                    &fsfp->fsd_offset, &dtmatches, PSIZE, &tbytes, dbufp);
        IREAD_UNLOCK(dip);
        if (rc)
        {
            freepool(dirent_pool, (caddr_t *)dbuf);
            goto readdir_Exit;
        }

        /* copy translate buffer to user FileFindBuf buffer */

        while ((*matchcnt < matches) && (ReturnCode == NO_ERROR))
        {
            uint32 namlen;

            /* translation buffer empty? */
            if (tbytes == 0)
                break;

            /* get size of next name */
            namlen = dbufp->d_namlen;

            /* user buffer full?
            * the +1 here is to allow for the null character
            * terminating the name string.
            */
            if ((count + ffhdsize + namlen + 1) > ubytes)
            {
                rc = ERROR_BUFFER_OVERFLOW;
                break;
            }

            /* get the inode for the file
            */
            ICACHE_LOCK();
            rc = iget(dvp->v_vfsp, dbufp->d_ino, &ip, 0);
            ICACHE_UNLOCK();

            if (rc)
                goto try_next;

            nxbuf = ffbuf;


            /* fill in file search info for files that have
             * the proper attributes; ignore others.
             */
            rc = get_fileinfo(ip, &nxbuf, ubytes, dbufp->d_name,
                              namlen, fsfp->fsd_havattr, level,
                              eaopp, flags);

            if ((rc == ERROR_BUFFER_OVERFLOW) && (*matchcnt == 0) &&
                    ((level == FIL_QUERYEASFROMLIST) ||
                     (level == FIL_QUERYEASFROMLISTL)))
            {
                /* Can't fit EA in buffer, try without
                 * getting EA
                 */

                if (level == FIL_QUERYEASFROMLIST)
                    level = FIL_QUERYEASIZE;
                else
                    level = FIL_QUERYEASIZEL;

                ReturnCode = ERROR_EAS_DIDNT_FIT;
                rc = get_fileinfo(ip, &nxbuf, ubytes,
                                  dbufp->d_name, namlen,
                                  fsfp->fsd_havattr, level,
                                  eaopp, flags);
            }
            /* release the inode */
            jfs_rele(IP2VP(ip));

            if (rc == 0)
            {
                /* set offset if requested */
                if (position)
                {
                    rc = KernCopyOut(ffbuf,
                                     &dbufp->d_offset,
                                     sizeof(int32));
                    if (rc)
                    {
                        /* This is very unlikely to
                         * happen! */
                        ASSERT(0);
                        break;
                    }
                }

                /* update output buffer count */
                count += nxbuf - ffbuf;

                /* move to next entry in output buffer */
                ffbuf = nxbuf;

                /* update match count */
                *matchcnt += 1;
            }
            else if (rc != -1)
                break;

try_next:
            /* rc == -1 indicates no attribute match,
             * just keep going.
             */
            rc = 0;

            /* save name for next call setup */
            lastmatch.name = dbufp->d_name;
            lastmatch.namlen = namlen;

            /* update dirent buffer count */
            tbytes -= dbufp->d_reclen;

            /* move to next entry in dirent buffer */
            dbufp = (struct dirent *)
                    ((caddr_t)dbufp + dbufp->d_reclen);
        }
        /* We don't want to continue if ReturnCode = ERROR_EAS_DIDNT_FIT
         */
        if (rc == 0)
            rc = ReturnCode;

        /* set return code for end of directory with no matches */
        if (fsfp->fsd_offset == -1)
            rc = ERROR_NO_MORE_FILES;
        else if ((rc == 0) || (rc == ERROR_EAS_DIDNT_FIT))
        {
            /* save last matching name for next call */
            UniStrncpy(fsfp->fsd_lastmatch,lastmatch.name,
                       lastmatch.namlen);
            fsfp->fsd_lastmatch[lastmatch.namlen] = '\0';
        }
    }

    /* claim success if we return any entries */
    if (*matchcnt != 0)
        rc = ReturnCode;

    freepool(dirent_pool, (caddr_t *)dbuf);

readdir_Exit:

    MMPHPostreaddir();     /* MMPH Performance Hook */
    return rc;
}