/** * Recursive worker for rtDbgSymCacheAddDir, for minimal stack wasting. * * @returns IPRT status code (fully bitched). * @param pszPath Pointer to a RTPATH_MAX size buffer containing * the path to the current directory ending with a * slash. * @param cchPath The size of the current directory path. * @param pDirEntry Pointer to the RTDIRENTRYEX structure to use. * @param pCfg The configuration. */ static int rtDbgSymCacheAddDirWorker(char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Open the directory. */ PRTDIR pDir; int rc, rc2; if (pCfg->pszFilter) { rc = RTStrCopy(&pszPath[cchPath], RTPATH_MAX - cchPath, pCfg->pszFilter); if (RT_FAILURE(rc)) { pszPath[cchPath] = '\0'; return RTMsgErrorRc(rc, "Filename too long (%Rrc): '%s" RTPATH_SLASH_STR "%s'", rc, pszPath, pCfg->pszFilter); } rc = RTDirOpenFiltered(&pDir, pszPath, RTDIRFILTER_WINNT, 0 /*fFlags*/); } else rc = RTDirOpen(&pDir, pszPath); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "RTDirOpen%s failed on '%s': %Rrc", pCfg->pszFilter ? "Filtered" : "", pszPath, rc); /* * Enumerate the files. */ for (;;) { rc2 = RTDirReadEx(pDir, pDirEntry, NULL, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK); if (RT_FAILURE(rc2)) { pszPath[cchPath] = '\0'; if (rc2 != VERR_NO_MORE_FILES) { RTMsgError("RTDirReadEx failed in '%s': %Rrc\n", pszPath, rc2); rc = rc2; } break; } /* Skip dot and dot-dot. */ if (RTDirEntryExIsStdDotLink(pDirEntry)) continue; /* Construct a full path. */ rc = RTStrCopy(&pszPath[cchPath], RTPATH_MAX, pDirEntry->szName); if (RT_FAILURE(rc)) { pszPath[cchPath] = '\0'; RTMsgError("File name too long in '%s': '%s' (%Rrc)", pszPath, pDirEntry->szName, rc); break; } switch (rtDbgSymCacheFigureType2(pszPath, &pDirEntry->Info)) { case RTDBGSYMCACHEFILETYPE_DIR: if (!pCfg->fRecursive) RTMsgInfo("Skipping directory '%s'...", pszPath); else { if (cchPath + pDirEntry->cbName + 3 <= RTPATH_MAX) { pszPath[cchPath + pDirEntry->cbName] = RTPATH_SLASH; pszPath[cchPath + pDirEntry->cbName + 1] = '\0'; rc2 = rtDbgSymCacheAddDirWorker(pszPath, cchPath + pDirEntry->cbName + 1, pDirEntry, pCfg); } else { RTMsgError("File name too long in '%s': '%s' (%Rrc)", pszPath, pDirEntry->szName, rc); rc2 = VERR_FILENAME_TOO_LONG; } } break; case RTDBGSYMCACHEFILETYPE_DEBUG_FILE: rc2 = rtDbgSymCacheAddDebugFile(pszPath, pCfg); break; case RTDBGSYMCACHEFILETYPE_IMAGE_FILE: rc2 = rtDbgSymCacheAddImageFile(pszPath, NULL /*pszExtraSuff*/, RTDBG_CACHE_UUID_MAP_DIR_IMAGES, pCfg); break; case RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE: rc2 = rtDbgSymCacheAddDebugBundle(pszPath, cchPath, pDirEntry->cbName, pCfg); break; case RTDBGSYMCACHEFILETYPE_IMAGE_BUNDLE: rc2 = rtDbgSymCacheAddImageBundle(pszPath, cchPath, pDirEntry->cbName, pDirEntry, pCfg); break; case RTDBGSYMCACHEFILETYPE_DIR_FILTER: case RTDBGSYMCACHEFILETYPE_INVALID: rc2 = RTMsgErrorRc(VERR_INTERNAL_ERROR_2, "Invalid: '%s'", pszPath); break; case RTDBGSYMCACHEFILETYPE_IGNORE: rc2 = VINF_SUCCESS; break; } if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) rc = rc2; } /* * Clean up. */ rc2 = RTDirClose(pDir); if (RT_FAILURE(rc2)) { RTMsgError("RTDirClose failed in '%s': %Rrc", pszPath, rc); rc = rc2; } return rc; }
int main(int argc, char **argv) { int rcRet = 0; RTR3InitExe(argc, &argv, 0); /* * Iterate arguments. */ bool fLong = false; bool fShortName = false; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (int j = 1; argv[i][j]; j++) { switch (argv[i][j]) { case 'l': fLong = true; break; case 's': fShortName = true; break; default: RTPrintf("Unknown option '%c' ignored!\n", argv[i][j]); break; } } } else { /* open */ PRTDIR pDir; int rc = RTDirOpen(&pDir, argv[i]); if (RT_SUCCESS(rc)) { /* list */ if (!fLong) { for (;;) { RTDIRENTRY DirEntry; rc = RTDirRead(pDir, &DirEntry, NULL); if (RT_FAILURE(rc)) break; switch (DirEntry.enmType) { case RTDIRENTRYTYPE_UNKNOWN: RTPrintf("u"); break; case RTDIRENTRYTYPE_FIFO: RTPrintf("f"); break; case RTDIRENTRYTYPE_DEV_CHAR: RTPrintf("c"); break; case RTDIRENTRYTYPE_DIRECTORY: RTPrintf("d"); break; case RTDIRENTRYTYPE_DEV_BLOCK: RTPrintf("b"); break; case RTDIRENTRYTYPE_FILE: RTPrintf("-"); break; case RTDIRENTRYTYPE_SYMLINK: RTPrintf("l"); break; case RTDIRENTRYTYPE_SOCKET: RTPrintf("s"); break; case RTDIRENTRYTYPE_WHITEOUT: RTPrintf("w"); break; default: rcRet = 1; RTPrintf("?"); break; } RTPrintf(" %#18llx %3d %s\n", (uint64_t)DirEntry.INodeId, DirEntry.cbName, DirEntry.szName); } } else { for (;;) { RTDIRENTRYEX DirEntry; rc = RTDirReadEx(pDir, &DirEntry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); if (RT_FAILURE(rc)) break; RTFMODE fMode = DirEntry.Info.Attr.fMode; switch (fMode & RTFS_TYPE_MASK) { case RTFS_TYPE_FIFO: RTPrintf("f"); break; case RTFS_TYPE_DEV_CHAR: RTPrintf("c"); break; case RTFS_TYPE_DIRECTORY: RTPrintf("d"); break; case RTFS_TYPE_DEV_BLOCK: RTPrintf("b"); break; case RTFS_TYPE_FILE: RTPrintf("-"); break; case RTFS_TYPE_SYMLINK: RTPrintf("l"); break; case RTFS_TYPE_SOCKET: RTPrintf("s"); break; case RTFS_TYPE_WHITEOUT: RTPrintf("w"); break; default: rcRet = 1; RTPrintf("?"); break; } /** @todo sticy bits++ */ RTPrintf("%c%c%c", fMode & RTFS_UNIX_IRUSR ? 'r' : '-', fMode & RTFS_UNIX_IWUSR ? 'w' : '-', fMode & RTFS_UNIX_IXUSR ? 'x' : '-'); RTPrintf("%c%c%c", fMode & RTFS_UNIX_IRGRP ? 'r' : '-', fMode & RTFS_UNIX_IWGRP ? 'w' : '-', fMode & RTFS_UNIX_IXGRP ? 'x' : '-'); RTPrintf("%c%c%c", fMode & RTFS_UNIX_IROTH ? 'r' : '-', fMode & RTFS_UNIX_IWOTH ? 'w' : '-', fMode & RTFS_UNIX_IXOTH ? 'x' : '-'); RTPrintf(" %c%c%c%c%c%c%c%c%c%c%c%c%c%c", fMode & RTFS_DOS_READONLY ? 'R' : '-', fMode & RTFS_DOS_HIDDEN ? 'H' : '-', fMode & RTFS_DOS_SYSTEM ? 'S' : '-', fMode & RTFS_DOS_DIRECTORY ? 'D' : '-', fMode & RTFS_DOS_ARCHIVED ? 'A' : '-', fMode & RTFS_DOS_NT_DEVICE ? 'd' : '-', fMode & RTFS_DOS_NT_NORMAL ? 'N' : '-', fMode & RTFS_DOS_NT_TEMPORARY ? 'T' : '-', fMode & RTFS_DOS_NT_SPARSE_FILE ? 'P' : '-', fMode & RTFS_DOS_NT_REPARSE_POINT ? 'J' : '-', fMode & RTFS_DOS_NT_COMPRESSED ? 'C' : '-', fMode & RTFS_DOS_NT_OFFLINE ? 'O' : '-', fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-', fMode & RTFS_DOS_NT_ENCRYPTED ? 'E' : '-'); RTPrintf(" %d %4d %4d %10lld %10lld %#llx %#llx %#llx %#llx", DirEntry.Info.Attr.u.Unix.cHardlinks, DirEntry.Info.Attr.u.Unix.uid, DirEntry.Info.Attr.u.Unix.gid, DirEntry.Info.cbObject, DirEntry.Info.cbAllocated, DirEntry.Info.BirthTime, DirEntry.Info.ChangeTime, DirEntry.Info.ModificationTime, DirEntry.Info.AccessTime); if (fShortName && DirEntry.cwcShortName) RTPrintf(" %2d %ls\n", DirEntry.cwcShortName, DirEntry.wszShortName); else RTPrintf(" %2d %s\n", DirEntry.cbName, DirEntry.szName); if (rc != VINF_SUCCESS) RTPrintf("^^ %Rrc\n", rc); } } if (rc != VERR_NO_MORE_FILES) { RTPrintf("tstDir: Enumeration failed! rc=%Rrc\n", rc); rcRet = 1; } /* close up */ rc = RTDirClose(pDir); if (RT_FAILURE(rc)) { RTPrintf("tstDir: Failed to close dir! rc=%Rrc\n", rc); rcRet = 1; } } else { RTPrintf("tstDir: Failed to open '%s', rc=%Rrc\n", argv[i], rc); rcRet = 1; } } } return rcRet; }
/** * Corrects the casing of the final component * * @returns * @param pClient . * @param pszFullPath . * @param pszStartComponent . */ static int vbsfCorrectCasing(SHFLCLIENTDATA *pClient, char *pszFullPath, char *pszStartComponent) { Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent)); AssertReturn((uintptr_t)pszFullPath < (uintptr_t)pszStartComponent - 1U, VERR_INTERNAL_ERROR_2); AssertReturn(pszStartComponent[-1] == RTPATH_DELIMITER, VERR_INTERNAL_ERROR_5); /* * Allocate a buffer that can hold really long file name entries as well as * the initial search pattern. */ size_t cchComponent = strlen(pszStartComponent); size_t cchParentDir = pszStartComponent - pszFullPath; size_t cchFullPath = cchParentDir + cchComponent; Assert(strlen(pszFullPath) == cchFullPath); size_t cbDirEntry = 4096; if (cchFullPath + 4 > cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName)) cbDirEntry = RT_OFFSETOF(RTDIRENTRYEX, szName) + cchFullPath + 4; PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry); if (pDirEntry == NULL) return VERR_NO_MEMORY; /* * Construct the search criteria in the szName member of pDirEntry. */ /** @todo This is quite inefficient, especially for directories with many * files. If any of the typically case sensitive host systems start * supporting opendir wildcard filters, it would make sense to build * one here with '?' for case foldable charaters. */ /** @todo Use RTDirOpen here and drop the whole uncessary path copying? */ int rc = RTPathJoinEx(pDirEntry->szName, cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName), pszFullPath, cchParentDir, RT_STR_TUPLE("*")); AssertRC(rc); if (RT_SUCCESS(rc)) { RTDIR hSearch = NULL; rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0 /*fFlags*/); if (RT_SUCCESS(rc)) { for (;;) { size_t cbDirEntrySize = cbDirEntry; rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient)); if (rc == VERR_NO_MORE_FILES) break; if ( rc != VINF_SUCCESS && rc != VWRN_NO_DIRENT_INFO) { if ( rc == VERR_NO_TRANSLATION || rc == VERR_INVALID_UTF8_ENCODING) continue; AssertMsgFailed(("%Rrc\n", rc)); break; } Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0])); if ( pDirEntry->cbName == cchComponent && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0])) { Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent)); strcpy(pszStartComponent, &pDirEntry->szName[0]); rc = VINF_SUCCESS; break; } } RTDirClose(hSearch); } } if (RT_FAILURE(rc)) Log(("vbsfCorrectCasing %s failed with %Rrc\n", pszStartComponent, rc)); RTMemFree(pDirEntry); return rc; }
HRESULT VFSExplorer::i_updateFS(TaskVFSExplorer *aTask) { LogFlowFuncEnter(); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS); HRESULT rc = S_OK; std::list<VFSExplorer::Data::DirEntry> fileList; char *pszPath = NULL; PRTDIR pDir = NULL; try { int vrc = RTDirOpen(&pDir, m->strPath.c_str()); if (RT_FAILURE(vrc)) throw setError(VBOX_E_FILE_ERROR, tr ("Can't open directory '%s' (%Rrc)"), pszPath, vrc); if (aTask->progress) aTask->progress->SetCurrentOperationProgress(33); RTDIRENTRYEX entry; while (RT_SUCCESS(vrc)) { vrc = RTDirReadEx(pDir, &entry, NULL, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); if (RT_SUCCESS(vrc)) { Utf8Str name(entry.szName); if ( name != "." && name != "..") fileList.push_back(VFSExplorer::Data::DirEntry(name, i_RTToVFSFileType(entry.Info.Attr.fMode), entry.Info.cbObject, entry.Info.Attr.fMode & (RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO))); } } if (aTask->progress) aTask->progress->SetCurrentOperationProgress(66); } catch(HRESULT aRC) { rc = aRC; } /* Clean up */ if (pszPath) RTStrFree(pszPath); if (pDir) RTDirClose(pDir); if (aTask->progress) aTask->progress->SetCurrentOperationProgress(99); /* Assign the result on success (this clears the old list) */ if (rc == S_OK) m->entryList.assign(fileList.begin(), fileList.end()); aTask->rc = rc; if (!aTask->progress.isNull()) aTask->progress->i_notifyComplete(rc); LogFlowFunc(("rc=%Rhrc\n", rc)); LogFlowFuncLeave(); return VINF_SUCCESS; }
/** * Recursively delete a directory. * * @returns IPRT status code, errors go via rtPathRmError. * @param pOpts The RM options. * @param pszPath Pointer to a writable buffer holding the path to * the directory. * @param cchPath The length of the path (avoid strlen). * @param pDirEntry Pointer to a directory entry buffer that is * RTPATHRM_DIR_MAX_ENTRY_SIZE bytes big. */ static int rtPathRmRecursive(PRTPATHRMCMDOPTS pOpts, char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry) { /* * Make sure the path ends with a slash. */ if (!cchPath || !RTPATH_IS_SLASH(pszPath[cchPath - 1])) { if (cchPath + 1 >= RTPATH_MAX) return rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Buffer overflow fixing up '%s'.\n", pszPath); pszPath[cchPath++] = RTPATH_SLASH; pszPath[cchPath] = '\0'; } /* * Traverse the directory. */ PRTDIR hDir; int rc = RTDirOpen(&hDir, pszPath); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, "Error opening directory '%s': %Rrc", pszPath, rc); int rcRet = VINF_SUCCESS; for (;;) { /* * Read the next entry, constructing an full path for it. */ size_t cbEntry = RTPATHRM_DIR_MAX_ENTRY_SIZE; rc = RTDirReadEx(hDir, pDirEntry, &cbEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); if (rc == VERR_NO_MORE_FILES) { /* * Reached the end of the directory. */ pszPath[cchPath] = '\0'; rc = RTDirClose(hDir); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, "Error closing directory '%s': %Rrc", pszPath, rc); /* Delete the directory. */ int rc2 = rtPathRmOneDir(pOpts, pszPath); if (RT_FAILURE(rc2) && RT_SUCCESS(rcRet)) return rc2; return rcRet; } if (RT_FAILURE(rc)) { rc = rtPathRmError(pOpts, pszPath, rc, "Error reading directory '%s': %Rrc", pszPath, rc); break; } /* Skip '.' and '..'. */ if ( pDirEntry->szName[0] == '.' && ( pDirEntry->cbName == 1 || ( pDirEntry->cbName == 2 && pDirEntry->szName[1] == '.'))) continue; /* Construct full path. */ if (cchPath + pDirEntry->cbName >= RTPATH_MAX) { pszPath[cchPath] = '\0'; rc = rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Path buffer overflow in directory '%s'.", pszPath); break; } memcpy(pszPath + cchPath, pDirEntry->szName, pDirEntry->cbName + 1); /* * Take action according to the type. */ switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK) { case RTFS_TYPE_FILE: rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info); break; case RTFS_TYPE_DIRECTORY: rc = rtPathRmRecursive(pOpts, pszPath, cchPath + pDirEntry->cbName, pDirEntry); break; case RTFS_TYPE_SYMLINK: rc = rtPathRmOneSymlink(pOpts, pszPath); break; case RTFS_TYPE_FIFO: case RTFS_TYPE_DEV_CHAR: case RTFS_TYPE_DEV_BLOCK: case RTFS_TYPE_SOCKET: rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info); break; case RTFS_TYPE_WHITEOUT: default: rc = rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE, "Object '%s' has an unknown file type: %o\n", pszPath, pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK); break; } if (RT_FAILURE(rc) && RT_SUCCESS(rcRet)) rcRet = rc; } /* * Some error occured, close and return. */ RTDirClose(hDir); return rc; }
static ssize_t rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode, const char *pszBasePath, char *pszBuf, size_t cchBuf) { /* * Check assumptions made by the code below. */ size_t const cchBasePath = strlen(pszBasePath); AssertReturnStmt(cchBasePath < RTPATH_MAX - 10U, errno = ENAMETOOLONG, -1); ssize_t rcRet; PRTDIR pDir; int rc = RTDirOpen(&pDir, pszBasePath); if (RT_SUCCESS(rc)) { char szPath[RTPATH_MAX]; /** @todo 4K per recursion - can easily be optimized away by passing it along pszBasePath and only remember the length. */ memcpy(szPath, pszBasePath, cchBasePath + 1); for (;;) { RTDIRENTRYEX Entry; rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); if (RT_FAILURE(rc)) { errno = rc == VERR_NO_MORE_FILES ? ENOENT : rc == VERR_BUFFER_OVERFLOW ? EOVERFLOW : EIO; rcRet = -1; break; } if (RTFS_IS_SYMLINK(Entry.Info.Attr.fMode)) continue; /* Do the matching. */ if ( Entry.Info.Attr.u.Unix.Device == DevNum && (Entry.Info.Attr.fMode & RTFS_TYPE_MASK) == fMode) { rcRet = rtLinuxConstructPath(pszBuf, cchBuf, pszBasePath, "%s", Entry.szName); break; } /* Recurse into subdirectories. */ if (!RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)) continue; if (Entry.szName[0] == '.') continue; szPath[cchBasePath] = '\0'; rc = RTPathAppend(szPath, sizeof(szPath) - 1, Entry.szName); /* -1: for slash */ if (RT_FAILURE(rc)) { errno = ENAMETOOLONG; rcRet = -1; break; } strcat(&szPath[cchBasePath], "/"); rcRet = rtLinuxFindDevicePathRecursive(DevNum, fMode, szPath, pszBuf, cchBuf); if (rcRet >= 0 || errno != ENOENT) break; } RTDirClose(pDir); } else { rcRet = -1; errno = RTErrConvertToErrno(rc); } return rcRet; }