src/lib/udc.c 1.18
1.18 2009/11/03 00:51:53 angie
Support for udcFuse and apps that will read files from it: plug minor memory leaks, use errAbort not assert, make udcFileMayOpen public, make udcParseUrl public so apps can determine path to file in udcFuse, add udcPathToUrl and udcSizeFromCache so that udcFuse can report the correct total file size.
Index: src/lib/udc.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/lib/udc.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -b -B -U 4 -r1.17 -r1.18
--- src/lib/udc.c 18 May 2009 21:35:20 -0000 1.17
+++ src/lib/udc.c 3 Nov 2009 00:51:53 -0000 1.18
@@ -264,14 +264,20 @@
if (status != 200) // && status != 302 && status != 301)
return FALSE;
char *sizeString = hashFindVal(hash, "Content-Length:");
if (sizeString == NULL)
+ {
+ hashFree(&hash);
errAbort("No Content-Length: returned in header for %s, can't proceed, sorry", url);
+ }
retInfo->size = atoll(sizeString);
char *lastModString = hashFindVal(hash, "Last-Modified:");
if (lastModString == NULL)
+ {
+ hashFree(&hash);
errAbort("No Last-Modified: returned in header for %s, can't proceed, sorry", url);
+ }
// Last-Modified: Wed, 25 Feb 2004 22:37:23 GMT
// Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
@@ -281,8 +287,9 @@
// TODO: it's very likely that there are other date string patterns
// out there that might be encountered.
if (strptime(lastModString, "%a, %d %b %Y %H:%M:%S %Z", &tm) == NULL)
{ /* Handle error */;
+ hashFree(&hash);
errAbort("unable to parse last-modified string [%s]", lastModString);
}
//printf("year: %d; month: %d; day: %d;\n",
@@ -297,8 +304,9 @@
is in effect */
t = mktime(&tm);
if (t == -1)
{ /* Handle error */;
+ hashFree(&hash);
errAbort("mktime failed while parsing last-modified string [%s]", lastModString);
}
//printf("seconds since the Epoch: %lld\n", (long long) t);"
@@ -398,9 +406,11 @@
writeOne(f, reserved64);
writeOne(f, reserved64);
writeOne(f, reserved64);
writeOne(f, reserved64);
-assert(ftell(f) == udcBitmapHeaderSize);
+if (ftell(f) != udcBitmapHeaderSize)
+ errAbort("ftell(f=%s) is %lld, not expected udcBitmapHeaderSize %d",
+ file->bitmapFileName, (long long)ftell(f), udcBitmapHeaderSize);
/* Write out initial all-zero bitmap. */
for (i=0; i<bitmapSize; ++i)
putc(0, f);
@@ -604,9 +614,11 @@
return output;
}
void udcParseUrl(char *url, char **retProtocol, char **retAfterProtocol, char **retColon)
-/* handle url parsing */
+/* Parse the URL into components that udc treats separately.
+ * *retAfterProtocol is Q-encoded to keep special chars out of filenames.
+ * Free *retProtocol and *retAfterProtocol but not *retColon when done. */
{
char *protocol, *afterProtocol;
char *colon = strchr(url, ':');
if (!colon)
@@ -648,18 +660,23 @@
file->sparseFileName = fileNameInCacheDir(file, sparseDataName);
}
struct udcFile *udcFileMayOpen(char *url, char *cacheDir)
-/* Open up a cached file. Return NULL if file doesn't exist. */
+/* Open up a cached file. cacheDir may be null in which case udcDefaultDir() will be
+ * used. Return NULL if file doesn't exist. */
{
+if (cacheDir == NULL)
+ cacheDir = udcDefaultDir();
verbose(2, "udcfileOpen(%s, %s)\n", url, cacheDir);
/* Parse out protocol. Make it "transparent" if none specified. */
char *protocol, *afterProtocol, *colon;
boolean isTransparent = FALSE;
udcParseUrl(url, &protocol, &afterProtocol, &colon);
if (!colon)
{
+ freeMem(protocol);
protocol = cloneString("transparent");
+ freeMem(afterProtocol);
afterProtocol = cloneString(url);
isTransparent = TRUE;
}
struct udcProtocol *prot;
@@ -672,8 +689,10 @@
{
if (!prot->fetchInfo(url, &info))
{
udcProtocolFree(&prot);
+ freeMem(protocol);
+ freeMem(afterProtocol);
return NULL;
}
}
@@ -710,9 +729,10 @@
return file;
}
struct udcFile *udcFileOpen(char *url, char *cacheDir)
-/* Open up a cached file. Abort if file doesn't exist. */
+/* Open up a cached file. cacheDir may be null in which case udcDefaultDir() will be
+ * used. Abort if if file doesn't exist. */
{
struct udcFile *udcFile = udcFileMayOpen(url, cacheDir);
if (udcFile == NULL)
errAbort("Couldn't open %s", url);
@@ -735,8 +755,10 @@
freeMem(file->cacheDir);
freeMem(file->bitmapFileName);
freeMem(file->sparseFileName);
freeMem(file);
+freeMem(protocol);
+freeMem(afterProtocol);
return list;
}
void udcFileClose(struct udcFile **pFile)
@@ -755,8 +777,84 @@
}
freez(pFile);
}
+static void qDecode(const char *input, char *buf, size_t size)
+/* Reverse the qEncode performed on afterProcotol above into buf or abort. */
+{
+safecpy(buf, size, input);
+char c, *r = buf, *w = buf;
+while ((c = *r++) != '\0')
+ {
+ if (c == 'Q')
+ {
+ int q;
+ if (sscanf(r, "%02X", &q))
+ {
+ *w++ = (char)q;
+ r += 2;
+ }
+ else
+ errAbort("qDecode: input \"%s\" does not appear to be properly formatted "
+ "starting at \"%s\"", input, r);
+ }
+ else
+ *w++ = c;
+ }
+*w = '\0';
+}
+
+char *udcPathToUrl(const char *path, char *buf, size_t size, char *cacheDir)
+/* Translate path into an URL, store in buf, return pointer to buf if successful
+ * and NULL if not. */
+{
+if (cacheDir == NULL)
+ cacheDir = udcDefaultDir();
+int offset = 0;
+if (startsWith(cacheDir, (char *)path))
+ offset = strlen(cacheDir);
+if (path[offset] == '/')
+ offset++;
+char protocol[16];
+strncpy(protocol, path+offset, sizeof(protocol));
+protocol[ArraySize(protocol)-1] = '\0';
+char *p = strchr(protocol, '/');
+if (p == NULL)
+ {
+ errAbort("unable to parse protocol (first non-'%s' directory) out of path '%s'\n",
+ cacheDir, path);
+ return NULL;
+ }
+*p++ = '\0';
+char afterProtocol[4096];
+qDecode(path+1+strlen(protocol)+1, afterProtocol, sizeof(afterProtocol));
+safef(buf, size, "%s://%s", protocol, afterProtocol);
+return buf;
+}
+
+int udcSizeFromCache(char *url, char *cacheDir)
+/* Look up the file size from the local cache bitmap file, or -1 if there
+ * is no cache for url. */
+{
+int ret = -1;
+if (cacheDir == NULL)
+ cacheDir = udcDefaultDir();
+struct slName *sl, *slList = udcFileCacheFiles(url, cacheDir);
+for (sl = slList; sl != NULL; sl = sl->next)
+ if (endsWith(sl->name, bitmapName))
+ {
+ struct udcBitmap *bits = udcBitmapOpen(sl->name);
+ if (bits != NULL)
+ ret = bits->fileSize;
+ else
+ warn("Can't open bitmap file %s: %s\n", sl->name, strerror(errno));
+ udcBitmapClose(&bits);
+ }
+ else
+slNameFreeList(&slList);
+return ret;
+}
+
static void readBitsIntoBuf(FILE *f, int headerSize, int bitStart, int bitEnd,
Bits **retBits, int *retPartOffset)
/* Do some bit-to-byte offset conversions and read in all the bytes that
* have information in the bits we're interested in. */