static const char * DetermineRealRootDirectory(void) { static char *completePath; const char *cachePath; if (completePath != NULL) { return completePath; } cachePath = Xdg_GetCacheHome(); if (cachePath != NULL) { const char dndSuffix[] = "/vmware/drag_and_drop/"; completePath = Unicode_Duplicate(cachePath); StrUtil_SafeStrcat(&completePath, dndSuffix); VERIFY(strlen(completePath) < PATH_MAX); Log_Trivia("dnd: will stage to %s\n", completePath); return completePath; } Log_Trivia("dnd: failed to determine path\n"); return NULL; }
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; }
static char * FileLockLocationChecksum(ConstUnicode path) // IN: { int c; uint32 hash = 5381; #if defined(_WIN32) char *p; Unicode value = Unicode_Duplicate(path); /* Don't get fooled by mixed case; "normalize" */ Str_ToLower(value); p = value; #else char *p = (char *) path; #endif /* DBJ2 hash... good enough? */ while ((c = *p++)) { hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ } #if defined(_WIN32) Unicode_Free(value); #endif return Str_SafeAsprintf(NULL, "%u", hash); }
char * Unicode_Join(const char *first, // IN: ...) // IN: { char *result; if (first == NULL) { result = NULL; } else { va_list args; const char *cur; result = Unicode_Duplicate(first); va_start(args, first); while ((cur = va_arg(args, const char *)) != NULL) { char *temp; temp = Unicode_Format("%s%s", result, cur); free(result); result = temp; } va_end(args); } return result; }
static int ActivateLockList(ConstUnicode dirName, // IN: LockValues *myValues) // IN: { ActiveLock *ptr; ASSERT(dirName); ASSERT(Unicode_StartsWith(dirName, "D")); /* Search the list for a matching entry */ for (ptr = myValues->lockList; ptr != NULL; ptr = ptr->next) { if (Unicode_Compare(ptr->dirName, dirName) == 0) { break; } } /* No entry? Attempt to add one. */ if (ptr == NULL) { ptr = Util_SafeMalloc(sizeof *ptr); ptr->next = myValues->lockList; myValues->lockList = ptr; ptr->age = 0; ptr->dirName = Unicode_Duplicate(dirName); } /* Mark the entry (exists) */ ptr->marked = TRUE; return 0; }
int File_MakeSafeTemp(ConstUnicode tag, // IN (OPT): Unicode *presult) // OUT: { int fd; Unicode dir = NULL; Unicode fileName = NULL; ASSERT(presult); *presult = NULL; if (tag && File_IsFullPath(tag)) { File_GetPathName(tag, &dir, &fileName); } else { dir = File_GetSafeTmpDir(TRUE); fileName = Unicode_Duplicate(tag ? tag : "vmware"); } fd = File_MakeTempEx(dir, fileName, presult); Unicode_Free(dir); Unicode_Free(fileName); return fd; }
void FileIO_Init(FileIODescriptor *fd, // IN/OUT: ConstUnicode pathName) // IN: { ASSERT(fd); ASSERT(pathName); fd->fileName = Unicode_Duplicate(pathName); }
Bool FileIO_CloseAndUnlink(FileIODescriptor *fd) // IN: { Unicode path; Bool ret; ASSERT(fd); ASSERT(FileIO_IsValid(fd)); path = Unicode_Duplicate(fd->fileName); ret = FileIO_Close(fd); if (!ret) { if (File_UnlinkIfExists(path) == -1) { ret = TRUE; } } Unicode_Free(path); return ret; }
FileIOResult FileIO_CloseAndUnlink(FileIODescriptor *fd) // IN: { char *path; FileIOResult ret; ASSERT(fd); ASSERT(FileIO_IsValid(fd)); path = Unicode_Duplicate(fd->fileName); ret = FileIO_Close(fd); if (FileIO_IsSuccess(ret)) { if (File_UnlinkIfExists(path) == -1) { ret = FILEIO_ERROR; } } free(path); return ret; }
void File_SplitName(ConstUnicode pathName, // IN: Unicode *volume, // OUT (OPT): Unicode *directory, // OUT (OPT): Unicode *base) // OUT (OPT): { Unicode vol; Unicode dir; Unicode bas; UnicodeIndex volEnd; UnicodeIndex length; UnicodeIndex baseBegin; WIN32_ONLY(UnicodeIndex pathLen); ASSERT(pathName); /* * Get volume. */ volEnd = 0; #if defined(_WIN32) pathLen = Unicode_LengthInCodePoints(pathName); if ((pathLen > 2) && (Unicode_StartsWith(pathName, "\\\\") || Unicode_StartsWith(pathName, "//"))) { /* UNC path */ volEnd = FileFirstSlashIndex(pathName, 2); if (volEnd == UNICODE_INDEX_NOT_FOUND) { /* we have \\foo, which is just bogus */ volEnd = 0; } else { volEnd = FileFirstSlashIndex(pathName, volEnd + 1); if (volEnd == UNICODE_INDEX_NOT_FOUND) { /* we have \\foo\bar, which is legal */ volEnd = pathLen; } } } else if ((pathLen >= 2) && (Unicode_FindSubstrInRange(pathName, 1, 1, ":", 0, 1) != UNICODE_INDEX_NOT_FOUND)) { /* drive-letter path */ volEnd = 2; } if (volEnd > 0) { vol = Unicode_Substr(pathName, 0, volEnd); } else { vol = Unicode_Duplicate(""); } #else vol = Unicode_Duplicate(""); #endif /* _WIN32 */ /* * Get base. */ baseBegin = FileLastSlashIndex(pathName, 0); baseBegin = (baseBegin == UNICODE_INDEX_NOT_FOUND) ? 0 : baseBegin + 1; if (baseBegin >= volEnd) { bas = Unicode_Substr(pathName, baseBegin, -1); } else { bas = Unicode_Duplicate(""); } /* * Get dir. */ length = baseBegin - volEnd; if (length > 0) { dir = Unicode_Substr(pathName, volEnd, length); } else { dir = Unicode_Duplicate(""); } /* * Return what needs to be returned. */ if (volume) { *volume = vol; } else { Unicode_Free(vol); } if (directory) { *directory = dir; } else { Unicode_Free(dir); } if (base) { *base = bas; } else { Unicode_Free(bas); } }
Bool FileIO_AtomicUpdate(FileIODescriptor *newFD, // IN/OUT: file IO descriptor FileIODescriptor *currFD) // IN/OUT: file IO descriptor { char *currPath = NULL; char *newPath = NULL; #if defined(_WIN32) uint32 currAccess; uint32 newAccess; FileIOResult status; FileIODescriptor tmpFD; #else int fd; #endif int savedErrno = 0; Bool ret = FALSE; ASSERT(FileIO_IsValid(newFD)); ASSERT(FileIO_IsValid(currFD)); if (HostType_OSIsVMK()) { #if defined(VMX86_SERVER) FS_SwapFilesArgs *args = NULL; char *dirName = NULL; char *fileName = NULL; char *dstDirName = NULL; char *dstFileName = NULL; currPath = File_FullPath(FileIO_Filename(currFD)); if (!currPath) { savedErrno = errno; Log("%s: File_FullPath of '%s' failed.\n", __FUNCTION__, FileIO_Filename(currFD)); goto swapdone; } newPath = File_FullPath(FileIO_Filename(newFD)); if (!newPath) { savedErrno = errno; Log("%s: File_FullPath of '%s' failed.\n", __FUNCTION__, FileIO_Filename(newFD)); goto swapdone; } File_GetPathName(newPath, &dirName, &fileName); File_GetPathName(currPath, &dstDirName, &dstFileName); ASSERT(dirName && *dirName); ASSERT(fileName && *fileName); ASSERT(dstDirName && *dstDirName); ASSERT(dstFileName && *dstFileName); ASSERT(!strcmp(dirName, dstDirName)); args = (FS_SwapFilesArgs *) Util_SafeCalloc(1, sizeof(*args)); if (Str_Snprintf(args->srcFile, sizeof(args->srcFile), "%s", fileName) < 0) { Log("%s: Path too long \"%s\".\n", __FUNCTION__, fileName); savedErrno = ENAMETOOLONG; goto swapdone; } if (Str_Snprintf(args->dstFilePath, sizeof(args->dstFilePath), "%s/%s", dstDirName, dstFileName) < 0) { Log("%s: Path too long \"%s\".\n", __FUNCTION__, dstFileName); savedErrno = ENAMETOOLONG; goto swapdone; } /* * Issue the ioctl on the directory rather than on the file, * because the file could be open. */ fd = Posix_Open(dirName, O_RDONLY); if (fd < 0) { Log("%s: Open failed \"%s\" %d.\n", __FUNCTION__, dirName, errno); ASSERT(errno != EBUSY); /* #615124. */ savedErrno = errno; goto swapdone; } if (ioctl(fd, IOCTLCMD_VMFS_SWAP_FILES, args) != 0) { savedErrno = errno; if (errno != ENOSYS && errno != ENOTTY) { Log("%s: ioctl failed %d.\n", __FUNCTION__, errno); ASSERT(errno != EBUSY); /* #615124. */ } } else { ret = TRUE; } close(fd); /* * Did we fail because we are on a file system that does not * support the IOCTLCMD_VMFS_SWAP_FILES ioctl? If so fallback to * using rename. * * Check for both ENOSYS and ENOTTY. PR 957695 */ if (savedErrno == ENOSYS || savedErrno == ENOTTY) { /* * NFS allows renames of locked files, even if both files * are locked. The file lock follows the file handle, not * the name, so after the rename we can swap the underlying * file descriptors instead of closing and reopening the * target file. * * This is different than the hosted path below because * ESX uses native file locks and hosted does not. * * We assume that all ESX file systems that support rename * have the same file lock semantics as NFS. */ if (File_Rename(newPath, currPath)) { Log("%s: rename of '%s' to '%s' failed %d.\n", __FUNCTION__, newPath, currPath, errno); savedErrno = errno; goto swapdone; } ret = TRUE; fd = newFD->posix; newFD->posix = currFD->posix; currFD->posix = fd; FileIO_Close(newFD); } swapdone: free(args); free(dirName); free(fileName); free(dstDirName); free(dstFileName); free(currPath); free(newPath); errno = savedErrno; return ret; #else NOT_REACHED(); #endif } #if defined(_WIN32) currPath = Unicode_Duplicate(FileIO_Filename(currFD)); newPath = Unicode_Duplicate(FileIO_Filename(newFD)); newAccess = newFD->flags; currAccess = currFD->flags; FileIO_Close(newFD); /* * The current file needs to be closed and reopened, * but we don't want to drop the file lock by calling * FileIO_Close() on it. Instead, use native close primitives. * We'll reopen it later with FileIO_Open. Set the * descriptor/handle to an invalid value while we're in the * middle of transferring ownership. */ CloseHandle(currFD->win32); currFD->win32 = INVALID_HANDLE_VALUE; if (File_RenameRetry(newPath, currPath, 10) == 0) { ret = TRUE; } else { savedErrno = errno; ASSERT(!ret); } FileIO_Invalidate(&tmpFD); /* * Clear the locking bits from the requested access so that reopening * the file ignores the advisory lock. */ ASSERT((currAccess & FILEIO_OPEN_LOCK_MANDATORY) == 0); currAccess &= ~(FILEIO_OPEN_LOCK_MANDATORY | FILEIO_OPEN_LOCK_ADVISORY | FILEIO_OPEN_LOCK_BEST | FILEIO_OPEN_LOCKED); status = FileIO_Open(&tmpFD, currPath, currAccess, FILEIO_OPEN); if (!FileIO_IsSuccess(status)) { Panic("Failed to reopen dictionary after renaming " "\"%s\" to \"%s\": %s (%d)\n", newPath, currPath, FileIO_ErrorEnglish(status), status); } ASSERT(tmpFD.lockToken == NULL); currFD->win32 = tmpFD.win32; FileIO_Cleanup(&tmpFD); Unicode_Free(currPath); Unicode_Free(newPath); errno = savedErrno; return ret; #else currPath = (char *)FileIO_Filename(currFD); newPath = (char *)FileIO_Filename(newFD); if (File_Rename(newPath, currPath)) { Log("%s: rename of '%s' to '%s' failed %d.\n", __FUNCTION__, newPath, currPath, errno); savedErrno = errno; } else { ret = TRUE; fd = newFD->posix; newFD->posix = currFD->posix; currFD->posix = fd; FileIO_Close(newFD); } errno = savedErrno; return ret; #endif }
int FileLockMemberValues(ConstUnicode lockDir, // IN: ConstUnicode fileName, // IN: char *buffer, // OUT: uint32 requiredSize, // IN: LockValues *memberValues) // OUT: { #ifndef __MINGW32__ uint32 argc = 0; FILELOCK_FILE_HANDLE handle; uint32 len; char *argv[FL_MAX_ARGS]; char *saveptr = NULL; int err; Unicode path; FileData fileData; ParseTable table = { PARSE_TABLE_STRING, "lc", (void *) &memberValues->locationChecksum }; ASSERT(lockDir); ASSERT(fileName); path = Unicode_Join(lockDir, DIRSEPS, fileName, NULL); err = FileLockOpenFile(path, O_RDONLY, &handle); if (err != 0) { /* * A member file may "disappear" if is deleted due to an unlock * immediately after a directory scan but before the scan is processed. * Since this is a "normal" thing ENOENT will be suppressed. */ if (err != ENOENT) { Warning(LGPFX" %s open failure on '%s': %s\n", __FUNCTION__, UTF8(path), strerror(err)); } goto bail; } /* Attempt to obtain the lock file attributes now that it is opened */ err = FileAttributesRobust(path, &fileData); if (err != 0) { Warning(LGPFX" %s file size failure on '%s': %s\n", __FUNCTION__, UTF8(path), strerror(err)); FileLockCloseFile(handle); goto bail; } /* Complain if the lock file is not the proper size */ if (fileData.fileSize != requiredSize) { Warning(LGPFX" %s file '%s': size %"FMT64"u, required size %u\n", __FUNCTION__, UTF8(path), fileData.fileSize, requiredSize); FileLockCloseFile(handle); goto corrupt; } /* Attempt to read the lock file data and validate how much was read. */ err = FileLockReadFile(handle, buffer, requiredSize, &len); FileLockCloseFile(handle); if (err != 0) { Warning(LGPFX" %s read failure on '%s': %s\n", __FUNCTION__, UTF8(path), strerror(err)); goto bail; } if (len != requiredSize) { Warning(LGPFX" %s read length issue on '%s': %u and %u\n", __FUNCTION__, UTF8(path), len, requiredSize); err = EIO; goto bail; } /* Extract and validate the lock file data. */ for (argc = 0; argc < FL_MAX_ARGS; argc++) { argv[argc] = strtok_r((argc == 0) ? buffer : NULL, " ", &saveptr); if (argv[argc] == NULL) { break; } } if ((argc < 4) || ((argc == FL_MAX_ARGS) && (strtok_r(NULL, " ", &saveptr) != NULL))) { goto corrupt; } /* * Lock file arguments are space separated. There is a minimum of 4 * arguments - machineID, executionID, Lamport number and lock type. * The maximum number of arguments is FL_MAX_ARGS. * * The fifth argument, if present, is the payload or "[" if there is no * payload and additional arguments are present. The additional arguments * form a properly list - one or more "name=value" pairs. * * Here is picture of valid forms: * * 0 1 2 3 4 5 6 Comment *------------------------- * A B C D contents, no payload, no list entries * A B C D [ contents, no payload, no list entries * A B C D P contents, a payload, no list entries * A B C D [ x contents, no payload, one list entry * A B C D P x contents, a payload, one list entry * A B C D [ x y contents, no payload, two list entries * A B C D P x y contents, a payload, two list entries */ memberValues->locationChecksum = NULL; if (argc == 4) { memberValues->payload = NULL; } else { if (strcmp(argv[4], "[") == 0) { memberValues->payload = NULL; } else { memberValues->payload = argv[4]; } if (FileLockParseArgs(argv, argc - 5, &table, 1)) { goto corrupt; } } if (sscanf(argv[2], "%u", &memberValues->lamportNumber) != 1) { goto corrupt; } if ((strcmp(argv[3], LOCK_SHARED) != 0) && (strcmp(argv[3], LOCK_EXCLUSIVE) != 0)) { goto corrupt; } memberValues->machineID = argv[0]; memberValues->executionID = argv[1]; memberValues->lockType = argv[3]; memberValues->memberName = Unicode_Duplicate(fileName); Unicode_Free(path); return 0; corrupt: Warning(LGPFX" %s removing problematic lock file '%s'\n", __FUNCTION__, UTF8(path)); if (argc) { Log(LGPFX" %s '%s' contents are:\n", __FUNCTION__, UTF8(fileName)); for (len = 0; len < argc; len++) { Log(LGPFX" %s %s argv[%d]: '%s'\n", __FUNCTION__, UTF8(fileName), len, argv[len]); } } /* Remove the lock file and behave like it has disappeared */ err = FileDeletionRobust(path, FALSE); if (err == 0) { err = ENOENT; } bail: Unicode_Free(path); return err; #else // XXX - incomplete: needs a win/mingw32 implementation, if required. NOT_IMPLEMENTED(); return 0; #endif }