60e0e2650cf3fc2f198721b5e1e58976f3a321b2
chmalee
  Tue Apr 1 14:14:21 2025 -0700
Call realpath when outputting files to client in case of an incorrect hg.conf parameter with a trailing '/', refs Jairo email

diff --git src/hg/hgHubConnect/trackHubWizard.c src/hg/hgHubConnect/trackHubWizard.c
index 7b56e152e9a..6ad59958551 100644
--- src/hg/hgHubConnect/trackHubWizard.c
+++ src/hg/hgHubConnect/trackHubWizard.c
@@ -11,30 +11,31 @@
 #include "md5.h"
 #include "trashDir.h"
 #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 <limits.h>
 
 void removeOneFile(char *userName, char *cgiFileName, char *fullPath, char *db, char *fileType)
 /* 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);
 if (fileName)
     {
     if (fileExists(fileName))
         {
@@ -148,41 +149,47 @@
 {
 }
 
 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();
 jsonWriteObjectStart(jw, "userFiles");
 if (userName)
     {
     // the url for this user:
     jsonWriteString(jw, "userUrl", webDataDir(userName));
     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(file->location, userName));
+        jsonWriteString(jw, "fullPath", stripDataDir(fullPath, userName));
         jsonWriteString(jw, "md5sum", file->md5sum);
         jsonWriteObjectEnd(jw);
         }
     jsonWriteListEnd(jw);
     }
 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