static char * FindSuitableExistingDirectory( const char *realRoot, // IN: e.g. $HOME/.cache/vmware/drag_and_drop/ const char *apparentRoot) // IN: e.g. /tmp/VMwareDnD/ { char *result = NULL; char **stagingDirList; int numStagingDirs = File_ListDirectory(realRoot, &stagingDirList); int i; for (i = 0; i < numStagingDirs && result == NULL; i++) { char *stagingDir = Unicode_Append(realRoot, stagingDirList[i]); char *apparentStagingDir = Unicode_Append(apparentRoot, stagingDirList[i]); char *temp = NULL; struct stat sb; if ( File_IsEmptyDirectory(stagingDir) && ( Posix_Symlink(stagingDir, apparentStagingDir) == 0 || ( Posix_Lstat(apparentStagingDir, &sb) == 0 && sb.st_uid == getuid() && (temp = Posix_ReadLink(apparentStagingDir)) != NULL && strcmp(stagingDir, temp) == 0))) { result = apparentStagingDir; apparentStagingDir = NULL; } free(stagingDir); free(apparentStagingDir); free(temp); } Util_FreeStringList(stagingDirList, numStagingDirs); return result; }
Bool DnD_DeleteStagingFiles(const char *stagingDir, // IN: Bool onReboot) // IN: { Bool ret = TRUE; ASSERT(stagingDir); if (!File_Exists(stagingDir)) { /* The stagingDir is already gone. */ return TRUE; } if (!File_IsDirectory(stagingDir)) { return FALSE; } if (onReboot) { if (File_UnlinkDelayed(stagingDir)) { ret = FALSE; } } else { int i; int numFiles; char *base; char **fileList = NULL; /* get list of files in current directory */ numFiles = File_ListDirectory(stagingDir, &fileList); if (numFiles == -1) { return FALSE; } /* delete everything in the directory */ base = Unicode_Append(stagingDir, DIRSEPS); for (i = 0; i < numFiles; i++) { char *curPath; curPath = Unicode_Append(base, fileList[i]); if (File_IsDirectory(curPath)) { if (!File_DeleteDirectoryTree(curPath)) { ret = FALSE; } } else { if (File_Unlink(curPath) == -1) { ret = FALSE; } } free(curPath); } free(base); } return ret; }
Unicode Unicode_Join(ConstUnicode first, // IN: ...) // IN { va_list args; Unicode result; ConstUnicode cur; if (first == NULL) { return NULL; } result = Unicode_Duplicate(first); va_start(args, first); while ((cur = va_arg(args, ConstUnicode)) != NULL) { Unicode temp; temp = Unicode_Append(result, cur); Unicode_Free(result); result = temp; } va_end(args); return result; }
int FileUnlockIntrinsic(ConstUnicode pathName, // IN: const void *lockToken) // IN: { int err; ASSERT(pathName); ASSERT(lockToken); LOG(1, ("Requesting unlock on %s\n", UTF8(pathName))); if (lockToken == &implicitReadToken) { /* * The lock token is the fixed-address implicit read lock token. * Since no lock file was created no further action is required. */ err = 0; } else { Unicode lockDir; /* The lock directory path */ lockDir = Unicode_Append(pathName, FILELOCK_SUFFIX); /* * The lock token is the (unicode) path of the lock file. * * TODO: under vmx86_debug validate the contents of the lock file as * matching the machineID and executionID. */ err = FileDeletionRobust((Unicode) lockToken, FALSE); if (err && vmx86_debug) { Log(LGPFX" %s failed for '%s': %s\n", __FUNCTION__, (char *) lockToken, strerror(err)); } /* * The lockToken (a unicode path) was allocated in FileLockIntrinsic * and returned to the caller hidden behind a "void *" pointer. */ Unicode_Free((Unicode) lockToken); FileRemoveDirectoryRobust(lockDir); // just in case we can clean up Unicode_Free(lockDir); } return err; }
void File_GetPathName(ConstUnicode fullPath, // IN: Unicode *pathName, // OUT (OPT): Unicode *baseName) // OUT (OPT): { Unicode volume; UnicodeIndex len; UnicodeIndex curLen; File_SplitName(fullPath, &volume, pathName, baseName); if (pathName == NULL) { Unicode_Free(volume); return; } /* * The volume component may be empty. */ if (!Unicode_IsEmpty(volume)) { Unicode temp = Unicode_Append(volume, *pathName); Unicode_Free(*pathName); *pathName = temp; } Unicode_Free(volume); /* * Remove any trailing directory separator characters. */ len = Unicode_LengthInCodePoints(*pathName); curLen = len; while ((curLen > 0) && (FileFirstSlashIndex(*pathName, curLen - 1) == curLen - 1)) { curLen--; } if (curLen < len) { Unicode temp = Unicode_Substr(*pathName, 0, curLen); Unicode_Free(*pathName); *pathName = temp; } }
char * HgfsUri_ConvertFromPathToHgfsUri(const char *pathName, // IN: path to convert Bool hgfsOnly) // IN { char *shareUri = NULL; Bool isHgfsName = FALSE; char *sharesDefaultRootPath = NULL; /* We can only operate on full paths. */ if (pathName[0] != DIRSEPC) { return shareUri; } /* Retrieve the servername & share name in use. */ if (!HgfsHlpr_QuerySharesDefaultRootPath(&sharesDefaultRootPath)) { Debug("%s: Unable to query shares default root path\n", __FUNCTION__); goto exit; } if (Unicode_StartsWith(pathName, sharesDefaultRootPath)) { char *relativeSharePath = NULL; char *escapedSharePath = NULL; UnicodeIndex relativePathStart = strlen(sharesDefaultRootPath); if ( strlen(pathName) > relativePathStart && pathName[relativePathStart] == DIRSEPC) { relativePathStart++; } relativeSharePath = Unicode_RemoveRange(pathName, 0, relativePathStart); HgfsEscape_Undo(relativeSharePath, strlen(relativeSharePath) + 1); escapedSharePath = g_uri_escape_string(relativeSharePath, "/", FALSE); shareUri = Unicode_Append(GHI_HGFS_SHARE_URL_UTF8, escapedSharePath); g_free(escapedSharePath); free(relativeSharePath); isHgfsName = TRUE; } exit: if (!isHgfsName && !hgfsOnly) { /* Only convert non-hgfs file name if hgfsOnly is not set. */ char *escapedPath = g_uri_escape_string(pathName, "/", FALSE); shareUri = Str_Asprintf(NULL, "file://%s", escapedPath); g_free(escapedPath); } HgfsHlpr_FreeSharesRootPath(sharesDefaultRootPath); return shareUri; }
Bool FileLockIsLocked(ConstUnicode pathName, // IN: int *err) // OUT: { uint32 i; int errValue; int numEntries; Unicode lockDir; Bool isLocked = FALSE; Unicode *fileList = NULL; lockDir = Unicode_Append(pathName, FILELOCK_SUFFIX); numEntries = FileListDirectoryRobust(lockDir, &fileList); if (numEntries == -1) { errValue = errno; goto bail; } for (i = 0; i < numEntries; i++) { if (Unicode_StartsWith(fileList[i], "M")) { isLocked = TRUE; break; } } for (i = 0; i < numEntries; i++) { Unicode_Free(fileList[i]); } free(fileList); errValue = 0; bail: Unicode_Free(lockDir); if (err != NULL) { *err = errValue; } return isLocked; }
Bool File_DoesVolumeSupportAcls(const char *path) // IN: { Bool succeeded = FALSE; #if defined(_WIN32) Bool res; char *vol; char *vol2; const utf16_t *vol2W; DWORD fsFlags; ASSERT(path); File_SplitName(path, &vol, NULL, NULL); vol2 = Unicode_Append(vol, DIRSEPS); vol2W = UNICODE_GET_UTF16(vol2); res = GetVolumeInformationW(vol2W, NULL, 0, NULL, NULL, &fsFlags, NULL, 0); UNICODE_RELEASE_UTF16(vol2W); if (res) { if ((fsFlags & FS_PERSISTENT_ACLS) == 0) { goto exit; } } else { Log(LGPFX" %s: GetVolumeInformation failed: %d\n", __FUNCTION__, GetLastError()); goto exit; } succeeded = TRUE; exit: free(vol); free(vol2); #endif return succeeded; }
static char * CreateStagingDirectory( const char *realRoot, // IN: e.g. $HOME/.cache/vmware/drag_and_drop/ const char *apparentRoot) // IN: e.g. /tmp/VMwareDnD/ { char *result = NULL; int i; for (i = 0; i < 10 && result == NULL; i++) { char *realStagingDir = NULL; char *apparentStagingDir = NULL; // Reminder: mkdtemp updates its arg in-place. realStagingDir = Str_SafeAsprintf(NULL, "%sXXXXXX", realRoot); if (mkdtemp(realStagingDir) != NULL) { char *randomPart = strrchr(realStagingDir, '/') + 1; VERIFY(*randomPart != '\0'); apparentStagingDir = Unicode_Append(apparentRoot, randomPart); if (Posix_Symlink(realStagingDir, apparentStagingDir) == 0) { // Transfer ownership to caller. result = apparentStagingDir; apparentStagingDir = NULL; } else { Warning("dnd: symlink(%s): %s", apparentStagingDir, Err_ErrString()); Posix_Rmdir(realStagingDir); } } else { Warning("dnd: mkdtemp(%s): %s", realStagingDir, Err_ErrString()); } free(realStagingDir); free(apparentStagingDir); } return result; }
Unicode File_ReplaceExtension(ConstUnicode pathName, // IN: ConstUnicode newExtension, // IN: uint32 numExtensions, // IN: ...) // IN: { Unicode path; Unicode base; Unicode result; va_list arguments; UnicodeIndex index; ASSERT(pathName); ASSERT(newExtension); ASSERT(Unicode_StartsWith(newExtension, ".")); File_GetPathName(pathName, &path, &base); index = Unicode_FindLast(base, "."); if (index != UNICODE_INDEX_NOT_FOUND) { Unicode oldBase = base; if (numExtensions) { uint32 i; /* * Only truncate the old extension from the base if it exists in * in the valid extensions list. */ va_start(arguments, numExtensions); for (i = 0; i < numExtensions ; i++) { Unicode oldExtension = va_arg(arguments, Unicode); ASSERT(Unicode_StartsWith(oldExtension, ".")); if (Unicode_CompareRange(base, index, -1, oldExtension, 0, -1, FALSE) == 0) { base = Unicode_Truncate(oldBase, index); // remove '.' break; } } va_end(arguments); } else { /* Always truncate the old extension if extension list is empty . */ base = Unicode_Truncate(oldBase, index); // remove '.' } if (oldBase != base) { Unicode_Free(oldBase); } } if (Unicode_IsEmpty(path)) { result = Unicode_Append(base, newExtension); } else { result = Unicode_Join(path, DIRSEPS, base, newExtension, NULL); } Unicode_Free(path); Unicode_Free(base); return result; }
char * DnD_CreateStagingDirectory(void) { const char *root; char **stagingDirList; int numStagingDirs; int i; char *ret = NULL; Bool found = FALSE; /* * Make sure the root staging directory is created with the correct * permissions. */ root = DnDCreateRootStagingDirectory(); if (!root) { return NULL; } /* Look for an existing, empty staging directory */ numStagingDirs = File_ListDirectory(root, &stagingDirList); if (numStagingDirs < 0) { goto exit; } for (i = 0; i < numStagingDirs; i++) { if (!found) { char *stagingDir; stagingDir = Unicode_Append(root, stagingDirList[i]); if (File_IsEmptyDirectory(stagingDir) && DnDStagingDirectoryUsable(stagingDir)) { ret = Unicode_Append(stagingDir, DIRSEPS); /* * We can use this directory. Make sure to continue to loop * so we don't leak the remaining stagindDirList[i]s. */ found = TRUE; } free(stagingDir); } } Util_FreeStringList(stagingDirList, numStagingDirs); /* Only create a directory if we didn't find one above. */ if (!found) { rqContext *context; context = Random_QuickSeed((unsigned)time(NULL)); for (i = 0; i < 10; i++) { char *temp; /* Each staging directory is given a random name. */ free(ret); temp = Unicode_Format("%08x%c", Random_Quick(context), DIRSEPC); VERIFY(temp); ret = Unicode_Append(root, temp); free(temp); if (File_CreateDirectory(ret) && DnDSetPermissionsOnStagingDir(ret)) { found = TRUE; break; } } free(context); } exit: if (!found && ret != NULL) { free(ret); ret = NULL; } return ret; }
int FileLockHackVMX(ConstUnicode pathName) // IN: { int err; LockValues myValues; Unicode lockDir = NULL; Unicode entryFilePath = NULL; Unicode memberFilePath = NULL; Unicode entryDirectory = NULL; ASSERT(pathName); /* first the locking directory path name */ lockDir = Unicode_Append(pathName, FILELOCK_SUFFIX); /* establish our values */ myValues.machineID = (char *) FileLockGetMachineID(); // don't free this! myValues.executionID = FileLockGetExecutionID(); // free this! myValues.locationChecksum = FileLockLocationChecksum(lockDir); // free this! myValues.lamportNumber = 0; myValues.memberName = NULL; LOG(1, ("%s on %s (%s, %s).\n", __FUNCTION__, UTF8(pathName), myValues.machineID, myValues.executionID)); err = CreateEntryDirectory(myValues.machineID, myValues.executionID, lockDir, &entryDirectory, &entryFilePath, &memberFilePath, &myValues.memberName); if (err != 0) { goto bail; } /* Scan the lock directory */ err = Scanner(lockDir, ScannerVMX, &myValues, FALSE); if (err == 0) { /* if no members are valid, clean up */ if (myValues.lamportNumber == 1) { FileDeletionRobust(pathName, FALSE); } } else { if (vmx86_debug) { Warning(LGPFX" %s clean-up failure for '%s': %s\n", __FUNCTION__, UTF8(pathName), strerror(err)); } } /* clean up */ FileRemoveDirectoryRobust(entryDirectory); FileRemoveDirectoryRobust(lockDir); bail: Unicode_Free(lockDir); Unicode_Free(entryDirectory); Unicode_Free(entryFilePath); Unicode_Free(memberFilePath); Unicode_Free(myValues.memberName); free(myValues.locationChecksum); free(myValues.executionID); return err; }
void * FileLockIntrinsic(ConstUnicode pathName, // IN: Bool exclusivity, // IN: uint32 msecMaxWaitTime, // IN: const char *payload, // IN: int *err) // OUT: { FILELOCK_FILE_HANDLE handle; LockValues myValues; Unicode lockDir = NULL; Unicode entryFilePath = NULL; Unicode memberFilePath = NULL; Unicode entryDirectory = NULL; ASSERT(pathName); ASSERT(err); /* Construct the locking directory path */ lockDir = Unicode_Append(pathName, FILELOCK_SUFFIX); /* establish our values */ myValues.machineID = (char *) FileLockGetMachineID(); // don't free this! myValues.executionID = FileLockGetExecutionID(); // free this! myValues.payload = (char *) payload; myValues.lockType = exclusivity ? LOCK_EXCLUSIVE : LOCK_SHARED; myValues.lamportNumber = 0; myValues.locationChecksum = FileLockLocationChecksum(lockDir); // free this! myValues.waitTime = 0; myValues.msecMaxWaitTime = msecMaxWaitTime; myValues.memberName = NULL; LOG(1, ("Requesting %s lock on %s (%s, %s, %u).\n", myValues.lockType, UTF8(pathName), myValues.machineID, myValues.executionID, myValues.msecMaxWaitTime)); /* * Attempt to create the locking and entry directories; obtain the * entry and member path names. */ *err = CreateEntryDirectory(myValues.machineID, myValues.executionID, lockDir, &entryDirectory, &entryFilePath, &memberFilePath, &myValues.memberName); switch (*err) { case 0: break; case EROFS: /* FALL THROUGH */ case EACCES: if (!exclusivity) { /* * Lock is for read/shared access however the lock directory could * not be created. Grant an implicit read lock whenever possible. * The address of a private variable will be used for the lock token. */ Warning(LGPFX" %s implicit %s lock succeeded on '%s'.\n", __FUNCTION__, LOCK_SHARED, UTF8(pathName)); *err = 0; memberFilePath = &implicitReadToken; } /* FALL THROUGH */ default: goto bail; } ASSERT(Unicode_LengthInCodeUnits(memberFilePath) - Unicode_LengthInCodeUnits(pathName) <= FILELOCK_OVERHEAD); /* Attempt to create the entry file */ *err = FileLockOpenFile(entryFilePath, O_CREAT | O_WRONLY, &handle); if (*err != 0) { /* clean up */ FileRemoveDirectoryRobust(entryDirectory); FileRemoveDirectoryRobust(lockDir); goto bail; } /* what is max(Number[1]... Number[all lockers])? */ *err = Scanner(lockDir, NumberScan, &myValues, FALSE); if (*err != 0) { /* clean up */ FileLockCloseFile(handle); FileDeletionRobust(entryFilePath, FALSE); FileRemoveDirectoryRobust(entryDirectory); FileRemoveDirectoryRobust(lockDir); goto bail; } /* Number[i] = 1 + max([Number[1]... Number[all lockers]) */ myValues.lamportNumber++; /* Attempt to create the member file */ *err = CreateMemberFile(handle, &myValues, entryFilePath, memberFilePath); /* Remove entry directory; it has done its job */ FileRemoveDirectoryRobust(entryDirectory); if (*err != 0) { /* clean up */ FileDeletionRobust(entryFilePath, FALSE); FileDeletionRobust(memberFilePath, FALSE); FileRemoveDirectoryRobust(lockDir); goto bail; } /* Attempt to acquire the lock */ *err = Scanner(lockDir, WaitForPossession, &myValues, TRUE); switch (*err) { case 0: break; case EAGAIN: /* clean up */ FileDeletionRobust(memberFilePath, FALSE); FileRemoveDirectoryRobust(lockDir); /* FALL THROUGH */ default: break; } bail: Unicode_Free(lockDir); Unicode_Free(entryDirectory); Unicode_Free(entryFilePath); Unicode_Free(myValues.memberName); free(myValues.locationChecksum); free(myValues.executionID); if (*err != 0) { Unicode_Free(memberFilePath); memberFilePath = NULL; if (*err == EAGAIN) { *err = 0; // lock not acquired } } return (void *) memberFilePath; }