228
241
*----------------------------------------------------------------------
243
* FileIOResolveLockBits --
245
* Resolve the multitude of lock bits from historical public names
246
* to newer internal names.
248
* Input flags: FILEIO_OPEN_LOCKED a.k.a. FILEIO_OPEN_LOCK_BEST,
249
* FILEIO_OPEN_EXCLUSIVE_LOCK
250
* Output flags: FILEIO_OPEN_LOCK_MANDATORY, FILEIO_OPEN_LOCK_ADVISORY
256
* Only output flags are set in *access.
258
*----------------------------------------------------------------------
262
FileIOResolveLockBits(int *access) // IN/OUT: FILEIO_OPEN_* bits
266
* none: no locking at all
267
* advisory: open() ignores lock, FileIO_ respects lock.
268
* mandatory: open() and FileIO_ respect lock.
269
* "best": downgrades to advisory or mandatory based on OS support
271
if ((*access & FILEIO_OPEN_EXCLUSIVE_LOCK) != 0) {
272
*access &= ~FILEIO_OPEN_EXCLUSIVE_LOCK;
273
*access |= FILEIO_OPEN_LOCK_MANDATORY;
275
if ((*access & FILEIO_OPEN_LOCK_BEST) != 0) {
276
/* "Best effort" bit: mandatory if OS supports, advisory otherwise */
277
*access &= ~FILEIO_OPEN_LOCK_BEST;
278
if (HostType_OSIsVMK()) {
279
*access |= FILEIO_OPEN_LOCK_MANDATORY;
281
*access |= FILEIO_OPEN_LOCK_ADVISORY;
285
/* Only one lock type (or none at all) allowed */
286
ASSERT(((*access & FILEIO_OPEN_LOCK_ADVISORY) == 0) ||
287
((*access & FILEIO_OPEN_LOCK_MANDATORY) == 0));
292
*----------------------------------------------------------------------
232
296
* Call the FileLock module to lock the given file.
235
* FILEIO_SUCCESS All is well
236
* FILEIO_LOCK_FAILED Requested lock on file was not acquired
237
* FILEIO_ERROR A serious error occured.
299
* FILEIO_ERROR A serious error occured.
300
* FILEIO_SUCCESS All is well
301
* FILEIO_LOCK_FAILED Requested lock on file was not acquired
302
* FILEIO_FILE_NOT_FOUND Unable to find the specified file
303
* FILEIO_NO_PERMISSION Permissions issues
304
* FILEIO_FILE_NAME_TOO_LONG The path name is too long
474
629
return res == FILEIO_SUCCESS;
635
*-----------------------------------------------------------------------------
637
* FileIOAtomicTempPath
639
* Return a temp path name in the same directory as the argument file.
640
* The path is the full path of the source file with a '~' appended.
641
* The caller must free the path when done.
644
* Unicode path if successful, NULL on failure.
649
*-----------------------------------------------------------------------------
653
FileIOAtomicTempPath(FileIODescriptor *fileFD) // IN:
658
ASSERT(FileIO_IsValid(fileFD));
660
srcPath = File_FullPath(FileIO_Filename(fileFD));
662
Log("%s: File_FullPath of '%s' failed.\n", __FUNCTION__,
663
FileIO_Filename(fileFD));
666
path = Unicode_Join(srcPath, "~", NULL);
667
Unicode_Free(srcPath);
674
*-----------------------------------------------------------------------------
676
* FileIO_AtomicTempFile
678
* Create a temp file in the same directory as the argument file.
679
* On non-Windows attempts to create the temp file with the same
680
* permissions and owner/group as the argument file.
683
* FileIOResult of call that failed or FILEIO_SUCCESS
686
* Creates a new file.
688
*-----------------------------------------------------------------------------
692
FileIO_AtomicTempFile(FileIODescriptor *fileFD, // IN:
693
FileIODescriptor *tempFD) // OUT:
695
Unicode tempPath = NULL;
703
ASSERT(FileIO_IsValid(fileFD));
704
ASSERT(tempFD && !FileIO_IsValid(tempFD));
706
tempPath = FileIOAtomicTempPath(fileFD);
708
status = FILEIO_ERROR;
714
File_UnlinkIfExists(tempPath);
716
if (fstat(fileFD->posix, &stbuf)) {
717
Log("%s: Failed to fstat '%s', errno: %d.\n", __FUNCTION__,
718
FileIO_Filename(fileFD), errno);
719
ASSERT(!vmx86_server); // For APD, hosted can fall-back and write directly
720
status = FILEIO_ERROR;
723
permissions = stbuf.st_mode;
725
/* Do a "cleanup" unlink in case some previous process left a temp file around */
726
ret = Posix_Unlink(tempPath);
727
if (ret != 0 && errno != ENOENT) { /* ENOENT is expected, file should not exist */
728
Log("%s: Failed to unlink temporary file, errno: %d\n",
729
__FUNCTION__, errno);
730
/* Fall through; FileIO_Create will report the actual error */
734
status = FileIO_Create(tempFD, tempPath,
735
FILEIO_ACCESS_READ | FILEIO_ACCESS_WRITE,
736
FILEIO_OPEN_CREATE_SAFE, permissions);
737
if (!FileIO_IsSuccess(status)) {
738
Log("%s: Failed to create temporary file, err: %d\n", __FUNCTION__,
745
* On ESX we always use the vmkernel atomic file swap primitive, so
746
* there's no need to set the permissions and owner of the temp file.
749
if (!HostType_OSIsVMK()) {
750
if (fchmod(tempFD->posix, stbuf.st_mode)) {
751
Log("%s: Failed to chmod temporary file, errno: %d\n",
752
__FUNCTION__, errno);
753
status = FILEIO_ERROR;
756
if (fchown(tempFD->posix, stbuf.st_uid, stbuf.st_gid)) {
757
Log("%s: Failed to chown temporary file, errno: %d\n",
758
__FUNCTION__, errno);
759
status = FILEIO_ERROR;
765
Unicode_Free(tempPath);
766
return FILEIO_SUCCESS;
769
ASSERT(!FileIO_IsSuccess(status));
770
if (FileIO_IsValid(tempFD)) {
771
FileIO_Close(tempFD);
773
File_UnlinkIfExists(tempPath);
775
ret = Posix_Unlink(tempPath);
777
Log("%s: Failed to clean up temporary file, errno: %d\n",
778
__FUNCTION__, errno);
783
Unicode_Free(tempPath);
789
*-----------------------------------------------------------------------------
791
* FileIO_AtomicUpdate --
793
* On ESX when the target files reside on vmfs, exchanges the contents
794
* of two files using code modeled from VmkfsLib_SwapFiles. Both "curr"
795
* and "new" are left open.
797
* On ESX when the target files reside on NFS, and on hosted products,
798
* uses rename to swap files, so "new" becomes "curr", and path to "new"
799
* no longer exists on success.
801
* On success the caller must call FileIO_IsValid on newFD to verify it
802
* is still open before using it again.
805
* TRUE if successful, FALSE on failure.
810
*-----------------------------------------------------------------------------
815
FileIO_AtomicUpdate(FileIODescriptor *newFD, // IN/OUT: file IO descriptor
816
FileIODescriptor *currFD) // IN/OUT: file IO descriptor
825
ASSERT(FileIO_IsValid(newFD));
826
ASSERT(FileIO_IsValid(currFD));
828
if (HostType_OSIsVMK()) {
829
#if defined(VMX86_SERVER)
830
FS_SwapFilesArgs *args = NULL;
831
char *dirName = NULL;
832
char *fileName = NULL;
833
char *dstDirName = NULL;
834
char *dstFileName = NULL;
838
currPath = File_FullPath(FileIO_Filename(currFD));
839
newPath = File_FullPath(FileIO_Filename(newFD));
844
File_GetPathName(newPath, &dirName, &fileName);
845
File_GetPathName(currPath, &dstDirName, &dstFileName);
847
ASSERT(dirName && *dirName);
848
ASSERT(fileName && *fileName);
849
ASSERT(dstDirName && *dstDirName);
850
ASSERT(dstFileName && *dstFileName);
851
ASSERT(!strcmp(dirName, dstDirName));
853
args = (FS_SwapFilesArgs *) Util_SafeCalloc(1, sizeof(*args));
854
if (Str_Snprintf(args->srcFile, sizeof(args->srcFile), "%s",
856
Log("%s: Path too long \"%s\".\n", __FUNCTION__, fileName);
859
if (Str_Snprintf(args->dstFilePath, sizeof(args->dstFilePath), "%s/%s",
860
dstDirName, dstFileName) < 0) {
861
Log("%s: Path too long \"%s\".\n", __FUNCTION__, dstFileName);
866
* Issue the ioctl on the directory rather than on the file,
867
* because the file could be open.
870
fd = Posix_Open(dirName, O_RDONLY);
872
Log("%s: Open failed \"%s\" %d.\n", __FUNCTION__, dirName,
874
ASSERT_BUG_DEBUGONLY(615124, errno != EBUSY);
879
if (ioctl(fd, IOCTLCMD_VMFS_SWAP_FILES, args) != 0) {
881
if (errno != ENOSYS) {
882
Log("%s: ioctl failed %d.\n", __FUNCTION__, errno);
883
ASSERT_BUG_DEBUGONLY(615124, errno != EBUSY);
892
* Did we fail because we are on NFS?
894
if (savedErrno == ENOSYS) {
896
* NFS allows renames of locked files, even if both files
897
* are locked. The file lock follows the file handle, not
898
* the name, so after the rename we can swap the underlying
899
* file descriptors instead of closing and reopening the
902
* This is different than the hosted path below because
903
* ESX uses native file locks and hosted does not.
906
if (File_Rename(newPath, currPath)) {
907
Log("%s: rename of '%s' to '%s' failed %d.\n",
908
newPath, currPath, __FUNCTION__, errno);
913
newFD->posix = currFD->posix;
933
currPath = Unicode_Duplicate(FileIO_Filename(currFD));
934
newPath = Unicode_Duplicate(FileIO_Filename(newFD));
936
newAccess = newFD->flags;
937
currAccess = currFD->flags;
942
* The current file needs to be closed and reopened,
943
* but we don't want to drop the file lock by calling
944
* FileIO_Close() on it. Instead, use native close primitives.
945
* We'll reopen it later with a temp FileIODescriptor, and
946
* swap the file descriptor/handle. Set the descriptor/handle
947
* to an invalid value while we're in the middle of transferring
952
CloseHandle(currFD->win32);
953
currFD->win32 = INVALID_HANDLE_VALUE;
955
close(currFD->posix);
958
if (File_RenameRetry(newPath, currPath, 10)) {
967
* XXX - We shouldn't drop the file lock here.
968
* Need to implement FileIO_Reopen to close
969
* and reopen without dropping the lock.
972
FileIO_Close(currFD); // XXX - PR 769296
974
status = FileIO_Open(currFD, currPath, currAccess, 0);
975
if (!FileIO_IsSuccess(status)) {
976
Panic("Failed to reopen dictionary file.\n");
979
Unicode_Free(currPath);
980
Unicode_Free(newPath);