/********************************************************* * Copyright (C) 2011-2015 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #if defined(_WIN32) #include #endif #include #include #include #include #include #include #include #include #include "vmware.h" #include "log.h" #include "file.h" #include "fileInt.h" #include "util.h" #include "unicodeOperations.h" #include "posix.h" #if !defined(O_BINARY) #define O_BINARY 0 #endif /* *---------------------------------------------------------------------- * * FileTempNum -- * * Compute a number to be used as an attachment to a base name. * In order to avoid race conditions, files and directories are * kept separate via enforced odd (file) and even (directory) * numberings. * * Regardless of the input value of *var, the output value will * be even or odd as determined by createTempFile. * * Results: * An odd number if createTempFile is TRUE. * An even number if createTempFile is FALSE. * * Side effects: * None * *---------------------------------------------------------------------- */ static void FileTempNum(Bool createTempFile, // IN: uint32 *var) // IN/OUT: { ASSERT(var); *var += (FileSimpleRandom() >> 8) & 0xFF; *var = (*var & ~0x1) | (createTempFile ? 1 : 0); } /* *---------------------------------------------------------------------- * * File_MakeTempEx2 -- * * Create a temporary file or a directory. * If a temporary file is created successfully, then return an open file * descriptor to that file. * * 'dir' specifies the directory in which to create the file. It * must not end in a slash. * * 'createTempFile', if TRUE, then a temporary file will be created. If * FALSE, then a temporary directory will be created. * * 'createNameFunc' specifies the user-specified callback function that * will be called to construct the fileName. 'createNameFuncData' will be * passed everytime 'createNameFunc' is called. 'createNameFunc' * should return the proper fileName. * * Check the documentation for File_MakeTempHelperFunc. * * Results: * if a temporary file is created, then Open file descriptor or -1; * if a temporary directory is created, then 0 or -1; * If successful then presult points to a dynamically allocated * string with the pathname of the temp file. * * Side effects: * Creates the requested object when successful. Errno is set on error * * Files and directories are effectively in separate name spaces; * the numerical value attached via createNameFunc is odd for files * and even for directories. * *---------------------------------------------------------------------- */ int File_MakeTempEx2(ConstUnicode dir, // IN: Bool createTempFile, // IN: File_MakeTempCreateNameFunc *createNameFunc, // IN: void *createNameFuncData, // IN: Unicode *presult) // OUT: { uint32 i; int fd = -1; uint32 var = 0; Unicode path = NULL; if ((dir == NULL) || (createNameFunc == NULL)) { errno = EFAULT; return -1; } ASSERT(presult); *presult = NULL; for (i = 0; i < (MAX_INT32 / 2); i++) { Unicode fileName; /* construct suffixed pathname to use */ Unicode_Free(path); path = NULL; /* * Files and directories are kept separate (odd and even respectfully). * This way the available exclusion mechanisms work properly - O_EXCL * on files, mkdir on directories - and races are avoided. * * Not attempting an open on a directory is a good thing... */ FileTempNum(createTempFile, &var); fileName = (*createNameFunc)(var, createNameFuncData); ASSERT(fileName); /* construct base full pathname to use */ path = Unicode_Join(dir, DIRSEPS, fileName, NULL); Unicode_Free(fileName); if (createTempFile) { fd = Posix_Open(path, O_CREAT | O_EXCL | O_BINARY | O_RDWR, 0600); } else { fd = Posix_Mkdir(path, 0700); } if (fd != -1) { *presult = path; path = NULL; break; } if (errno != EEXIST) { Log(LGPFX" Failed to create temporary %s \"%s\": %s.\n", createTempFile ? "file" : "directory", UTF8(path), strerror(errno)); goto exit; } } if (fd == -1) { Warning(LGPFX" Failed to create temporary %s \"%s\": " "The name space is full.\n", createTempFile ? "file" : "directory", UTF8(path)); errno = EAGAIN; } exit: Unicode_Free(path); return fd; } /* *---------------------------------------------------------------------------- * * FileMakeTempExCreateNameFunc -- * * This is a helper function designed for File_MakeTempEx function. * Everytime this function is called, this creates a fileName with the * format and returns back to the caller. * * 'num' specifies the nth time this function is called. * * 'data' specifies the payload that is specified when File_MakeTempEx2() * function is called. This points to a Unicode string. * * Results: * if successful, a dynamically allocated string with the basename of * the temp file. NULL otherwise. * * Side effects: * None * *---------------------------------------------------------------------------- */ static Unicode FileMakeTempExCreateNameFunc(uint32 num, // IN: void *data) // IN: { if (data == NULL) { return NULL; } return Unicode_Format("%s%u", (Unicode) data, num); } /* *---------------------------------------------------------------------- * * File_MakeTempEx -- * * Create a temporary file and, if successful, return an open file * descriptor to that file. * * 'dir' specifies the directory in which to create the file. It * must not end in a slash. * * 'fileName' specifies the base filename of the created file. * * Results: * Open file descriptor or -1; if successful then presult points * to a dynamically allocated string with the pathname of the temp * file. * * Side effects: * Creates a file if successful. Errno is set on error * *---------------------------------------------------------------------- */ int File_MakeTempEx(ConstUnicode dir, // IN: ConstUnicode fileName, // IN: Unicode *presult) // OUT: { return File_MakeTempEx2(dir, TRUE, FileMakeTempExCreateNameFunc, (void *) fileName, presult); } /* *---------------------------------------------------------------------- * * File_MakeSafeTempDir -- * * Create a temporary directory in a safe area. * * Optional argument 'prefix' specifies the name prefix of the * created directory. When not provided a default will be provided. * * Results: * NULL Failure * !NULL Path name of created directory * * Side effects: * Creates a directory if successful. Errno is set on error * *---------------------------------------------------------------------- */ Unicode File_MakeSafeTempDir(ConstUnicode prefix) // IN: { Unicode result = NULL; Unicode dir = File_GetSafeTmpDir(TRUE); if (dir != NULL) { ConstUnicode effectivePrefix = (prefix == NULL) ? "safeDir" : prefix; File_MakeTempEx2(dir, FALSE, FileMakeTempExCreateNameFunc, (void *) effectivePrefix, &result); Unicode_Free(dir); } return result; } /* *---------------------------------------------------------------------- * * File_MakeSafeTemp -- * * Exactly the same as File_MakeTempEx except uses a safe directory * as the default temporary directory. * * Results: * Open file descriptor or -1 * * Side effects: * Creates a file if successful. * *---------------------------------------------------------------------- */ 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; } /* *----------------------------------------------------------------------------- * * File_DoesVolumeSupportAcls -- * * Determines if the volume that the pathname resides on supports * ACLs. * * Results: * TRUE it does * FALSE it doesn't * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool File_DoesVolumeSupportAcls(ConstUnicode path) // IN: { Bool succeeded = FALSE; #if defined(_WIN32) Bool res; Unicode vol, 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: Unicode_Free(vol); Unicode_Free(vol2); #endif return succeeded; }