/** * Check whether a device node points to a valid device and create a UDI and * a description for it, and store the device number, if it does. * @returns true if the device is valid, false otherwise * @param pcszNode the path to the device node * @param isDVD are we looking for a DVD device (or a floppy device)? * @param pDevice where to store the device node (optional) * @param pszDesc where to store the device description (optional) * @param cchDesc the size of the buffer in @a pszDesc * @param pszUdi where to store the device UDI (optional) * @param cchUdi the size of the buffer in @a pszUdi */ static bool devValidateDevice(const char *pcszNode, bool isDVD, dev_t *pDevice, char *pszDesc, size_t cchDesc, char *pszUdi, size_t cchUdi) { AssertPtrReturn(pcszNode, false); AssertPtrNullReturn(pDevice, false); AssertPtrNullReturn(pszDesc, false); AssertReturn(!pszDesc || cchDesc > 0, false); AssertPtrNullReturn(pszUdi, false); AssertReturn(!pszUdi || cchUdi > 0, false); RTFSOBJINFO ObjInfo; if (RT_FAILURE(RTPathQueryInfo(pcszNode, &ObjInfo, RTFSOBJATTRADD_UNIX))) return false; if (!RTFS_IS_DEV_BLOCK(ObjInfo.Attr.fMode)) return false; if (pDevice) *pDevice = ObjInfo.Attr.u.Unix.Device; if (isDVD) { char szVendor[128], szModel[128]; uint8_t u8Type; if (!isCdromDevNum(ObjInfo.Attr.u.Unix.Device)) return false; if (RT_FAILURE(cdromDoInquiry(pcszNode, &u8Type, szVendor, sizeof(szVendor), szModel, sizeof(szModel)))) return false; if (u8Type != TYPE_ROM) return false; dvdCreateDeviceStrings(szVendor, szModel, pszDesc, cchDesc, pszUdi, cchUdi); } else { /* Floppies on Linux are legacy devices with hardcoded majors and * minors */ unsigned Number; floppy_drive_name szName; if (major(ObjInfo.Attr.u.Unix.Device) != FLOPPY_MAJOR) return false; switch (minor(ObjInfo.Attr.u.Unix.Device)) { case 0: case 1: case 2: case 3: Number = minor(ObjInfo.Attr.u.Unix.Device); break; case 128: case 129: case 130: case 131: Number = minor(ObjInfo.Attr.u.Unix.Device) - 128 + 4; break; default: return false; } if (!floppyGetName(pcszNode, Number, szName)) return false; floppyCreateDeviceStrings(szName, Number, pszDesc, cchDesc, pszUdi, cchUdi); } return true; }
static void benchmarkPathQueryInfo(void) { RTTestSub(g_hTest, "RTPathQueryInfo"); RTFSOBJINFO ObjInfo; RTTESTI_CHECK_RC_RETV(RTPathQueryInfo(g_szNotExitingFile, &ObjInfo, RTFSOBJATTRADD_NOTHING), VERR_FILE_NOT_FOUND); TIME_OP(RTPathQueryInfo(g_szNotExitingFile, &ObjInfo, RTFSOBJATTRADD_NOTHING), "RTPathQueryInfo(g_szNotExitingFile)"); int rc = RTPathQueryInfo(g_szNotExitingDirFile, &ObjInfo, RTFSOBJATTRADD_NOTHING); RTTESTI_CHECK_RETV(rc == VERR_PATH_NOT_FOUND || VERR_FILE_NOT_FOUND); TIME_OP(RTPathQueryInfo(g_szNotExitingDirFile, &ObjInfo, RTFSOBJATTRADD_NOTHING), "RTPathQueryInfo(g_szNotExitingDirFile)"); RTTESTI_CHECK_RC_RETV(RTPathQueryInfo(g_pszTestDir, &ObjInfo, RTFSOBJATTRADD_NOTHING), VINF_SUCCESS); TIME_OP(RTPathQueryInfo(g_pszTestDir, &ObjInfo, RTFSOBJATTRADD_NOTHING), "RTPathQueryInfo(g_pszTestDir)"); RTTESTI_CHECK_RC_RETV(RTPathQueryInfo(g_pszTestDir, &ObjInfo, RTFSOBJATTRADD_UNIX), VINF_SUCCESS); TIME_OP(RTPathQueryInfo(g_pszTestDir, &ObjInfo, RTFSOBJATTRADD_UNIX), "RTPathQueryInfo(g_pszTestDir,UNIX)"); RTTestSubDone(g_hTest); }
RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, const char *pszSuggestion, va_list va) { AssertReturnStmt(cchBuf >= 2, errno = EINVAL, -1); AssertReturnStmt( fMode == RTFS_TYPE_DEV_CHAR || fMode == RTFS_TYPE_DEV_BLOCK, errno = EINVAL, -1); if (pszSuggestion) { /* * Construct the filename and read the link. */ char szFilename[RTPATH_MAX]; int rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", pszSuggestion, va); if (rc == -1) return -1; /* * Check whether the caller's suggestion was right. */ RTFSOBJINFO Info; rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX); if ( RT_SUCCESS(rc) && Info.Attr.u.Unix.Device == DevNum && (Info.Attr.fMode & RTFS_TYPE_MASK) == fMode) { size_t cchPath = strlen(szFilename); if (cchPath >= cchBuf) { errno = EOVERFLOW; return -1; } memcpy(pszBuf, szFilename, cchPath + 1); return cchPath; } /* The suggestion was wrong, fall back on the brute force attack. */ } return rtLinuxFindDevicePathRecursive(DevNum, fMode, "/dev/", pszBuf, cchBuf); }
RTDECL(ssize_t) RTLinuxCheckDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, const char *pszPattern, va_list va) { char szFilename[RTPATH_MAX]; int rc = VINF_TRY_AGAIN; AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER); AssertReturn( fMode == RTFS_TYPE_DEV_CHAR || fMode == RTFS_TYPE_DEV_BLOCK, VERR_INVALID_PARAMETER); if (pszPattern) { /* * Construct the filename and read the link. */ rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", pszPattern, va); if (rc > 0) { RTFSOBJINFO Info; rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX); if ( rc == VERR_PATH_NOT_FOUND || ( RT_SUCCESS(rc) && ( Info.Attr.u.Unix.Device != DevNum || (Info.Attr.fMode & RTFS_TYPE_MASK) != fMode))) rc = VERR_FILE_NOT_FOUND; } } if (RT_SUCCESS(rc)) { size_t cchPath = strlen(szFilename); if (cchPath >= cchBuf) return VERR_BUFFER_OVERFLOW; memcpy(pszBuf, szFilename, cchPath + 1); return cchPath; } return rc; }
static void test1Worker(RTTEST hTest, const char *pszBaseDir, const char *pszTarget, RTSYMLINKTYPE enmType, bool fDangling) { char szPath1[RTPATH_MAX]; char szPath2[RTPATH_MAX]; size_t cchTarget = strlen(pszTarget); char szPath3[RTPATH_MAX]; RTStrCopy(szPath3, sizeof(szPath3), pszTarget); #ifdef RT_OS_WINDOWS /* see RTSymlinkCreate in symlink-win.cpp */ char c; char *psz = szPath3; while ((c = *psz) != '\0') { if (c == '/') *psz = '\\'; psz++; } #endif /* Create it.*/ RTTESTI_CHECK_RC_OK_RETV(RTPathJoin(szPath1, sizeof(szPath1), pszBaseDir, "tstRTSymlink-link-1")); RTSymlinkDelete(szPath1, 0); /* clean up previous run */ RTTESTI_CHECK_RC_RETV(RTSymlinkCreate(szPath1, pszTarget, RTSYMLINKTYPE_FILE, 0), VINF_SUCCESS); /* Check the predicate functions. */ RTTESTI_CHECK(RTSymlinkExists(szPath1)); RTTESTI_CHECK(RTSymlinkIsDangling(szPath1) == fDangling); /* Read it. */ memset(szPath2, 0xff, sizeof(szPath2)); szPath2[sizeof(szPath2) - 1] = '\0'; RTTESTI_CHECK_RC(RTSymlinkRead(szPath1, szPath2, sizeof(szPath2), 0), VINF_SUCCESS); RTTESTI_CHECK_MSG(strcmp(szPath2, szPath3) == 0, ("got=\"%s\" expected=\"%s\"", szPath2, szPath3)); memset(szPath2, 0xff, sizeof(szPath2)); szPath2[sizeof(szPath2) - 1] = '\0'; RTTESTI_CHECK_RC(RTSymlinkRead(szPath1, szPath2, cchTarget + 1, 0), VINF_SUCCESS); RTTESTI_CHECK_MSG(strcmp(szPath2, szPath3) == 0, ("got=\"%s\" expected=\"%s\"", szPath2, szPath3)); memset(szPath2, 0xff, sizeof(szPath2)); szPath2[sizeof(szPath2) - 1] = '\0'; RTTESTI_CHECK_RC(RTSymlinkRead(szPath1, szPath2, cchTarget, 0), VERR_BUFFER_OVERFLOW); RTTESTI_CHECK_MSG( strncmp(szPath2, szPath3, cchTarget - 1) == 0 && szPath2[cchTarget - 1] == '\0', ("got=\"%s\" expected=\"%.*s\"", szPath2, cchTarget - 1, szPath3)); /* Other APIs that have to handle symlinks carefully. */ int rc; RTFSOBJINFO ObjInfo; RTTESTI_CHECK_RC(rc = RTPathQueryInfo(szPath1, &ObjInfo, RTFSOBJATTRADD_NOTHING), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTESTI_CHECK(RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)); RTTESTI_CHECK_RC(rc = RTPathQueryInfoEx(szPath1, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTESTI_CHECK(RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)); if (!fDangling) { RTTESTI_CHECK_RC(rc = RTPathQueryInfoEx(szPath1, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTESTI_CHECK(!RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)); else RT_ZERO(ObjInfo); if (enmType == RTSYMLINKTYPE_DIR) { RTTESTI_CHECK(RTDirExists(szPath1)); RTTESTI_CHECK(RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode)); } else if (enmType == RTSYMLINKTYPE_FILE) { RTTESTI_CHECK(RTFileExists(szPath1)); RTTESTI_CHECK(RTFS_IS_FILE(ObjInfo.Attr.fMode)); } /** @todo Check more APIs */ } /* Finally, the removal of the symlink. */ RTTESTI_CHECK_RC(RTSymlinkDelete(szPath1, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(RTSymlinkDelete(szPath1, 0), VERR_FILE_NOT_FOUND); }
/** * Recursive worker function to walk the /dev tree looking for DVD or floppy * devices. * @returns true if we have already found MAX_DEVICE_NODES devices, false * otherwise * @param pszPath the path to start recursing. The function can modify * this string at and after the terminating zero * @param cchPath the size of the buffer (not the string!) in @a pszPath * @param aDevices where to fill in information about devices that we have * found * @param wantDVD are we looking for DVD devices (or floppies)? */ static bool devFindDeviceRecursive(char *pszPath, size_t cchPath, deviceNodeArray aDevices, bool wantDVD) { /* * Check assumptions made by the code below. */ size_t const cchBasePath = strlen(pszPath); AssertReturn(cchBasePath < RTPATH_MAX - 10U, false); AssertReturn(pszPath[cchBasePath - 1] != '/', false); PRTDIR pDir; if (RT_FAILURE(RTDirOpen(&pDir, pszPath))) return false; for (;;) { RTDIRENTRY Entry; RTFSOBJINFO ObjInfo; int rc = RTDirRead(pDir, &Entry, NULL); if (RT_FAILURE(rc)) break; if (Entry.enmType == RTDIRENTRYTYPE_UNKNOWN) { if (RT_FAILURE(RTPathQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX))) continue; if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) continue; } if (Entry.enmType == RTDIRENTRYTYPE_SYMLINK) continue; pszPath[cchBasePath] = '\0'; if (RT_FAILURE(RTPathAppend(pszPath, cchPath, Entry.szName))) break; /* Do the matching. */ dev_t DevNode; char szDesc[256], szUdi[256]; if (!devValidateDevice(pszPath, wantDVD, &DevNode, szDesc, sizeof(szDesc), szUdi, sizeof(szUdi))) continue; unsigned i; for (i = 0; i < MAX_DEVICE_NODES; ++i) if (!aDevices[i].Device || (aDevices[i].Device == DevNode)) break; AssertBreak(i < MAX_DEVICE_NODES); if (aDevices[i].Device) continue; aDevices[i].Device = DevNode; RTStrPrintf(aDevices[i].szPath, sizeof(aDevices[i].szPath), "%s", pszPath); AssertCompile(sizeof(aDevices[i].szDesc) == sizeof(szDesc)); strcpy(aDevices[i].szDesc, szDesc); AssertCompile(sizeof(aDevices[i].szUdi) == sizeof(szUdi)); strcpy(aDevices[i].szUdi, szUdi); if (i == MAX_DEVICE_NODES - 1) break; continue; /* Recurse into subdirectories. */ if ( (Entry.enmType == RTDIRENTRYTYPE_UNKNOWN) && !RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode)) continue; if (Entry.enmType != RTDIRENTRYTYPE_DIRECTORY) continue; if (Entry.szName[0] == '.') continue; if (devFindDeviceRecursive(pszPath, cchPath, aDevices, wantDVD)) break; } RTDirClose(pDir); return aDevices[MAX_DEVICE_NODES - 1].Device ? true : false; }
int DnDURIList::appendPathRecursive(const char *pcszPath, size_t cbBaseLen, uint32_t fFlags) { AssertPtrReturn(pcszPath, VERR_INVALID_POINTER); RTFSOBJINFO objInfo; int rc = RTPathQueryInfo(pcszPath, &objInfo, RTFSOBJATTRADD_NOTHING); if (RT_FAILURE(rc)) return rc; /* * These are the types we currently support. Symlinks are not directly * supported. First the guest could be an OS which doesn't support it and * second the symlink could point to a file which is out of the base tree. * Both things are hard to support. For now we just copy the target file in * this case. */ if (!( RTFS_IS_DIRECTORY(objInfo.Attr.fMode) || RTFS_IS_FILE(objInfo.Attr.fMode) || RTFS_IS_SYMLINK(objInfo.Attr.fMode))) return VINF_SUCCESS; uint64_t cbSize = 0; rc = RTFileQuerySize(pcszPath, &cbSize); if (rc == VERR_IS_A_DIRECTORY) rc = VINF_SUCCESS; if (RT_FAILURE(rc)) return rc; m_lstTree.append(DnDURIObject( RTFS_IS_DIRECTORY(objInfo.Attr.fMode) ? DnDURIObject::Directory : DnDURIObject::File, pcszPath, &pcszPath[cbBaseLen], objInfo.Attr.fMode, cbSize)); m_cbTotal += cbSize; #ifdef DEBUG_andy LogFlowFunc(("strSrcPath=%s, strDstPath=%s, fMode=0x%x, cbSize=%RU64, cbTotal=%zu\n", pcszPath, &pcszPath[cbBaseLen], objInfo.Attr.fMode, cbSize, m_cbTotal)); #endif PRTDIR hDir; /* We have to try to open even symlinks, cause they could * be symlinks to directories. */ rc = RTDirOpen(&hDir, pcszPath); /* The following error happens when this was a symlink * to an file or a regular file. */ if ( rc == VERR_PATH_NOT_FOUND || rc == VERR_NOT_A_DIRECTORY) return VINF_SUCCESS; if (RT_FAILURE(rc)) return rc; while (RT_SUCCESS(rc)) { RTDIRENTRY DirEntry; rc = RTDirRead(hDir, &DirEntry, NULL); if (RT_FAILURE(rc)) { if (rc == VERR_NO_MORE_FILES) rc = VINF_SUCCESS; break; } switch (DirEntry.enmType) { case RTDIRENTRYTYPE_DIRECTORY: { /* Skip "." and ".." entries. */ if ( RTStrCmp(DirEntry.szName, ".") == 0 || RTStrCmp(DirEntry.szName, "..") == 0) break; char *pszRecDir = RTPathJoinA(pcszPath, DirEntry.szName); if (pszRecDir) { rc = appendPathRecursive(pszRecDir, cbBaseLen, fFlags); RTStrFree(pszRecDir); } else rc = VERR_NO_MEMORY; break; } case RTDIRENTRYTYPE_SYMLINK: case RTDIRENTRYTYPE_FILE: { char *pszNewFile = RTPathJoinA(pcszPath, DirEntry.szName); if (pszNewFile) { /* We need the size and the mode of the file. */ RTFSOBJINFO objInfo1; rc = RTPathQueryInfo(pszNewFile, &objInfo1, RTFSOBJATTRADD_NOTHING); if (RT_FAILURE(rc)) return rc; rc = RTFileQuerySize(pszNewFile, &cbSize); if (rc == VERR_IS_A_DIRECTORY) /* Happens for symlinks. */ rc = VINF_SUCCESS; if (RT_FAILURE(rc)) break; if (RTFS_IS_FILE(objInfo.Attr.fMode)) { m_lstTree.append(DnDURIObject(DnDURIObject::File, pszNewFile, &pszNewFile[cbBaseLen], objInfo1.Attr.fMode, cbSize)); m_cbTotal += cbSize; } else /* Handle symlink directories. */ rc = appendPathRecursive(pszNewFile, cbBaseLen, fFlags); #ifdef DEBUG_andy LogFlowFunc(("strSrcPath=%s, strDstPath=%s, fMode=0x%x, cbSize=%RU64, cbTotal=%zu\n", pszNewFile, &pszNewFile[cbBaseLen], objInfo1.Attr.fMode, cbSize, m_cbTotal)); #endif RTStrFree(pszNewFile); } else rc = VERR_NO_MEMORY; break; } default: break; } } RTDirClose(hDir); return rc; }
int DnDURIList::addEntry(const char *pcszSource, const char *pcszTarget, uint32_t fFlags) { AssertPtrReturn(pcszSource, VERR_INVALID_POINTER); AssertPtrReturn(pcszTarget, VERR_INVALID_POINTER); LogFlowFunc(("pcszSource=%s, pcszTarget=%s, fFlags=0x%x\n", pcszSource, pcszTarget, fFlags)); RTFSOBJINFO objInfo; int rc = RTPathQueryInfo(pcszSource, &objInfo, RTFSOBJATTRADD_NOTHING); if (RT_SUCCESS(rc)) { if (RTFS_IS_FILE(objInfo.Attr.fMode)) { LogFlowFunc(("File '%s' -> '%s' (%RU64 bytes, file mode 0x%x)\n", pcszSource, pcszTarget, (uint64_t)objInfo.cbObject, objInfo.Attr.fMode)); DnDURIObject *pObjFile = new DnDURIObject(DnDURIObject::File, pcszSource, pcszTarget); if (pObjFile) { if (fFlags & DNDURILIST_FLAGS_KEEP_OPEN) /* Shall we keep the file open while being added to this list? */ { /** @todo Add a standard fOpen mode for this list. */ rc = pObjFile->Open(DnDURIObject::Source, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, objInfo.Attr.fMode); } if (RT_SUCCESS(rc)) { m_lstTree.append(pObjFile); m_cTotal++; m_cbTotal += pObjFile->GetSize(); } else delete pObjFile; } else rc = VERR_NO_MEMORY; } else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) { LogFlowFunc(("Directory '%s' -> '%s' (file mode 0x%x)\n", pcszSource, pcszTarget, objInfo.Attr.fMode)); DnDURIObject *pObjDir = new DnDURIObject(DnDURIObject::Directory, pcszSource, pcszTarget, objInfo.Attr.fMode, 0 /* Size */); if (pObjDir) { m_lstTree.append(pObjDir); /** @todo Add DNDURILIST_FLAGS_KEEP_OPEN handling? */ m_cTotal++; } else rc = VERR_NO_MEMORY; } /* Note: Symlinks already should have been resolved at this point. */ else rc = VERR_NOT_SUPPORTED; } LogFlowFuncLeaveRC(rc); return rc; }
int DnDURIList::appendPathRecursive(const char *pcszSrcPath, const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase, uint32_t fFlags) { AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER); AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER); AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER); LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu\n", pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase)); RTFSOBJINFO objInfo; int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING); if (RT_SUCCESS(rc)) { if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) { rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags); if (RT_SUCCESS(rc)) { PRTDIR hDir; rc = RTDirOpen(&hDir, pcszSrcPath); if (RT_SUCCESS(rc)) { do { RTDIRENTRY DirEntry; rc = RTDirRead(hDir, &DirEntry, NULL); if (RT_FAILURE(rc)) { if (rc == VERR_NO_MORE_FILES) rc = VINF_SUCCESS; break; } switch (DirEntry.enmType) { case RTDIRENTRYTYPE_DIRECTORY: { /* Skip "." and ".." entries. */ if ( RTStrCmp(DirEntry.szName, ".") == 0 || RTStrCmp(DirEntry.szName, "..") == 0) break; char *pszSrc = RTPathJoinA(pcszSrcPath, DirEntry.szName); if (pszSrc) { char *pszDst = RTPathJoinA(pcszDstPath, DirEntry.szName); if (pszDst) { rc = appendPathRecursive(pszSrc, pszDst, pcszDstBase, cchDstBase, fFlags); RTStrFree(pszDst); } else rc = VERR_NO_MEMORY; RTStrFree(pszSrc); } else rc = VERR_NO_MEMORY; break; } case RTDIRENTRYTYPE_FILE: { char *pszSrc = RTPathJoinA(pcszSrcPath, DirEntry.szName); if (pszSrc) { char *pszDst = RTPathJoinA(pcszDstPath, DirEntry.szName); if (pszDst) { rc = addEntry(pszSrc, &pszDst[cchDstBase], fFlags); RTStrFree(pszDst); } else rc = VERR_NO_MEMORY; RTStrFree(pszSrc); } else rc = VERR_NO_MEMORY; break; } case RTDIRENTRYTYPE_SYMLINK: { if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS) { char *pszSrc = RTPathRealDup(pcszDstBase); if (pszSrc) { rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING); if (RT_SUCCESS(rc)) { if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) { LogFlowFunc(("Directory entry is symlink to directory\n")); rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags); } else if (RTFS_IS_FILE(objInfo.Attr.fMode)) { LogFlowFunc(("Directory entry is symlink to file\n")); rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags); } else rc = VERR_NOT_SUPPORTED; } RTStrFree(pszSrc); } else rc = VERR_NO_MEMORY; } break; } default: break; } } while (RT_SUCCESS(rc)); RTDirClose(hDir); } } } else if (RTFS_IS_FILE(objInfo.Attr.fMode)) { rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags); } else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode)) { if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS) { char *pszSrc = RTPathRealDup(pcszSrcPath); if (pszSrc) { rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING); if (RT_SUCCESS(rc)) { if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) { LogFlowFunc(("Symlink to directory\n")); rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags); } else if (RTFS_IS_FILE(objInfo.Attr.fMode)) { LogFlowFunc(("Symlink to file\n")); rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags); } else rc = VERR_NOT_SUPPORTED; } RTStrFree(pszSrc); } else rc = VERR_NO_MEMORY; } } else rc = VERR_NOT_SUPPORTED; } LogFlowFuncLeaveRC(rc); return rc; }
int DnDHGSendDataMessage::buildFileTree(const char *pcszPath, size_t cbBaseLen) { RTFSOBJINFO objInfo; int rc = RTPathQueryInfo(pcszPath, &objInfo, RTFSOBJATTRADD_NOTHING); if (RT_FAILURE(rc)) return rc; /* These are the types we currently support. Symlinks are not directly * supported. First the guest could be an OS which doesn't support it and * second the symlink could point to a file which is out of the base tree. * Both things are hard to support. For now we just copy the target file in * this case. */ if (!( RTFS_IS_DIRECTORY(objInfo.Attr.fMode) || RTFS_IS_FILE(objInfo.Attr.fMode) || RTFS_IS_SYMLINK(objInfo.Attr.fMode))) return VINF_SUCCESS; uint64_t cbSize = 0; rc = RTFileQuerySize(pcszPath, &cbSize); if (rc == VERR_IS_A_DIRECTORY) rc = VINF_SUCCESS; if (RT_FAILURE(rc)) return rc; m_uriList.append(PathEntry(pcszPath, &pcszPath[cbBaseLen], objInfo.Attr.fMode, cbSize)); m_cbAll += cbSize; DO(("cbFile: %u\n", cbSize)); PRTDIR hDir; /* We have to try to open even symlinks, cause they could be symlinks * to directories. */ rc = RTDirOpen(&hDir, pcszPath); /* The following error happens when this was a symlink to an file or a * regular file. */ if (rc == VERR_PATH_NOT_FOUND) return VINF_SUCCESS; if (RT_FAILURE(rc)) return rc; while (RT_SUCCESS(rc)) { RTDIRENTRY DirEntry; rc = RTDirRead(hDir, &DirEntry, NULL); if (RT_FAILURE(rc)) { if (rc == VERR_NO_MORE_FILES) rc = VINF_SUCCESS; break; } switch (DirEntry.enmType) { case RTDIRENTRYTYPE_DIRECTORY: { /* Skip "." and ".." entries. */ if ( RTStrCmp(DirEntry.szName, ".") == 0 || RTStrCmp(DirEntry.szName, "..") == 0) break; if (char *pszRecDir = RTStrAPrintf2("%s%c%s", pcszPath, RTPATH_DELIMITER, DirEntry.szName)) { rc = buildFileTree(pszRecDir, cbBaseLen); RTStrFree(pszRecDir); } else rc = VERR_NO_MEMORY; break; } case RTDIRENTRYTYPE_SYMLINK: case RTDIRENTRYTYPE_FILE: { if (char *pszNewFile = RTStrAPrintf2("%s%c%s", pcszPath, RTPATH_DELIMITER, DirEntry.szName)) { /* We need the size and the mode of the file. */ RTFSOBJINFO objInfo1; rc = RTPathQueryInfo(pszNewFile, &objInfo1, RTFSOBJATTRADD_NOTHING); if (RT_FAILURE(rc)) return rc; rc = RTFileQuerySize(pszNewFile, &cbSize); if (RT_FAILURE(rc)) break; m_uriList.append(PathEntry(pszNewFile, &pszNewFile[cbBaseLen], objInfo1.Attr.fMode, cbSize)); m_cbAll += cbSize; RTStrFree(pszNewFile); } else rc = VERR_NO_MEMORY; break; } default: break; } } RTDirClose(hDir); return rc; }