From: VMware, Inc <> Date: Mon, 20 Sep 2010 18:25:42 +0000 (-0700) Subject: Internal branch sync. Included in this change: X-Git-Tag: 2010.09.19-301124~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c92a8bfbb406a906bcd2fb9ef6801f92c5b64d1f;p=thirdparty%2Fopen-vm-tools.git Internal branch sync. Included in this change: . VIX: add new opcodes for TerminateProcess, DeleteFile, DeleteDirectory. . changes in shared code that don't affect open-vm-tools functionality. Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/lib/file/file.c b/open-vm-tools/lib/file/file.c index 31ae9320c..5928d5fb6 100644 --- a/open-vm-tools/lib/file/file.c +++ b/open-vm-tools/lib/file/file.c @@ -355,7 +355,27 @@ File_EnsureDirectory(ConstUnicode pathName) // IN: Bool File_DeleteEmptyDirectory(ConstUnicode pathName) // IN: { - return (FileRemoveDirectory(pathName) == 0) ? TRUE : FALSE; + Bool returnValue = TRUE; + + if (FileRemoveDirectory(pathName) != 0) { +#if defined(_WIN32) + /* + * Directory may have read-only bit set. Unset the + * read-only bit and try deleting one more time. + */ + if (File_SetFilePermissions(pathName, S_IWUSR)) { + if (FileRemoveDirectory(pathName) != 0) { + returnValue = FALSE; + } + } else { + returnValue = FALSE; + } +#else + returnValue = FALSE; +#endif + } + + return returnValue; } @@ -2563,3 +2583,271 @@ FileSleeper(uint32 msecMinSleepTime, // IN: return msecActualSleepTime; } #endif // N_PLAT_NLM + + +/* + *---------------------------------------------------------------------- + * + * FileRotateByRename -- + * + * The oldest indexed file should be removed so that the + * consequent rename succeeds. + * + * The last dst is 'fileName' and should not be deleted. + * + * Results: + * If newFileName is non-NULL: the new path is returned to + * *newFileName if the rotation succeeded, otherwise NULL + * is returned in *newFileName. The caller is responsible + * for freeing the string returned in *newFileName. + * + * Side effects: + * Rename backup old files kept so far. + * + *---------------------------------------------------------------------- + */ + +static void +FileRotateByRename(const char *fileName, // IN: full path to file + const char *baseName, // IN: filename w/o extension. + const char *ext, // IN: extension + int n, // IN: number of old files to keep + char **newFileName) // OUT/OPT: new path to file +{ + char *src = NULL; + char *dst = NULL; + int i; + int result; + + for (i = n; i >= 0; i--) { + src = (i == 0) ? (char *) fileName : + Str_SafeAsprintf(NULL, "%s-%d%s", baseName, i - 1, ext); + + if (dst != NULL) { + result = Posix_Rename(src, dst); + if (result == -1) { + int error = Err_Errno(); + if (error != ENOENT) { + Log("LOG failed to rename %s -> %s: %s\n", src, dst, + Err_Errno2String(error)); + } + } + } else { + result = File_UnlinkIfExists(src); + if (result == -1) { + Log("LOG failed to remove %s: %s\n", src, Msg_ErrString()); + } + } + if (src == fileName && newFileName != NULL) { + *newFileName = result == -1 ? NULL : strdup(dst); + } + ASSERT(dst != fileName); + free(dst); + dst = src; + } +} + + +/* + *---------------------------------------------------------------------- + * + * FileNumberCompare -- + * + * Helper function for comparing the contents of two + * uint32 pointers a and b, suitable for use by qsort + * to order an array of file numbers. + * + * Results: + * The contents of 'a' minus the contents of 'b'. + * + * Side effects: + * None. + */ + +static int +FileNumberCompare(const void *a, // IN: + const void *b) // IN: +{ + return *(uint32 *)a - *(uint32 *)b; +} + + +/* + *---------------------------------------------------------------------- + * + * FileRotateByRenumber -- + * + * File rotation scheme optimized for vmfs: + * 1) find highest numbered file (maxNr) + * 2) rename . to -. + * 3) delete (nFound - numToKeep) lowest numbered files. + * + * Wrap around is handled incorrectly. + * + * Results: + * If newFilePath is non-NULL: the new path is returned to + * *newFilePath if the rotation succeeded, otherwise NULL + * is returned in *newFilePath. The caller is responsible + * for freeing the string returned in *newFilePath. + * + * Side effects: + * Files renamed / deleted. + * + *---------------------------------------------------------------------- + */ + +static void +FileRotateByRenumber(const char *filePath, // IN: full path to file + const char *filePathNoExt, // IN: filename w/o extension. + const char *ext, // IN: extension + int n, // IN: number old files to keep + char **newFilePath) // OUT/OPT: new path to file +{ + char *baseDir = NULL, *fmtString = NULL, *baseName = NULL, *tmp; + char *fullPathNoExt = NULL; + uint32 maxNr = 0; + int i, nrFiles, nFound = 0; + char **fileList = NULL; + uint32 *fileNumbers; + int result; + + fullPathNoExt = File_FullPath(filePathNoExt); + if (fullPathNoExt == NULL) { + Log("%s: failed to get full path for '%s'.\n", __FUNCTION__, + filePathNoExt); + goto cleanup; + } + + File_GetPathName(fullPathNoExt, &baseDir, &baseName); + if ((baseDir[0] == '\0') || (baseName[0] == '\0')) { + Log("%s: failed to get base dir for path '%s'.\n", __FUNCTION__, + filePathNoExt); + goto cleanup; + } + + fmtString = Str_SafeAsprintf(NULL, "%s-%%d%s%%n", baseName, ext); + + nrFiles = File_ListDirectory(baseDir, &fileList); + if (nrFiles == -1) { + Log("%s: failed to read the directory '%s'.\n", __FUNCTION__, + baseDir); + goto cleanup; + } + + fileNumbers = Util_SafeCalloc(nrFiles, sizeof(uint32)); + + for (i = 0; i < nrFiles; i++) { + uint32 curNr; + int bytesProcessed = 0; + + /* + * Make sure the whole file name matched what we expect for the file. + */ + + if ((sscanf(fileList[i], fmtString, &curNr, &bytesProcessed) >= 1) && + (bytesProcessed == strlen(fileList[i]))) { + fileNumbers[nFound++] = curNr; + } + free(fileList[i]); + } + + if (nFound > 0) { + qsort(fileNumbers, nFound, sizeof(uint32), FileNumberCompare); + maxNr = fileNumbers[nFound - 1]; + } + + /* rename the existing file to the next number */ + tmp = Str_SafeAsprintf(NULL, "%s/%s-%d%s", baseDir, baseName, maxNr + 1, ext); + result = Posix_Rename(filePath, tmp); + if (result == -1) { + int error = Err_Errno(); + if (error != ENOENT) { + Log("%s: failed to rename %s -> %s failed: %s\n", __FUNCTION__, + filePath, tmp, Err_Errno2String(error)); + } + } + if (newFilePath != NULL) { + if (result == -1) { + *newFilePath = NULL; + free(tmp); + } else { + *newFilePath = tmp; + } + } + + if (nFound >= n) { + /* Delete the extra files. */ + for (i = 0; i <= nFound - n; i++) { + tmp = Str_SafeAsprintf(NULL, "%s/%s-%d%s", baseDir, baseName, + fileNumbers[i], ext); + + if (Posix_Unlink(tmp) == -1) { + Log("%s: failed to remove %s: %s\n", __FUNCTION__, + tmp, Msg_ErrString()); + } + free(tmp); + } + } + + cleanup: + free(fileList); + free(fmtString); + free(baseDir); + free(baseName); + free(fullPathNoExt); +} + + +/* + *---------------------------------------------------------------------- + * + * File_Rotate -- + * + * Rotate old files. The 'noRename' option is useful for filesystems + * where rename is hideously expensive (*cough* vmfs). + * + * Results: + * If newFileName is non-NULL: the new path is returned to + * *newFileName if the rotation succeeded, otherwise NULL + * is returned in *newFileName. The caller is responsible + * for freeing the string returned in *newFileName. + * + * Side effects: + * Files are renamed / deleted. + * + *---------------------------------------------------------------------- + */ + +void +File_Rotate(const char *fileName, // IN: original file + int n, // IN: number of backup files + Bool noRename, // IN: don't rename all files + char **newFileName) // OUT/OPT: new path to file +{ + const char *ext; + size_t baseLen; + char *baseName; + + if ((ext = Str_Strrchr(fileName, '.')) == NULL) { + ext = fileName + strlen(fileName); + } + baseLen = ext - fileName; + + /* + * Backup base of file name. + * + * Since the Str_Asprintf(...) doesn't like format of %.*s and crashes + * in Windows 2000. (Daniel Liu) + */ + + baseName = Util_SafeStrdup(fileName); + baseName[baseLen] = '\0'; + + if (noRename) { + FileRotateByRenumber(fileName, baseName, ext, n, newFileName); + } else { + FileRotateByRename(fileName, baseName, ext, n, newFileName); + } + + free(baseName); +} diff --git a/open-vm-tools/lib/foundryMsg/foundryMsg.c b/open-vm-tools/lib/foundryMsg/foundryMsg.c index 6042f00b5..3ca2f5334 100644 --- a/open-vm-tools/lib/foundryMsg/foundryMsg.c +++ b/open-vm-tools/lib/foundryMsg/foundryMsg.c @@ -470,6 +470,13 @@ static const VixCommandInfo vixCommandInfoTable[] = { VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VALIDATE_CREDENTIALS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_TERMINATE_PROCESS, + VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_GUEST_FILE_EX, + VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_GUEST_DIRECTORY_EX, + VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), + }; diff --git a/open-vm-tools/lib/include/file.h b/open-vm-tools/lib/include/file.h index af8aefa87..20576cb81 100644 --- a/open-vm-tools/lib/include/file.h +++ b/open-vm-tools/lib/include/file.h @@ -276,6 +276,11 @@ Bool File_Replace(ConstUnicode oldFile, Bool File_Rename(ConstUnicode oldFile, ConstUnicode newFile); +void File_Rotate(const char *fileName, + int n, + Bool noRename, + char **newFileName); + int64 File_GetSize(ConstUnicode pathName); int64 File_GetSizeByPath(ConstUnicode pathName); diff --git a/open-vm-tools/lib/include/vixCommands.h b/open-vm-tools/lib/include/vixCommands.h index fefda03e0..45df21ff9 100644 --- a/open-vm-tools/lib/include/vixCommands.h +++ b/open-vm-tools/lib/include/vixCommands.h @@ -1630,6 +1630,19 @@ struct VixMsgCreateTempFileRequestEx { VixMsgCreateTempFileRequestEx; +typedef +#include "vmware_pack_begin.h" +struct { + VixCommandRequestHeader header; + + int32 fileOptions; + uint32 guestPathNameLength; + uint32 filePropertiesLength; + Bool recursive; +} +#include "vmware_pack_end.h" +VixMsgDeleteDirectoryRequest; + /* * ********************************************************** * Connect/Disconnect device request. The response is just a generic @@ -2385,6 +2398,9 @@ enum { VIX_COMMAND_ACQUIRE_CREDENTIALS = 190, VIX_COMMAND_RELEASE_CREDENTIALS = 191, VIX_COMMAND_VALIDATE_CREDENTIALS = 192, + VIX_COMMAND_TERMINATE_PROCESS = 193, + VIX_COMMAND_DELETE_GUEST_FILE_EX = 194, + VIX_COMMAND_DELETE_GUEST_DIRECTORY_EX = 195, /* * HOWTO: Adding a new Vix Command. Step 2a. @@ -2396,7 +2412,7 @@ enum { * Once a new command is added here, a command info field needs to be added * in bora/lib/foundryMsg/foundryMsg.c as well. */ - VIX_COMMAND_LAST_NORMAL_COMMAND = 193, + VIX_COMMAND_LAST_NORMAL_COMMAND = 196, VIX_TEST_UNSUPPORTED_TOOLS_OPCODE_COMMAND = 998, VIX_TEST_UNSUPPORTED_VMX_OPCODE_COMMAND = 999, diff --git a/open-vm-tools/lib/include/vm_product.h b/open-vm-tools/lib/include/vm_product.h index 5b7aba965..d424a270d 100644 --- a/open-vm-tools/lib/include/vm_product.h +++ b/open-vm-tools/lib/include/vm_product.h @@ -121,6 +121,10 @@ #define PRODUCT_VPX_NAME MAKE_NAME("VirtualCenter") +#define PRODUCT_VPXA_NAME PRODUCT_VPX_NAME " Agent" + +#define PRODUCT_FDM_NAME MAKE_NAME("Fault Domain Manager") + #define PRODUCT_WBC_NAME MAKE_NAME("WebCenter") #define PRODUCT_SDK_NAME MAKE_NAME("SDK") @@ -136,6 +140,8 @@ #define PRODUCT_VDM_CLIENT_NAME MAKE_NAME("View Client") #define PRODUCT_VDM_CLIENT_NAME_FOR_LICENSE PRODUCT_VDM_CLIENT_NAME +#define PRODUCT_XVP_SHORT_NAME "XVP" +#define PRODUCT_XVP_NAME MAKE_NAME("vCenter XVP Manager") #define PRODUCT_RMKSCONTAINER_NAME MAKE_NAME("Remote MKS Container") // XXX VMvisor is the underlying technology for possibly several products, @@ -301,7 +307,15 @@ # define PRODUCT_SHORT_NAME PRODUCT_API_SCRIPTING_PERL_NAME # endif #elif defined(VMX86_VPX) -# define PRODUCT_SHORT_NAME PRODUCT_VPX_NAME +# if defined(CSI_FDM) +# define PRODUCT_SHORT_NAME PRODUCT_FDM_NAME +# elif defined(VPXA) +# define PRODUCT_SHORT_NAME PRODUCT_VPXA_NAME +# elif defined(XVP) +# define PRODUCT_SHORT_NAME PRODUCT_XVP_NAME +# else +# define PRODUCT_SHORT_NAME PRODUCT_VPX_NAME +# endif #elif defined(VMX86_WBC) # define PRODUCT_SHORT_NAME PRODUCT_WBC_NAME #elif defined(VMX86_SDK) @@ -390,6 +404,9 @@ # define PRODUCT_NAME_FOR_LICENSE "VMware Workstation" # endif # define PRODUCT_SMP_NAME_FOR_LICENSE "" // None +# elif defined(VMX86_VPX) +# define PRODUCT_NAME_FOR_LICENSE PRODUCT_NAME " Server" +# define PRODUCT_SMP_NAME_FOR_LICENSE "" // None # elif defined(VMX86_WGS_MIGRATION) # define PRODUCT_NAME_FOR_LICENSE PRODUCT_NAME " for " PRODUCT_OS # define PRODUCT_SMP_NAME_FOR_LICENSE "" // None @@ -499,6 +516,9 @@ # define PRODUCT_NAME_FOR_LICENSE "VMware Workstation" # endif # define PRODUCT_SMP_NAME_FOR_LICENSE "" // None +# elif defined(VMX86_VPX) +# define PRODUCT_NAME_FOR_LICENSE PRODUCT_NAME " Server" +# define PRODUCT_SMP_NAME_FOR_LICENSE "" // None # elif defined(VMX86_WGS_MIGRATION) # define PRODUCT_NAME_FOR_LICENSE PRODUCT_NAME " for Win32" # define PRODUCT_SMP_NAME_FOR_LICENSE "" // None diff --git a/open-vm-tools/lib/include/vm_version.h b/open-vm-tools/lib/include/vm_version.h index ce05e4c30..2a6586b85 100644 --- a/open-vm-tools/lib/include/vm_version.h +++ b/open-vm-tools/lib/include/vm_version.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 1998-2004 VMware, Inc. All rights reserved. + * Copyright (C) 1998-2010 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 @@ -233,8 +233,8 @@ #define VMSAFE_FILE_VERSION 1,1,0,PRODUCT_BUILD_NUMBER_NUMERIC #define NETDUMP_VERSION "1.1.0" #define NETDUMP_FILE_VERSION 1,1,0,PRODUCT_BUILD_NUMBER_NUMERIC -#define VDDK_VERSION "1.1.0" -#define VDDK_FILE_VERSION 1,1,0,PRODUCT_BUILD_NUMBER_NUMERIC +#define VDDK_VERSION "5.1.0" +#define VDDK_FILE_VERSION 5,1,0,PRODUCT_BUILD_NUMBER_NUMERIC #define OVFTOOL_VERSION "2.0.1" #define VDM_CLIENT_VERSION "e.x.p" diff --git a/open-vm-tools/lib/misc/hostType.c b/open-vm-tools/lib/misc/hostType.c index e210ceaa2..1d42d362f 100644 --- a/open-vm-tools/lib/misc/hostType.c +++ b/open-vm-tools/lib/misc/hostType.c @@ -30,7 +30,7 @@ #include "hostType.h" #include "str.h" -#ifdef VMX86_SERVER +#if defined(VMX86_SERVER) || (defined(VMX86_VPX) && defined(linux)) #include #include #include @@ -66,7 +66,7 @@ static int HostTypeOSVMKernelType(void) { -#ifdef VMX86_SERVER +#if defined(VMX86_SERVER) || (defined(VMX86_VPX) && defined(linux)) static int vmkernelType = -1; if (vmkernelType == -1) { diff --git a/open-vm-tools/services/plugins/vix/vixTools.c b/open-vm-tools/services/plugins/vix/vixTools.c index 3c6d3f1ae..115f1c3d1 100644 --- a/open-vm-tools/services/plugins/vix/vixTools.c +++ b/open-vm-tools/services/plugins/vix/vixTools.c @@ -290,11 +290,11 @@ static const char *fileExtendedInfoLinuxFormatString = "" "%d" "%"FMT64"u" "%"FMT64"u" - "%"FMT64"u" "%"FMT64"u" "%d" "%d" "%d" + "%s" ""; #endif @@ -2597,7 +2597,8 @@ VixToolsDeleteObject(VixCommandRequestHeader *requestMsg) // IN impersonatingVMWareUser = TRUE; /////////////////////////////////////////// - if (VIX_COMMAND_DELETE_GUEST_FILE == requestMsg->opCode) { + if ((VIX_COMMAND_DELETE_GUEST_FILE == requestMsg->opCode) || + (VIX_COMMAND_DELETE_GUEST_FILE_EX == requestMsg->opCode)) { /* * if pathName is an invalid symbolic link, we still want to delete it. */ @@ -2674,6 +2675,99 @@ abort: } // VixToolsDeleteObject +/* + *----------------------------------------------------------------------------- + * + * VixToolsDeleteDirectory -- + * + * Delete a directory on the guest. + * + * Return value: + * TRUE on success + * FALSE on failure + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +VixError +VixToolsDeleteDirectory(VixCommandRequestHeader *requestMsg) // IN +{ + VixError err = VIX_OK; + char *directoryPath = NULL; + Bool success; + Bool impersonatingVMWareUser = FALSE; + void *userToken = NULL; + Bool recursive = TRUE; + VixMsgDeleteDirectoryRequest *deleteDirectoryRequest = + (VixMsgDeleteDirectoryRequest *) requestMsg; + + if ((requestMsg->commonHeader.bodyLength + + requestMsg->commonHeader.headerLength) != + (((uint64) sizeof(*deleteDirectoryRequest)) + + deleteDirectoryRequest->guestPathNameLength + 1)) { + ASSERT(0); + Debug("%s: Invalid request message received\n", __FUNCTION__); + err = VIX_E_INVALID_MESSAGE_BODY; + goto abort; + } + + directoryPath = ((char *) deleteDirectoryRequest) + + sizeof(*deleteDirectoryRequest); + + if (0 == *directoryPath) { + err = VIX_E_INVALID_ARG; + goto abort; + } + + if ('\0' != *(directoryPath + deleteDirectoryRequest->guestPathNameLength)) { + ASSERT(0); + Debug("%s: Invalid request message received.\n", __FUNCTION__); + err = VIX_E_INVALID_MESSAGE_BODY; + goto abort; + } + + recursive = deleteDirectoryRequest->recursive; + err = VixToolsImpersonateUser(requestMsg, &userToken); + if (VIX_OK != err) { + goto abort; + } + impersonatingVMWareUser = TRUE; + + success = File_Exists(directoryPath); + if (!success) { + err = VIX_E_FILE_NOT_FOUND; + goto abort; + } + + if (File_IsSymLink(directoryPath) || File_IsFile(directoryPath)) { + err = VIX_E_NOT_A_DIRECTORY; + goto abort; + } + + if (recursive) { + success = File_DeleteDirectoryTree(directoryPath); + } else { + success = File_DeleteEmptyDirectory(directoryPath); + } + + if (!success) { + err = FoundryToolsDaemon_TranslateSystemErr(); + goto abort; + } + +abort: + if (impersonatingVMWareUser) { + VixToolsUnimpersonateUser(userToken); + } + VixToolsLogoutUser(userToken); + + return err; +} // VixToolsDeleteDirectory + + /* *----------------------------------------------------------------------------- * @@ -4301,6 +4395,10 @@ VixToolsListFiles(VixCommandRequestHeader *requestMsg, // IN int numResults; GRegex *regex = NULL; GError *gerr = NULL; + char *pathName; +#ifdef linux + char *symlinkTarget = NULL; +#endif ASSERT(NULL != requestMsg); @@ -4405,6 +4503,7 @@ VixToolsListFiles(VixCommandRequestHeader *requestMsg, // IN for (fileNum = offset + index; fileNum < numFiles; fileNum++) { + currentFileName = fileNameList[fileNum]; if (regex) { @@ -4422,9 +4521,31 @@ VixToolsListFiles(VixCommandRequestHeader *requestMsg, // IN resultBufferSize += formatStringLength; resultBufferSize += 2; // DIRSEPC chars - resultBufferSize += 10 + 20 + (20 * 3); // properties + size + times + resultBufferSize += 10 + 20 + (20 * 2); // properties + size + times +#ifdef _WIN32 + resultBufferSize += 20; // createTime +#endif #ifdef linux resultBufferSize += 10 * 3; // uid, gid, perms + + /* + * It would be nice if this were cleaner, but then we'd have to save + * off the symlinks for the second loop. + */ + if (listingSingleFile && File_IsSymLink(currentFileName)) { + symlinkTarget = Posix_ReadLink(currentFileName); + resultBufferSize += strlen(symlinkTarget); + free(symlinkTarget); + } else { + pathName = Str_SafeAsprintf(NULL, "%s%s%s", dirPathName, DIRSEPS, + currentFileName); + if (File_IsSymLink(pathName)) { + symlinkTarget = Posix_ReadLink(pathName); + resultBufferSize += strlen(symlinkTarget); + free(symlinkTarget); + } + free(pathName); + } #endif resultBufferSize += strlen(currentFileName); @@ -4472,7 +4593,6 @@ VixToolsListFiles(VixCommandRequestHeader *requestMsg, // IN count < numResults; fileNum++, count++) { /* File_ListDirectory never returns "." or ".." */ - char *pathName; currentFileName = fileNameList[fileNum]; @@ -4817,16 +4937,17 @@ VixToolsPrintFileExtendedInfo(const char *filePathName, // IN int64 fileSize = 0; VmTimeType modTime = 0; VmTimeType accessTime = 0; - VmTimeType createTime = 0; int32 fileProperties = 0; #ifdef _WIN32 DWORD fileAttr = 0; Bool hidden = FALSE; Bool readOnly = FALSE; + VmTimeType createTime = 0; #elif defined(linux) int permissions = 0; int ownerId = 0; int groupId = 0; + char *symlinkTarget = NULL; #endif struct stat statbuf; @@ -4842,6 +4963,23 @@ VixToolsPrintFileExtendedInfo(const char *filePathName, // IN fileSize = File_GetSize(filePathName); } +#ifdef linux + /* + * If the file is a symlink, figure out where it points. + */ + if (fileProperties & VIX_FILE_ATTRIBUTES_SYMLINK) { + symlinkTarget = Posix_ReadLink(filePathName); + } + + /* + * Have a nice empty value if it's not a link or there's some error + * reading the link. + */ + if (NULL == symlinkTarget) { + symlinkTarget = Util_SafeStrdup(""); + } +#endif + #ifdef _WIN32 fileAttr = Win32U_GetFileAttributes(filePathName); if (fileAttr != INVALID_FILE_ATTRIBUTES) { @@ -4860,8 +4998,14 @@ VixToolsPrintFileExtendedInfo(const char *filePathName, // IN groupId = statbuf.st_gid; permissions = statbuf.st_mode; #endif - modTime = statbuf.st_mtime; + /* + * We want create time. ctime is the inode change time for Linux, + * so we can't report anything. + */ +#ifdef _WIN32 createTime = statbuf.st_ctime; +#endif + modTime = statbuf.st_mtime; accessTime = statbuf.st_atime; } else { Debug("%s: Posix_Stat(%s) failed with %d\n", @@ -4888,11 +5032,12 @@ VixToolsPrintFileExtendedInfo(const char *filePathName, // IN fileProperties, fileSize, modTime, - createTime, accessTime, ownerId, groupId, - permissions); + permissions, + symlinkTarget); + free(symlinkTarget); #endif #endif // defined(_WIN32) || defined(linux) } // VixToolsPrintFileExtendedInfo @@ -6924,15 +7069,18 @@ VixToolsCheckIfVixCommandEnabled(int opcode, // IN VIX_TOOLS_CONFIG_API_LIST_FILES_NAME); break; case VIX_COMMAND_DELETE_GUEST_FILE: + case VIX_COMMAND_DELETE_GUEST_FILE_EX: enabled = !VixToolsGetAPIDisabledFromConf(confDictRef, VIX_TOOLS_CONFIG_API_DELETE_FILE_NAME); break; case VIX_COMMAND_DELETE_GUEST_DIRECTORY: case VIX_COMMAND_DELETE_GUEST_EMPTY_DIRECTORY: + case VIX_COMMAND_DELETE_GUEST_DIRECTORY_EX: enabled = !VixToolsGetAPIDisabledFromConf(confDictRef, VIX_TOOLS_CONFIG_API_DELETE_DIRECTORY_NAME); break; case VIX_COMMAND_KILL_PROCESS: + case VIX_COMMAND_TERMINATE_PROCESS: enabled = !VixToolsGetAPIDisabledFromConf(confDictRef, VIX_TOOLS_CONFIG_API_TERMINATE_PROCESS_NAME); break; @@ -7147,12 +7295,18 @@ VixTools_ProcessVixCommand(VixCommandRequestHeader *requestMsg, // IN break; //////////////////////////////////// case VIX_COMMAND_DELETE_GUEST_FILE: + case VIX_COMMAND_DELETE_GUEST_FILE_EX: case VIX_COMMAND_DELETE_GUEST_REGISTRY_KEY: case VIX_COMMAND_DELETE_GUEST_DIRECTORY: case VIX_COMMAND_DELETE_GUEST_EMPTY_DIRECTORY: err = VixToolsDeleteObject(requestMsg); break; + //////////////////////////////////// + case VIX_COMMAND_DELETE_GUEST_DIRECTORY_EX: + err = VixToolsDeleteDirectory(requestMsg); + break; + //////////////////////////////////// case VIX_COMMAND_REGISTRY_KEY_EXISTS: case VIX_COMMAND_GUEST_FILE_EXISTS: @@ -7174,6 +7328,7 @@ VixTools_ProcessVixCommand(VixCommandRequestHeader *requestMsg, // IN //////////////////////////////////// case VIX_COMMAND_KILL_PROCESS: + case VIX_COMMAND_TERMINATE_PROCESS: err = VixToolsKillProcess(requestMsg); break;