static int noteUsage(int fd, int32_t startAt, struct pcdir *dp, struct pcdir *lp, int32_t longEntryStartCluster, int isHidden, int isDir, struct nameinfo *fullPathName) { struct pcdir *orphanEntry; int32_t chain = startAt; int32_t count = 0; int savePathNextIteration = 0; int haveBad = 0; ClusterInfo *tmpl = NULL; while ((chain >= FIRST_CLUSTER) && (chain <= LastCluster)) { if ((markInUse(fd, chain, dp, lp, longEntryStartCluster, isHidden ? HIDDEN : VISIBLE, &tmpl)) != CLINFO_NEWLY_ALLOCED) break; count++; if (savePathNextIteration == 1) { savePathNextIteration = 0; if (fullPathName != NULL) fullPathName->references++; squirrelPath(fullPathName, chain); } if (isMarkedBad(chain)) { haveBad = 1; savePathNextIteration = 1; } if (isHidden) HiddenClusterCount++; else if (isDir) DirClusterCount++; else FileClusterCount++; chain = nextInChain(chain); } /* * Do a sanity check on the file size in the directory entry. * This may create an orphaned cluster chain. */ if (sanityCheckSize(fd, dp, count, isDir, startAt, fullPathName, &orphanEntry) == TRUNCATED) { /* * The pre-existing directory entry has been truncated, * so the chain associated with it no longer has any * bad clusters. Instead, the new orphan has them. */ if (haveBad > 0) { truncChainWithBadCluster(fd, orphanEntry, startAt); } haveBad = 0; } return (haveBad); }
/* * visitNodes() * * This is the main workhouse routine for traversing pcfs metadata. * There isn't a lot to the metadata. Basically there is a root * directory somewhere (either in its own special place outside the * data area or in a data cluster). The root directory (and all other * directories) are filled with a number of fixed size entries. An * entry has the filename and extension, the file's attributes, the * file's size, and the starting data cluster of the storage allocated * to the file. To determine which clusters are assigned to the file, * you start at the starting cluster entry in the FAT, and follow the * chain of entries in the FAT. * * Arguments are: * fd * descriptor for accessing the raw file system data * currentCluster * original caller supplies the initial starting cluster, * subsequent recursive calls are made with updated * cluster numbers for the sub-directories. * dirData * pointer to the directory data bytes * dirDataLen * size of the whole buffer of data bytes (usually it is * the size of a cluster, but the root directory on * FAT12/16 is not necessarily the same size as a cluster). * depth * original caller should set it to zero (assuming they are * starting from the root directory). This number is used to * change the indentation of file names presented as debug info. * descend * boolean indicates if we should descend into subdirectories. * operation * what, if any, matching should be performed. * The PCFS_TRAVERSE_ALL operation is a depth first traversal * of all nodes in the metadata tree, that tracks all the * clusters in use (according to the meta-data, at least) * matchRequired * value to be matched (if any) * found * output parameter * used to return pointer to a directory entry that matches * the search requirement * original caller should pass in a pointer to a NULL pointer. * lastDirCluster * output parameter * if no match found, last cluster num of starting directory * dirEnd * output parameter * if no match found, return parameter stores pointer to where * new directory entry could be appended to existing directory * recordPath * output parameter * as files are discovered, and directories traversed, this * buffer is used to store the current full path name. * pathLen * output parameter * this is in the integer length of the current full path name. */ static void visitNodes(int fd, int32_t currentCluster, ClusterContents *dirData, int32_t dirDataLen, int depth, int descend, int operation, char matchRequired, struct pcdir **found, int32_t *lastDirCluster, struct pcdir **dirEnd, char *recordPath, int *pathLen) { struct pcdir *longdp = NULL; struct pcdir *dp; int32_t longStart; int withinLongName = 0; int saveLen = *pathLen; dp = dirData->dirp; /* * A directory entry where the first character of the name is * PCD_UNUSED indicates the end of the directory. */ while ((uchar_t *)dp < dirData->bytes + dirDataLen && dp->pcd_filename[0] != PCD_UNUSED) { /* * Handle the special case find operations. */ searchChecks(dp, operation, matchRequired, found); if (*found) break; /* * Are we looking at part of a long file name entry? * If so, we may need to note the start of the name. * We don't do any further processing of long file * name entries. * * We also skip deleted entries and the '.' and '..' * entries. */ if ((dp->pcd_attr & PCDL_LFN_BITS) == PCDL_LFN_BITS) { if (!withinLongName) { withinLongName++; longStart = currentCluster; longdp = dp; } dp++; continue; } else if ((dp->pcd_filename[0] == PCD_ERASED) || (dp->pcd_filename[0] == '.')) { /* * XXX - if we were within a long name, then * its existence is bogus, because it is not * attached to any real file. */ withinLongName = 0; dp++; continue; } withinLongName = 0; if (operation == PCFS_TRAVERSE_ALL) catalogEntry(fd, dp, longdp, longStart, depth, recordPath, pathLen); longdp = NULL; longStart = 0; if (dp->pcd_attr & PCA_DIR && descend == PCFS_VISIT_SUBDIRS) { traverseDir(fd, extractStartCluster(dp), depth + 1, descend, operation, matchRequired, found, lastDirCluster, dirEnd, recordPath, pathLen); if (*found) break; } dp++; *pathLen = saveLen; } if (*found) return; if ((uchar_t *)dp < dirData->bytes + dirDataLen) { /* * We reached the end of directory before the end of * our provided data (a cluster). That means this cluster * is the last one in this directory's chain. It also * means we've just looked at the last directory entry. */ *lastDirCluster = currentCluster; *dirEnd = dp; return; } /* * If there is more to the directory we'll go get it otherwise we * are done traversing this directory. */ if ((currentCluster == FAKE_ROOTDIR_CLUST) || (lastInFAT(currentCluster))) { *lastDirCluster = currentCluster; return; } else { traverseDir(fd, nextInChain(currentCluster), depth, descend, operation, matchRequired, found, lastDirCluster, dirEnd, recordPath, pathLen); *pathLen = saveLen; } }
NarratorNodeIfc & ChainNarratorNodeIterator::firstChild() { return nextInChain(); }