1ff2e18ba5e50dd2d1becd3cd6a25343578c10b8 markd Tue Apr 21 14:09:04 2026 -0700 rework of htslib/UDC integration to use htslib hfile driver mechanism diff --git src/lib/hfileUdc.c src/lib/hfileUdc.c new file mode 100644 index 00000000000..8971847d896 --- /dev/null +++ src/lib/hfileUdc.c @@ -0,0 +1,124 @@ +/* hfileUdc -- hfile backend that routes HTTP/HTTPS/FTP through UDC. + * + * Registers as an hfile scheme handler at priority 60 (above libcurl's 50), + * so all remote file access via htslib automatically uses UDC caching. + * + * Replaces the legacy knetUdc.c / knetfile hook approach. + */ + +/* Copyright (C) 2026 The Regents of the University of California + * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ + +#include "common.h" +#include "udc.h" +#include "hfileUdc.h" + +#include "htslib/hfile.h" +#include "hfile_internal.h" + +#include + +typedef struct { + hFILE base; /* must be first */ + struct udcFile *udc; /* UDC file handle */ + bits64 fileSize; /* cached file size for SEEK_END */ +} hFILE_udc; + +/* --- backend operations --- */ + +static ssize_t udc_read(hFILE *fpv, void *buffer, size_t nbytes) +{ +hFILE_udc *fp = (hFILE_udc *) fpv; +bits64 n = udcRead(fp->udc, buffer, (bits64)nbytes); +return (ssize_t)n; +} + +static ssize_t udc_write(hFILE *fpv, const void *buffer, size_t nbytes) +{ +(void)fpv; (void)buffer; (void)nbytes; +errno = EROFS; +return -1; +} + +static off_t udc_seek(hFILE *fpv, off_t offset, int whence) +{ +hFILE_udc *fp = (hFILE_udc *) fpv; +bits64 abspos; + +switch (whence) + { + case SEEK_SET: + abspos = offset; + break; + case SEEK_CUR: + abspos = udcTell(fp->udc) + offset; + break; + case SEEK_END: + abspos = fp->fileSize + offset; + break; + default: + errno = EINVAL; + return -1; + } + +udcSeek(fp->udc, abspos); +return (off_t)udcTell(fp->udc); +} + +static int udc_close(hFILE *fpv) +{ +hFILE_udc *fp = (hFILE_udc *) fpv; +udcFileClose(&fp->udc); +return 0; +} + +static const struct hFILE_backend udc_backend = +{ + udc_read, udc_write, udc_seek, NULL, udc_close +}; + +/* --- scheme handler open --- */ + +static hFILE *hopen_udc(const char *url, const char *mode) +{ +if (!(sameOk((char *)mode, "r") || sameOk((char *)mode, "rb"))) + { + errno = EROFS; + return NULL; + } + +struct udcFile *udcf = udcFileMayOpen((char *)url, NULL); +if (udcf == NULL) + { + errno = ENOENT; + return NULL; + } + +hFILE_udc *fp = (hFILE_udc *) hfile_init(sizeof(hFILE_udc), mode, 0); +if (fp == NULL) + { + udcFileClose(&udcf); + return NULL; + } + +fp->udc = udcf; +fp->fileSize = udcFileOpenSize(udcf); +fp->base.backend = &udc_backend; +return &fp->base; +} + +static const struct hFILE_scheme_handler udc_handler = +{ + hopen_udc, hfile_always_remote, "UCSC UDC", 60 +}; + +/* --- public registration --- */ + +void hfileUdcInstall() +/* Install UDC as the hfile backend for HTTP/HTTPS/FTP URLs. + * Call once at startup; replaces legacy knetUdcInstall(). */ +{ +hfile_add_scheme_handler("http", &udc_handler); +hfile_add_scheme_handler("https", &udc_handler); +hfile_add_scheme_handler("ftp", &udc_handler); +} \ No newline at end of file