/** * Constructs a local (unix) domain socket name. * * @returns IPRT status code. * @param pAddr The address structure to construct the name in. * @param pcbAddr Where to return the address size. * @param pszName The user specified name (valid). * @param fNative Whether it's a native name or a portable name. */ static int rtLocalIpcPosixConstructName(struct sockaddr_un *pAddr, uint8_t *pcbAddr, const char *pszName, bool fNative) { const char *pszNativeName; int rc = rtPathToNative(&pszNativeName, pszName, NULL /*pszBasePath not support*/); if (RT_SUCCESS(rc)) { size_t cchNativeName = strlen(pszNativeName); size_t cbFull = !fNative ? cchNativeName + sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) : cchNativeName + 1; if (cbFull <= sizeof(pAddr->sun_path)) { RT_ZERO(*pAddr); #ifdef RT_OS_OS2 /* Size must be exactly right on OS/2. */ *pcbAddr = sizeof(*pAddr); #else *pcbAddr = RT_OFFSETOF(struct sockaddr_un, sun_path) + (uint8_t)cbFull; #endif #ifdef HAVE_SUN_LEN_MEMBER pAddr->sun_len = *pcbAddr; #endif pAddr->sun_family = AF_LOCAL; if (!fNative) { memcpy(pAddr->sun_path, RTLOCALIPC_POSIX_NAME_PREFIX, sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) - 1); memcpy(&pAddr->sun_path[sizeof(RTLOCALIPC_POSIX_NAME_PREFIX) - 1], pszNativeName, cchNativeName + 1); } else memcpy(pAddr->sun_path, pszNativeName, cchNativeName + 1); } else
RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags) { /* * Validate input. */ AssertPtrReturn(pszPath, false); AssertReturn(*pszPath, false); Assert(RTPATH_F_IS_VALID(fFlags, 0)); /* * Convert the path and check if it exists using stat(). */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { struct stat Stat; if (fFlags & RTPATH_F_FOLLOW_LINK) rc = stat(pszNativePath, &Stat); else rc = lstat(pszNativePath, &Stat); if (!rc) rc = VINF_SUCCESS; else rc = VERR_GENERAL_FAILURE; rtPathFreeNative(pszNativePath, pszPath); } return RT_SUCCESS(rc); }
RTR3DECL(int) RTPathSetMode(const char *pszPath, RTFMODE fMode) { AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); int rc; fMode = rtFsModeNormalize(fMode, pszPath, 0); if (rtFsModeIsValidPermissions(fMode)) { char const *pszNativePath; rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { if (chmod(pszNativePath, fMode & RTFS_UNIX_MASK) != 0) rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativePath, pszPath); } } else { AssertMsgFailed(("Invalid file mode! %RTfmode\n", fMode)); rc = VERR_INVALID_FMODE; } return rc; }
int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf) { NOREF(pszPathBuf); /* only used on windows */ /* * Convert to a native path and try opendir. */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pDir->pszPath, NULL); if (RT_SUCCESS(rc)) { pDir->pDir = opendir(pszNativePath); if (pDir->pDir) { /* * Init data. */ pDir->fDataUnread = false; memset(&pDir->Data, 0, RT_OFFSETOF(RTDIR, Data.d_name)); /* not strictly necessary */ memset(&pDir->Data.d_name[0], 0, pDir->cbMaxName); } else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativePath, pDir->pszPath); } return rc; }
RTDECL(int) RTSymlinkDelete(const char *pszSymlink, uint32_t fDelete) { char const *pszNativeSymlink; int rc = rtPathToNative(&pszNativeSymlink, pszSymlink, NULL); if (RT_SUCCESS(rc)) { struct stat s; if (!lstat(pszNativeSymlink, &s)) { if (S_ISLNK(s.st_mode)) { if (unlink(pszNativeSymlink) == 0) rc = VINF_SUCCESS; else rc = RTErrConvertFromErrno(errno); } else rc = VERR_NOT_SYMLINK; } else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativeSymlink, pszSymlink); } LogFlow(("RTSymlinkDelete(%p={%s}, #%x): returns %Rrc\n", pszSymlink, pszSymlink, fDelete, rc)); return rc; }
RTDECL(bool) RTSymlinkIsDangling(const char *pszSymlink) { bool fRc = false; char const *pszNativeSymlink; int rc = rtPathToNative(&pszNativeSymlink, pszSymlink, NULL); if (RT_SUCCESS(rc)) { struct stat s; fRc = !lstat(pszNativeSymlink, &s) && S_ISLNK(s.st_mode); if (fRc) { errno = 0; fRc = stat(pszNativeSymlink, &s) != 0 && ( errno == ENOENT || errno == ENOTDIR || errno == ELOOP); } rtPathFreeNative(pszNativeSymlink, pszSymlink); } LogFlow(("RTSymlinkIsDangling(%p={%s}): returns %RTbool\n", pszSymlink, pszSymlink, fRc)); return fRc; }
int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf) { NOREF(pszPathBuf); /* only used on windows */ /* * Convert to a native path and try opendir. */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pDir->pszPath, NULL); if (RT_SUCCESS(rc)) { pDir->pDir = opendir(pszNativePath); if (pDir->pDir) { /* * Init data (allocated as all zeros). */ pDir->fDataUnread = false; /* spelling it out */ } else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativePath, pDir->pszPath); } return rc; }
RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath) { /* * Convert input. */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { /* * On POSIX platforms the API doesn't take a length parameter, which makes it * a little bit more work. */ char szTmpPath[PATH_MAX + 1]; const char *psz = realpath(pszNativePath, szTmpPath); if (psz) rc = rtPathFromNativeCopy(pszRealPath, cchRealPath, szTmpPath, NULL); else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativePath, pszPath); } LogFlow(("RTPathReal(%p:{%s}, %p:{%s}, %u): returns %Rrc\n", pszPath, pszPath, pszRealPath, RT_SUCCESS(rc) ? pszRealPath : "<failed>", cchRealPath, rc)); return rc; }
RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial) { /* * Validate input. */ AssertMsgReturn(VALID_PTR(pszFsPath) && *pszFsPath, ("%p", pszFsPath), VERR_INVALID_PARAMETER); AssertMsgReturn(VALID_PTR(pu32Serial), ("%p", pu32Serial), VERR_INVALID_PARAMETER); /* * Convert the path and query the stats. * We're simply return the device id. */ char const *pszNativeFsPath; int rc = rtPathToNative(&pszNativeFsPath, pszFsPath, NULL); if (RT_SUCCESS(rc)) { struct stat Stat; if (!stat(pszNativeFsPath, &Stat)) { if (pu32Serial) *pu32Serial = (uint32_t)Stat.st_dev; } else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativeFsPath, pszFsPath); } LogFlow(("RTFsQuerySerial(%p:{%s}, %p:{%RX32}: returns %Rrc\n", pszFsPath, pszFsPath, pu32Serial, pu32Serial ? *pu32Serial : 0, rc)); return rc; }
RTDECL(int) RTSymlinkReadA(const char *pszSymlink, char **ppszTarget) { AssertPtr(ppszTarget); char const *pszNativeSymlink; int rc = rtPathToNative(&pszNativeSymlink, pszSymlink, NULL); if (RT_SUCCESS(rc)) { /* Guess the initial buffer size. */ ssize_t cbBuf; struct stat s; if (!lstat(pszNativeSymlink, &s)) cbBuf = RT_MIN(RT_ALIGN_Z(s.st_size, 64), 64); else cbBuf = 1024; /* Read loop that grows the buffer. */ char *pszBuf = NULL; for (;;) { RTMemTmpFree(pszBuf); pszBuf = (char *)RTMemTmpAlloc(cbBuf); if (pszBuf) { ssize_t cbReturned = readlink(pszNativeSymlink, pszBuf, cbBuf); if (cbReturned >= cbBuf) { /* Increase the buffer size and try again */ cbBuf *= 2; continue; } if (cbReturned > 0) { pszBuf[cbReturned] = '\0'; rc = rtPathFromNativeDup(ppszTarget, pszBuf, pszSymlink); } else if (errno == EINVAL) rc = VERR_NOT_SYMLINK; else rc = RTErrConvertFromErrno(errno); } else rc = VERR_NO_TMP_MEMORY; break; } /* for loop */ RTMemTmpFree(pszBuf); rtPathFreeNative(pszNativeSymlink, pszSymlink); } if (RT_SUCCESS(rc)) LogFlow(("RTSymlinkReadA(%p={%s},%p): returns %Rrc *ppszTarget=%p:{%s}\n", pszSymlink, pszSymlink, ppszTarget, rc, *ppszTarget, *ppszTarget)); else LogFlow(("RTSymlinkReadA(%p={%s},%p): returns %Rrc\n", pszSymlink, pszSymlink, ppszTarget, rc)); return rc; }
RTDECL(int) RTDirRemove(const char *pszPath) { char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { if (rmdir(pszNativePath)) rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativePath, pszPath); } LogFlow(("RTDirRemove(%p={%s}): returns %Rrc\n", pszPath, pszPath, rc)); return rc; }
RTDECL(int) RTSymlinkCreate(const char *pszSymlink, const char *pszTarget, RTSYMLINKTYPE enmType, uint32_t fCreate) { /* * Validate the input. */ AssertReturn(enmType > RTSYMLINKTYPE_INVALID && enmType < RTSYMLINKTYPE_END, VERR_INVALID_PARAMETER); AssertPtrReturn(pszSymlink, VERR_INVALID_POINTER); AssertPtrReturn(pszTarget, VERR_INVALID_POINTER); /* * Convert the paths. */ char const *pszNativeSymlink; int rc = rtPathToNative(&pszNativeSymlink, pszSymlink, NULL); if (RT_SUCCESS(rc)) { const char *pszNativeTarget; rc = rtPathToNative(&pszNativeTarget, pszTarget, NULL); if (RT_SUCCESS(rc)) { /* * Create the link. */ if (symlink(pszNativeTarget, pszNativeSymlink) == 0) rc = VINF_SUCCESS; else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativeTarget, pszTarget); } rtPathFreeNative(pszNativeSymlink, pszSymlink); } LogFlow(("RTSymlinkCreate(%p={%s}, %p={%s}, %d, %#x): returns %Rrc\n", pszSymlink, pszSymlink, pszTarget, pszTarget, enmType, fCreate, rc)); return rc; }
RTDECL(bool) RTDirExists(const char *pszPath) { bool fRc = false; char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { struct stat s; fRc = !stat(pszNativePath, &s) && S_ISDIR(s.st_mode); rtPathFreeNative(pszNativePath, pszPath); } LogFlow(("RTDirExists(%p={%s}): returns %RTbool\n", pszPath, pszPath, fRc)); return fRc; }
RTDECL(bool) RTSymlinkExists(const char *pszSymlink) { bool fRc = false; char const *pszNativeSymlink; int rc = rtPathToNative(&pszNativeSymlink, pszSymlink, NULL); if (RT_SUCCESS(rc)) { struct stat s; fRc = !lstat(pszNativeSymlink, &s) && S_ISLNK(s.st_mode); rtPathFreeNative(pszNativeSymlink, pszSymlink); } LogFlow(("RTSymlinkExists(%p={%s}): returns %RTbool\n", pszSymlink, pszSymlink, fRc)); return fRc; }
RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pcbFree, uint32_t *pcbBlock, uint32_t *pcbSector) { /* * Validate input. */ AssertMsgReturn(VALID_PTR(pszFsPath) && *pszFsPath, ("%p", pszFsPath), VERR_INVALID_PARAMETER); /* * Convert the path and query the information. */ char const *pszNativeFsPath; int rc = rtPathToNative(&pszNativeFsPath, pszFsPath, NULL); if (RT_SUCCESS(rc)) { /** @todo I'm not quite sure if statvfs was properly specified by SuS, I have to check my own * implementation and FreeBSD before this can eventually be promoted to posix. */ struct statvfs StatVFS; RT_ZERO(StatVFS); if (!statvfs(pszNativeFsPath, &StatVFS)) { /* * Calc the returned values. */ if (pcbTotal) *pcbTotal = (RTFOFF)StatVFS.f_blocks * StatVFS.f_frsize; if (pcbFree) *pcbFree = (RTFOFF)StatVFS.f_bavail * StatVFS.f_frsize; if (pcbBlock) *pcbBlock = StatVFS.f_frsize; /* no idea how to get the sector... */ if (pcbSector) *pcbSector = 512; } else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativeFsPath, pszFsPath); } LogFlow(("RTFsQuerySizes(%p:{%s}, %p:{%RTfoff}, %p:{%RTfoff}, %p:{%RX32}, %p:{%RX32}): returns %Rrc\n", pszFsPath, pszFsPath, pcbTotal, pcbTotal ? *pcbTotal : 0, pcbFree, pcbFree ? *pcbFree : 0, pcbBlock, pcbBlock ? *pcbBlock : 0, pcbSector, pcbSector ? *pcbSector : 0, rc)); return rc; }
RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties) { /* * Validate. */ AssertMsgReturn(VALID_PTR(pszFsPath) && *pszFsPath, ("%p", pszFsPath), VERR_INVALID_PARAMETER); AssertMsgReturn(VALID_PTR(pProperties), ("%p", pProperties), VERR_INVALID_PARAMETER); /* * Convert the path and query the information. */ char const *pszNativeFsPath; int rc = rtPathToNative(&pszNativeFsPath, pszFsPath, NULL); if (RT_SUCCESS(rc)) { struct statvfs StatVFS; RT_ZERO(StatVFS); if (!statvfs(pszNativeFsPath, &StatVFS)) { /* * Calc/fake the returned values. */ pProperties->cbMaxComponent = StatVFS.f_namemax; #if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) pProperties->fCaseSensitive = false; #else pProperties->fCaseSensitive = true; #endif pProperties->fCompressed = false; pProperties->fFileCompression = false; pProperties->fReadOnly = !!(StatVFS.f_flag & ST_RDONLY); pProperties->fRemote = false; pProperties->fSupportsUnicode = true; } else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativeFsPath, pszFsPath); } LogFlow(("RTFsQueryProperties(%p:{%s}, %p:{.cbMaxComponent=%u, .fReadOnly=%RTbool}): returns %Rrc\n", pszFsPath, pszFsPath, pProperties, pProperties->cbMaxComponent, pProperties->fReadOnly, rc)); return rc; }
RTDECL(int) RTPathSetCurrent(const char *pszPath) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); /* * Change the directory. */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { if (chdir(pszNativePath)) rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativePath, pszPath); } return rc; }
RTDECL(int) RTDirCreate(const char *pszPath, RTFMODE fMode, uint32_t fCreate) { int rc; fMode = rtFsModeNormalize(fMode, pszPath, 0); if (rtFsModeIsValidPermissions(fMode)) { char const *pszNativePath; rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { if (mkdir(pszNativePath, fMode & RTFS_UNIX_MASK)) { rc = errno; bool fVerifyIsDir = true; #ifdef RT_OS_SOLARIS /* * mkdir on nfs mount points has been/is busted in various * during the Nevada development cycle. We've observed: * - Build 111b (2009.06) returns EACCES. * - Build ca. 70-80 returns ENOSYS. */ if ( rc == ENOSYS || rc == EACCES) { rc = RTErrConvertFromErrno(rc); fVerifyIsDir = false; /* We'll check if it's a dir ourselves since we're going to stat() anyway. */ struct stat st; if (!stat(pszNativePath, &st)) { rc = VERR_ALREADY_EXISTS; if (!S_ISDIR(st.st_mode)) rc = VERR_IS_A_FILE; } } else rc = RTErrConvertFromErrno(rc); #else rc = RTErrConvertFromErrno(rc); #endif if ( rc == VERR_ALREADY_EXISTS && fVerifyIsDir == true) { /* * Verify that it really exists as a directory. */ struct stat st; if (!stat(pszNativePath, &st) && !S_ISDIR(st.st_mode)) rc = VERR_IS_A_FILE; } } } rtPathFreeNative(pszNativePath, pszPath); } else { AssertMsgFailed(("Invalid file mode! %RTfmode\n", fMode)); rc = VERR_INVALID_FMODE; } LogFlow(("RTDirCreate(%p={%s}, %RTfmode): returns %Rrc\n", pszPath, pszPath, fMode, rc)); return rc; }
/** * Worker for RTPathRename, RTDirRename, RTFileRename. * * @returns IPRT status code. * @param pszSrc The source path. * @param pszDst The destination path. * @param fRename The rename flags. * @param fFileType The filetype. We use the RTFMODE filetypes here. If it's 0, * anything goes. If it's RTFS_TYPE_DIRECTORY we'll check that the * source is a directory. If Its RTFS_TYPE_FILE we'll check that it's * not a directory (we are NOT checking whether it's a file). */ DECLHIDDEN(int) rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType) { /* * Convert the paths. */ char const *pszNativeSrc; int rc = rtPathToNative(&pszNativeSrc, pszSrc, NULL); if (RT_SUCCESS(rc)) { char const *pszNativeDst; rc = rtPathToNative(&pszNativeDst, pszDst, NULL); if (RT_SUCCESS(rc)) { /* * Check that the source exists and that any types that's specified matches. * We have to check this first to avoid getting errnous VERR_ALREADY_EXISTS * errors from the next step. * * There are race conditions here (perhaps unlikely ones, but still), but I'm * afraid there is little with can do to fix that. */ struct stat SrcStat; if (lstat(pszNativeSrc, &SrcStat)) rc = RTErrConvertFromErrno(errno); else if (!fFileType) rc = VINF_SUCCESS; else if (RTFS_IS_DIRECTORY(fFileType)) rc = S_ISDIR(SrcStat.st_mode) ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY; else rc = S_ISDIR(SrcStat.st_mode) ? VERR_IS_A_DIRECTORY : VINF_SUCCESS; if (RT_SUCCESS(rc)) { bool fSameFile = false; /* * Check if the target exists, rename is rather destructive. * We'll have to make sure we don't overwrite the source! * Another race condition btw. */ struct stat DstStat; if (lstat(pszNativeDst, &DstStat)) rc = errno == ENOENT ? VINF_SUCCESS : RTErrConvertFromErrno(errno); else { Assert(SrcStat.st_dev && DstStat.st_dev); Assert(SrcStat.st_ino && DstStat.st_ino); if ( SrcStat.st_dev == DstStat.st_dev && SrcStat.st_ino == DstStat.st_ino && (SrcStat.st_mode & S_IFMT) == (DstStat.st_mode & S_IFMT)) { /* * It's likely that we're talking about the same file here. * We should probably check paths or whatever, but for now this'll have to be enough. */ fSameFile = true; } if (fSameFile) rc = VINF_SUCCESS; else if (S_ISDIR(DstStat.st_mode) || !(fRename & RTPATHRENAME_FLAGS_REPLACE)) rc = VERR_ALREADY_EXISTS; else rc = VINF_SUCCESS; } if (RT_SUCCESS(rc)) { if (!rename(pszNativeSrc, pszNativeDst)) rc = VINF_SUCCESS; else if ( (fRename & RTPATHRENAME_FLAGS_REPLACE) && (errno == ENOTDIR || errno == EEXIST)) { /* * Check that the destination isn't a directory. * Yet another race condition. */ if (rtPathSame(pszNativeSrc, pszNativeDst)) { rc = VINF_SUCCESS; Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): appears to be the same file... (errno=%d)\n", pszSrc, pszDst, fRename, fFileType, errno)); } else { if (lstat(pszNativeDst, &DstStat)) rc = errno != ENOENT ? RTErrConvertFromErrno(errno) : VINF_SUCCESS; else if (S_ISDIR(DstStat.st_mode)) rc = VERR_ALREADY_EXISTS; else rc = VINF_SUCCESS; if (RT_SUCCESS(rc)) { if (!unlink(pszNativeDst)) { if (!rename(pszNativeSrc, pszNativeDst)) rc = VINF_SUCCESS; else { rc = RTErrConvertFromErrno(errno); Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n", pszSrc, pszDst, fRename, fFileType, rc, errno)); } } else { rc = RTErrConvertFromErrno(errno); Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): failed to unlink dst rc=%Rrc errno=%d\n", pszSrc, pszDst, fRename, fFileType, rc, errno)); } } else Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): dst !dir check failed rc=%Rrc\n", pszSrc, pszDst, fRename, fFileType, rc)); } } else { rc = RTErrConvertFromErrno(errno); if (errno == ENOTDIR) rc = VERR_ALREADY_EXISTS; /* unless somebody is racing us, this is the right interpretation */ Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n", pszSrc, pszDst, fRename, fFileType, rc, errno)); } } else Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): destination check failed rc=%Rrc errno=%d\n", pszSrc, pszDst, fRename, fFileType, rc, errno)); } else Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): source type check failed rc=%Rrc errno=%d\n", pszSrc, pszDst, fRename, fFileType, rc, errno)); rtPathFreeNative(pszNativeDst, pszDst); } rtPathFreeNative(pszNativeSrc, pszSrc); } return rc; }
RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType) { *penmType = RTFSTYPE_UNKNOWN; /* * Validate input. */ AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER); AssertReturn(*pszFsPath, VERR_INVALID_PARAMETER); /* * Convert the path and query the stats. * We're simply return the device id. */ char const *pszNativeFsPath; int rc = rtPathToNative(&pszNativeFsPath, pszFsPath, NULL); if (RT_SUCCESS(rc)) { struct stat Stat; if (!stat(pszNativeFsPath, &Stat)) { #if defined(RT_OS_LINUX) FILE *mounted = setmntent("/proc/mounts", "r"); if (!mounted) mounted = setmntent("/etc/mtab", "r"); if (mounted) { char szBuf[1024]; struct stat mntStat; struct mntent mntEnt; while (getmntent_r(mounted, &mntEnt, szBuf, sizeof(szBuf))) { if (!stat(mntEnt.mnt_dir, &mntStat)) { if (mntStat.st_dev == Stat.st_dev) { if (!strcmp("ext4", mntEnt.mnt_type)) *penmType = RTFSTYPE_EXT4; else if (!strcmp("ext3", mntEnt.mnt_type)) *penmType = RTFSTYPE_EXT3; else if (!strcmp("ext2", mntEnt.mnt_type)) *penmType = RTFSTYPE_EXT2; else if (!strcmp("jfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_JFS; else if (!strcmp("xfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_XFS; else if ( !strcmp("vfat", mntEnt.mnt_type) || !strcmp("msdos", mntEnt.mnt_type)) *penmType = RTFSTYPE_FAT; else if (!strcmp("ntfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_NTFS; else if (!strcmp("hpfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_HPFS; else if (!strcmp("ufs", mntEnt.mnt_type)) *penmType = RTFSTYPE_UFS; else if (!strcmp("tmpfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_TMPFS; else if (!strcmp("hfsplus", mntEnt.mnt_type)) *penmType = RTFSTYPE_HFS; else if (!strcmp("udf", mntEnt.mnt_type)) *penmType = RTFSTYPE_UDF; else if (!strcmp("iso9660", mntEnt.mnt_type)) *penmType = RTFSTYPE_ISO9660; else if (!strcmp("smbfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_SMBFS; else if (!strcmp("cifs", mntEnt.mnt_type)) *penmType = RTFSTYPE_CIFS; else if (!strcmp("nfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_NFS; else if (!strcmp("nfs4", mntEnt.mnt_type)) *penmType = RTFSTYPE_NFS; else if (!strcmp("sysfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_SYSFS; else if (!strcmp("proc", mntEnt.mnt_type)) *penmType = RTFSTYPE_PROC; else if ( !strcmp("fuse", mntEnt.mnt_type) || !strncmp("fuse.", mntEnt.mnt_type, 5) || !strcmp("fuseblk", mntEnt.mnt_type)) *penmType = RTFSTYPE_FUSE; else { /* sometimes there are more than one entry for the same partition */ continue; } break; } } } endmntent(mounted); } #elif defined(RT_OS_SOLARIS) if (!strcmp("zfs", Stat.st_fstype)) *penmType = RTFSTYPE_ZFS; else if (!strcmp("ufs", Stat.st_fstype)) *penmType = RTFSTYPE_UFS; else if (!strcmp("nfs", Stat.st_fstype)) *penmType = RTFSTYPE_NFS; #elif defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) struct statfs statfsBuf; if (!statfs(pszNativeFsPath, &statfsBuf)) { if (!strcmp("hfs", statfsBuf.f_fstypename)) *penmType = RTFSTYPE_HFS; else if ( !strcmp("fat", statfsBuf.f_fstypename) || !strcmp("msdos", statfsBuf.f_fstypename)) *penmType = RTFSTYPE_FAT; else if (!strcmp("ntfs", statfsBuf.f_fstypename)) *penmType = RTFSTYPE_NTFS; else if (!strcmp("autofs", statfsBuf.f_fstypename)) *penmType = RTFSTYPE_AUTOFS; else if (!strcmp("devfs", statfsBuf.f_fstypename)) *penmType = RTFSTYPE_DEVFS; else if (!strcmp("nfs", statfsBuf.f_fstypename)) *penmType = RTFSTYPE_NFS; else if (!strcmp("ufs", statfsBuf.f_fstypename)) *penmType = RTFSTYPE_UFS; else if (!strcmp("zfs", statfsBuf.f_fstypename)) *penmType = RTFSTYPE_ZFS; } else rc = RTErrConvertFromErrno(errno); #endif } else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativeFsPath, pszFsPath); } return rc; }
RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER); AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST, ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs), VERR_INVALID_PARAMETER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); /* * Convert the filename. */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { struct stat Stat; if (fFlags & RTPATH_F_FOLLOW_LINK) rc = stat(pszNativePath, &Stat); else rc = lstat(pszNativePath, &Stat); /** @todo how doesn't have lstat again? */ if (!rc) { rtFsConvertStatToObjInfo(pObjInfo, &Stat, pszPath, 0); switch (enmAdditionalAttribs) { case RTFSOBJATTRADD_NOTHING: case RTFSOBJATTRADD_UNIX: Assert(pObjInfo->Attr.enmAdditional == RTFSOBJATTRADD_UNIX); break; case RTFSOBJATTRADD_UNIX_OWNER: rtFsObjInfoAttrSetUnixOwner(pObjInfo, Stat.st_uid); break; case RTFSOBJATTRADD_UNIX_GROUP: rtFsObjInfoAttrSetUnixGroup(pObjInfo, Stat.st_gid); break; case RTFSOBJATTRADD_EASIZE: /** @todo Use SGI extended attribute interface to query EA info. */ pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; pObjInfo->Attr.u.EASize.cb = 0; break; default: AssertMsgFailed(("Impossible!\n")); return VERR_INTERNAL_ERROR; } } else rc = RTErrConvertFromErrno(errno); rtPathFreeNative(pszNativePath, pszPath); } LogFlow(("RTPathQueryInfoEx(%p:{%s}, pObjInfo=%p, %d): returns %Rrc\n", pszPath, pszPath, pObjInfo, enmAdditionalAttribs, rc)); return rc; }
RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); /* * Convert the paths. */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { RTFSOBJINFO ObjInfo; /* * If it's a no-op, we'll only verify the existance of the file. */ if (!pAccessTime && !pModificationTime) rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, fFlags); else { /* * Convert the input to timeval, getting the missing one if necessary, * and call the API which does the change. */ struct timeval aTimevals[2]; if (pAccessTime && pModificationTime) { RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]); } else { rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags); if (RT_SUCCESS(rc)) { RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]); } else Log(("RTPathSetTimes('%s',%p,%p,,): RTPathQueryInfo failed with %Rrc\n", pszPath, pAccessTime, pModificationTime, rc)); } if (RT_SUCCESS(rc)) { if (fFlags & RTPATH_F_FOLLOW_LINK) { if (utimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } #if (defined(RT_OS_DARWIN) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) \ || defined(RT_OS_FREEBSD) \ || defined(RT_OS_LINUX) \ || defined(RT_OS_OS2) /** @todo who really has lutimes? */ else { if (lutimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } #else else { if (pAccessTime && pModificationTime) rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags); if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) rc = VERR_NS_SYMLINK_SET_TIME; else if (RT_SUCCESS(rc)) { if (utimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } } #endif if (RT_FAILURE(rc)) Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n", pszPath, pAccessTime, pModificationTime, rc, errno)); } } rtPathFreeNative(pszNativePath, pszPath); }