Beispiel #1
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
}
Beispiel #2
0
static int
DnD_TryInitVmblock(const char *vmbFsName,          // IN
                   const char *vmbMntPoint,        // IN
                   const char *vmbDevice,          // IN
                   mode_t vmbDeviceMode,           // IN
                   Bool (*verifyBlock)(int fd))    // IN
{
#if defined NO_SETMNTENT || defined NO_ENDMNTENT
   NOT_IMPLEMENTED();
   errno = ENOSYS;
   return -1;
#else
   Bool found = FALSE;
   int blockFd = -1;
   char *realMntPoint;
   MNTHANDLE fp;
   DECLARE_MNTINFO(mnt);

   ASSERT(vmbFsName);
   ASSERT(vmbMntPoint);
   ASSERT(vmbDevice);

   /* Resolve desired mount point in case it is symlinked somewhere */
   realMntPoint = Posix_RealPath(vmbMntPoint);
   if (!realMntPoint) {
      /*
       * If resolve failed for some reason try to fall back to
       * original mount point specification.
       */
      realMntPoint = Util_SafeStrdup(vmbMntPoint);
   }

   /* Make sure the vmblock file system is mounted. */
   fp = OPEN_MNTFILE("r");
   if (fp == NULL) {
      LOG(1, ("%s: could not open mount file\n", __func__));
      goto out;
   }

   while (GETNEXT_MNTINFO(fp, mnt)) {
      /*
       * In the future we can publish the mount point in VMDB so that the UI
       * can use it rather than enforcing the VMBLOCK_MOUNT_POINT check here.
       */

      if (strcmp(MNTINFO_FSTYPE(mnt), vmbFsName) == 0 &&
          strcmp(MNTINFO_MNTPT(mnt), realMntPoint) == 0) {
         found = TRUE;
         break;
      }
   }

   (void) CLOSE_MNTFILE(fp);

   if (found) {
      /* Open device node for communication with vmblock. */
      blockFd = Posix_Open(vmbDevice, vmbDeviceMode);
      if (blockFd < 0) {
         LOG(1, ("%s: Can not open blocker device (%s)\n",
                 __func__, strerror(errno)));
      } else {
         LOG(4, ("%s: Opened blocker device at %s\n",
                 __func__, VMBLOCK_DEVICE));
         if (verifyBlock && !verifyBlock(blockFd)) {
            LOG(4, ("%s: Blocker device at %s did not pass checks, closing.\n",
                    __func__, VMBLOCK_DEVICE));
            close(blockFd);
            blockFd = -1;
         }
      }
   }

out:
   free(realMntPoint);
   return blockFd;
#endif
}
Beispiel #3
0
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;
}