Example #1
0
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);
}
Example #4
0
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;
}
Example #6
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;
}
Example #7
0
void
FileIO_Init(FileIODescriptor *fd,   // IN/OUT:
            ConstUnicode pathName)  // IN:
{
    ASSERT(fd);
    ASSERT(pathName);

    fd->fileName = Unicode_Duplicate(pathName);
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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);
   }
}
Example #11
0
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
}