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; }
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; }
void Unicode_FreeList(Unicode *list, // IN: the list to free ssize_t length) // IN: the length { Util_FreeStringList(list, length); }
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; }