544b4db19ee0f7f92c9d338d6900c34a53d9f032 chmalee Wed Jun 11 15:45:15 2025 -0700 Add back the good parts of b318572799b35, mostly have the pre-create hook set the upload path so we don't have to move files around in the pre-finish hook diff --git src/hg/lib/userdata.c src/hg/lib/userdata.c index 3823add7dac..0cca26e42c8 100644 --- src/hg/lib/userdata.c +++ src/hg/lib/userdata.c @@ -27,64 +27,93 @@ { return (loginSystemEnabled() || wikiLinkEnabled()) ? wikiLinkUserName() : NULL; } char *emailForUserName(char *userName) /* Fetch the email for this user from gbMembers hgcentral table */ { struct sqlConnection *sc = hConnectCentral(); struct dyString *query = sqlDyStringCreate("select email from gbMembers where userName = '%s'", userName); char *email = sqlQuickString(sc, dyStringCannibalize(&query)); hDisconnectCentral(&sc); // this should be freeMem'd: return email; } -char *getDataDir(char *userName) -/* Return the full path to the user specific data directory, can be configured via hg.conf - * on hgwdev, this is /data/tusd */ +char *getEncodedUserNamePath(char *userName) +/* Compute the path for just the userName part of the users upload */ +{ +struct dyString *ret = dyStringNew(0); +if (!userName) + return NULL; +char *encUserName = cgiEncode(userName); +char *userPrefix = md5HexForString(encUserName); +userPrefix[2] = '\0'; +dyStringPrintf(ret, "%s/%s", userPrefix, encUserName); +return dyStringCannibalize(&ret); +} + +// make this a global so if we have to repeatedly call stripDataDir() +// we only need to check the filesystem for path validity once +static char *dataDir = NULL; + +static char *setDataDir(char *userName) +/* Set the dataDir value based on hg.conf and the userName. Use realpath to make sure + * the directory exists and resolve the path if it is a symlink. Return the final + * path for convenience */ { char *tusdDataBaseDir = cfgOption("tusdDataDir"); if (!tusdDataBaseDir || isEmpty(tusdDataBaseDir)) errAbort("trying to save user file but no tusdDataDir defined in hg.conf"); if (tusdDataBaseDir[0] != '/') errAbort("config setting tusdDataDir must be an absolute path (starting with '/')"); char *encUserName = cgiEncode(userName); char *userPrefix = md5HexForString(encUserName); userPrefix[2] = '\0'; struct dyString *newDataDir = dyStringNew(0); dyStringPrintf(newDataDir, "%s/%s/%s", tusdDataBaseDir, userPrefix, encUserName); char *canonicalPath = needMem(PATH_MAX); realpath(dyStringContents(newDataDir), canonicalPath); // now that we have canonicalized the path we need to add a '/' back on // so the rest of the routines can append to this result dyStringClear(newDataDir); dyStringPrintf(newDataDir, "%s/", canonicalPath); -return dyStringCannibalize(&newDataDir); + +dataDir = dyStringCannibalize(&newDataDir); +return dataDir; +} + +char *getDataDir(char *userName) +/* Return the full path to the user specific data directory, can be configured via hg.conf + * on hgwdev, this is /data/tusd */ +{ +if (!dataDir) + setDataDir(userName); +return dataDir; } char *stripDataDir(char *fname, char *userName) /* Strips the getDataDir(userName) off of fname. The dataDir may be a symbolic * link, we will resolve it here. NOTE that this relies on * calling realpath(3) on the fname argument prior to calling stripDataDir() */ { -char *dataDir = getDataDir(userName); +getDataDir(userName); if (!dataDir) { // catch a realpath error return NULL; } int prefixSize = strlen(dataDir); if (startsWith(dataDir, fname)) { char *ret = fname + prefixSize; return ret; } return NULL; } char *getHubDataDir(char *userName, char *hub)