/* * 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; }
/* * 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; }