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; }
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; }
static char * FileFindExistingSafeTmpDir(uid_t userId, // IN: const char *userName, // IN: const char *baseTmpDir) // IN: { int i; int numFiles; char *pattern; char *tmpDir = NULL; char **fileList = NULL; /* * We always use the pattern PRODUCT-USER-xxxx when creating * alternative safe temp directories, so check for ones with * those names and the appropriate permissions. */ pattern = Unicode_Format("%s-%s-", PRODUCT_GENERIC_NAME_LOWER, userName); if (pattern == NULL) { return NULL; } numFiles = File_ListDirectory(baseTmpDir, &fileList); if (numFiles == -1) { free(pattern); return NULL; } for (i = 0; i < numFiles; i++) { if (Unicode_StartsWith(fileList[i], pattern)) { char *path = Unicode_Join(baseTmpDir, DIRSEPS, fileList[i], NULL); if (File_IsDirectory(path) && FileAcceptableSafeTmpDir(path, userId)) { tmpDir = path; break; } free(path); } } Util_FreeStringList(fileList, numFiles); free(pattern); return tmpDir; }
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; }
VmBackupOp * VmBackup_NewScriptOp(VmBackupScriptType type, // IN VmBackupState *state) // IN { Bool fail = FALSE; char **fileList = NULL; char *scriptDir = NULL; int numFiles = 0; size_t i; VmBackupScriptOp *op = NULL; scriptDir = VmBackupGetScriptPath(); if (scriptDir == NULL) { goto exit; } op = calloc(1, sizeof *op); if (op == NULL) { goto exit; } op->state = state; op->type = type; op->callbacks.queryFn = VmBackupScriptOpQuery; op->callbacks.cancelFn = VmBackupScriptOpCancel; op->callbacks.releaseFn = VmBackupScriptOpRelease; g_debug("Trying to run scripts from %s\n", scriptDir); /* * Load the list of scripts to run when freezing. The same list will be * used later in case of failure, or when thawing, in reverse order. * * This logic won't recurse into directories, so only files directly under * the script dir will be considered. * * Legacy scripts will be the first ones to run (or last ones in the * case of thawing). If either the legacy freeze or thaw script * exist, the first entry in the script list will be reserved for * them, and their path might not exist (in case, for example, the * freeze script exists but the thaw script doesn't). */ if (type == VMBACKUP_SCRIPT_FREEZE) { VmBackupScript *scripts = NULL; int legacy = 0; size_t idx = 0; state->scripts = NULL; state->currentScript = 0; if (File_IsFile(LEGACY_FREEZE_SCRIPT) || File_IsFile(LEGACY_THAW_SCRIPT)) { legacy = 1; } if (File_IsDirectory(scriptDir)) { numFiles = File_ListDirectory(scriptDir, &fileList); } if (numFiles + legacy > 0) { scripts = calloc(numFiles + legacy + 1, sizeof *scripts); if (scripts == NULL) { fail = TRUE; goto exit; } /* * VmBackupRunNextScript increments the index, so need to make it point * to "before the first script". */ state->currentScript = -1; state->scripts = scripts; } if (legacy > 0) { scripts[idx++].path = Util_SafeStrdup(LEGACY_FREEZE_SCRIPT); } if (numFiles > 0) { size_t i; if (numFiles > 1) { qsort(fileList, (size_t) numFiles, sizeof *fileList, VmBackupStringCompare); } for (i = 0; i < numFiles; i++) { char *script; script = Str_Asprintf(NULL, "%s%c%s", scriptDir, DIRSEPC, fileList[i]); if (script == NULL) { fail = TRUE; goto exit; } else if (File_IsFile(script)) { scripts[idx++].path = script; } else { free(script); } } } } else if (state->scripts != NULL) { VmBackupScript *scripts = state->scripts; if (strcmp(scripts[0].path, LEGACY_FREEZE_SCRIPT) == 0) { vm_free(scripts[0].path); scripts[0].path = Util_SafeStrdup(LEGACY_THAW_SCRIPT); } } /* * If there are any scripts to be executed, start the first one. If we get to * this point, we won't free the scripts array until VmBackupScriptOpRelease * is called after thawing (or after the sync provider failed and the "fail" * scripts are run). */ fail = (state->scripts != NULL && VmBackupRunNextScript(op) == -1); exit: /* Free the file list. */ for (i = 0; i < numFiles; i++) { free(fileList[i]); } free(fileList); if (fail && op != NULL) { VmBackup_Release((VmBackupOp *) op); op = NULL; } free(scriptDir); return (VmBackupOp *) op; }