b318572799b35ed9cd6fabdeb247495d72d4da4c chmalee Tue Jun 3 18:07:28 2025 -0700 Make the serverName a required input to hubspace uploads so the hubspace machine can determine where to place uploads. Prevents any current or future username collisions between euro and rr and prevents tusd temp file collisions between the machines, refs #31058 diff --git src/hg/hgHubConnect/trackHubWizard.c src/hg/hgHubConnect/trackHubWizard.c index 512b51e8d25..1c92d433dbe 100644 --- src/hg/hgHubConnect/trackHubWizard.c +++ src/hg/hgHubConnect/trackHubWizard.c @@ -13,46 +13,66 @@ #include "hgHubConnect.h" #include "jsHelper.h" #include "web.h" #include "wikiLink.h" #include "customTrack.h" #include "userdata.h" #include "jsonWrite.h" #include "cartJson.h" #include "hubSpace.h" #include "hubSpaceKeys.h" #include "hubConnect.h" #include "trackHub.h" #include "htmshell.h" #include -void removeOneFile(char *userName, char *cgiFileName, char *fullPath, char *db, char *fileType) +static char *getMachineName() +/* What is the machine we are running on? */ +{ +// what server are we running on? this becomes a subdirectory for each upload +if (hIsPrivateHost()) + return "hgwdev"; +else if (hIsBetaHost()) + return "hgwbeta"; +else if (hIsPreviewHost()) + return "preview"; +else + { + if (hHostHasPrefix("genome")) + return hHttpHost(); + else + // RR machines need one name (genome), genome-euro and genome-asia can go through + return "genome"; + } +} + +void removeOneFile(char *userName, char *cgiFileName, char *fullPath, char *db, char *fileType, char *serverName) /* Remove one single file for userName */ { // prefixUserFile returns a canonicalized path, or NULL if the // canonicalized path does not begin with the hg.conf specified userDataDir // TODO: make the debug information from stderr go to stdout so the user // can know there is a mistake somewhere, and only print the debug // information in the event that the filename actually begins with the // userDataDir so we don't tell hackers what files do and do not exist -char *fileName = prefixUserFile(userName, fullPath, NULL); +char *fileName = prefixUserFile(userName, fullPath, NULL, serverName); if (fileName) { if (fileExists(fileName)) { fprintf(stderr, "deleting file: '%s'\n", fileName); - removeFileForUser(fileName, userName); + removeFileForUser(fileName, userName, serverName); fflush(stderr); } else { fprintf(stderr, "file '%s' does not exist\n", fileName); fflush(stderr); } } } int pathDepth(char *path) { // replace multiple occurences of '/' with just a single one to get a canonical path // as path///to/file and path/to/file are the same path on Linux char *deduped = replaceChars(path, "//", "/"); @@ -72,129 +92,137 @@ if (aDepth != bDepth) return bDepth - aDepth; // if equal depth than lexicographic sort is fine return strcmp(jsonStringField(a,"fullPath"), jsonStringField(b, "fullPath")); } void sortByFullPath(struct jsonElement *listJson) { slSort(&(listJson->val.jeList), sortByFullPathCmp); } void doRemoveFile(struct cartJson *cj, struct hash *paramHash) /* Process the request to remove a file */ { char *userName = getUserName(); +char *serverName = getMachineName(); +if (!serverName) + { + char *commandJson = cgiOptionalString(CARTJSON_COMMAND); + errAbort("Error: no hostname for request. Please email genome-www@soe.ucsc.edu with your" + " username and the following text so we can debug:\n%s", commandJson); + } if (userName) { // our array of objects, each object represents a track file struct jsonElement *deleteJson = hashFindVal(paramHash, "fileList"); + char *reqServerName = cartJsonRequiredParam(paramHash, "serverName", cj->jw, NULL); + if (!sameString(serverName, reqServerName)) + { + errAbort("doRemoveFile: requested serverName does not match"); + } struct slRef *copy, *f, *fileList = deleteJson->val.jeList; struct jsonElement *dirListJsonEle = newJsonList(NULL); jsonWriteListStart(cj->jw, "deletedList"); for (f = fileList; f != NULL; ) { struct jsonElement *fileObj = (struct jsonElement *)f->val; char *fileName = jsonStringField(fileObj, "fileName"); char *fileType = jsonStringField(fileObj, "fileType"); char *db = jsonStringField(fileObj, "genome"); char *fullPath = jsonStringField(fileObj, "fullPath"); copy = f->next; if (sameString(fileType, "dir")) { f->next = NULL; jsonListAdd(dirListJsonEle, fileObj); } else { if (sameString(fileType, "hub.txt")) { // disconnect this hub from the cart if it exists - char *hubUrl = urlForFile(userName, fullPath); + char *hubUrl = urlForFile(userName, fullPath, serverName); char *hubId = hubNameFromUrl(hubUrl); if (hubId) { /* remove the cart variable */ hubId += 4; // skip past the hub_ part char buffer[1024]; safef(buffer, sizeof buffer, "hgHubConnect.hub.%s", hubId); cartRemove(cj->cart, buffer); } } - removeOneFile(userName, fileName, fullPath, db, fileType); + removeOneFile(userName, fileName, fullPath, db, fileType, serverName); // write out the fullPath so the DataTable can remove the correct row: jsonWriteString(cj->jw, NULL, fullPath); } f = copy; } // now attempt to delete any requested directories, but don't die if they still have contents sortByFullPath(dirListJsonEle); struct slRef *dir = NULL; for (dir = dirListJsonEle->val.jeList; dir != NULL; dir = dir->next) { struct jsonElement *fileObj = (struct jsonElement *)dir->val; char *fileName = jsonStringField(fileObj, "fileName"); char *fileType = jsonStringField(fileObj, "fileType"); char *db = jsonStringField(fileObj, "genome"); char *fullPath = jsonStringField(fileObj, "fullPath"); - removeOneFile(userName, fileName, fullPath, db, fileType); + removeOneFile(userName, fileName, fullPath, db, fileType, serverName); // write out the fullPath so the DataTable can remove the correct row: jsonWriteString(cj->jw, NULL, fullPath); } jsonWriteListEnd(cj->jw); } } void doMoveFile(struct cartJson *cj, struct hash *paramHash) /* Move a file to a new hub */ { } static void outUiDataForUser(struct jsonWrite *jw) /* List out the currently stored files for the user as well as other data * needed to create the hubSpace table */ { char *userName = getUserName(); +char *machName = getMachineName(); jsonWriteObjectStart(jw, "userFiles"); if (userName) { // the url for this user: - jsonWriteString(jw, "userUrl", webDataDir(userName)); + jsonWriteString(jw, "userUrl", webDataDir(userName, machName)); jsonWriteListStart(jw, "fileList"); struct hubSpace *file, *fileList = listFilesForUser(userName); - char fullPath[PATH_MAX]; for (file = fileList; file != NULL; file = file->next) { - // enforce realpath here in case of a trailing '/' on the hg.conf variable - // during a previous upload step - char *fpath = realpath(file->location, fullPath); - if (!fpath) - errAbort("Error listing user files for file '%s'", file->location); jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "fileName", file->fileName); jsonWriteNumber(jw, "fileSize", file->fileSize); jsonWriteString(jw, "fileType", file->fileType); jsonWriteString(jw, "parentDir", file->parentDir); jsonWriteString(jw, "genome", file->db); jsonWriteString(jw, "lastModified", file->lastModified); jsonWriteString(jw, "uploadTime", file->creationTime); - jsonWriteString(jw, "fullPath", stripDataDir(fullPath, userName)); + jsonWriteString(jw, "fullPath", stripDataDir(file->location, userName, machName)); jsonWriteString(jw, "md5sum", file->md5sum); jsonWriteObjectEnd(jw); } jsonWriteListEnd(jw); } +jsonWriteString(jw, "serverName", machName); jsonWriteBoolean(jw, "isLoggedIn", getUserName() ? TRUE : FALSE); jsonWriteString(jw, "hubNameDefault", defaultHubNameForUser(getUserName())); // if the user is not logged, the 0 for the quota is ignored jsonWriteNumber(jw, "userQuota", getUserName() ? checkUserQuota(getUserName()) : 0); jsonWriteNumber(jw, "maxQuota", getUserName() ? getMaxUserQuota(getUserName()) : HUB_SPACE_DEFAULT_QUOTA); jsonWriteObjectEnd(jw); } void getHubSpaceUIState(struct cartJson *cj, struct hash *paramHash) /* Get all the data we need to make a users hubSpace UI table. The cartJson library * deals with printing the json */ { outUiDataForUser(cj->jw); }