Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #8
0
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;
}
Exemple #9
0
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;
}
Exemple #10
0
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;
}
Exemple #11
0
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;
}