Mercurial > repos > youngkim > ezbamqc
diff ezBAMQC/src/htslib/hfile_irods.c @ 0:dfa3745e5fd8
Uploaded
author | youngkim |
---|---|
date | Thu, 24 Mar 2016 17:12:52 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ezBAMQC/src/htslib/hfile_irods.c Thu Mar 24 17:12:52 2016 -0400 @@ -0,0 +1,243 @@ +/* hfile_irods.c -- iRODS backend for low-level file streams. + + Copyright (C) 2013, 2015 Genome Research Ltd. + + Author: John Marshall <jm18@sanger.ac.uk> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "hfile_internal.h" + +#include <rcConnect.h> +#include <dataObjOpen.h> +#include <dataObjRead.h> +#include <dataObjWrite.h> +#include <dataObjFsync.h> +#include <dataObjLseek.h> +#include <dataObjClose.h> + +typedef struct { + hFILE base; + int descriptor; +} hFILE_irods; + +static int status_errno(int status) +{ + switch (status) { + case SYS_NO_API_PRIV: return EACCES; + case SYS_MALLOC_ERR: return ENOMEM; + case SYS_OUT_OF_FILE_DESC: return ENFILE; + case SYS_BAD_FILE_DESCRIPTOR: return EBADF; + case CAT_NO_ROWS_FOUND: return ENOENT; + case CATALOG_ALREADY_HAS_ITEM_BY_THAT_NAME: return EEXIST; + default: return EIO; + } +} + +static void set_errno(int status) +{ + int err = abs(status) % 1000; + errno = err? err : status_errno(status); +} + +static struct { + rcComm_t *conn; + rodsEnv env; +} irods = { NULL }; + +static void irods_exit() +{ + (void) rcDisconnect(irods.conn); + irods.conn = NULL; +} + +static int irods_init() +{ + rErrMsg_t err; + int ret; + + ret = getRodsEnv(&irods.env); + if (ret < 0) goto error; + + irods.conn = rcConnect(irods.env.rodsHost, irods.env.rodsPort, + irods.env.rodsUserName, irods.env.rodsZone, + NO_RECONN, &err); + if (irods.conn == NULL) { ret = err.status; goto error; } + + if (strcmp(irods.env.rodsUserName, PUBLIC_USER_NAME) != 0) { + ret = clientLogin(irods.conn); + if (ret != 0) goto error; + } + + // In the unlikely event atexit() fails, it's better to succeed here and + // carry on and do the I/O; then eventually when the program exits, we'll + // merely disconnect from the server uncleanly, as if we had aborted. + (void) atexit(irods_exit); + + return 0; + +error: + if (irods.conn) { (void) rcDisconnect(irods.conn); } + irods.conn = NULL; + set_errno(ret); + return -1; +} + +static ssize_t irods_read(hFILE *fpv, void *buffer, size_t nbytes) +{ + hFILE_irods *fp = (hFILE_irods *) fpv; + openedDataObjInp_t args; + bytesBuf_t buf; + int ret; + + memset(&args, 0, sizeof args); + args.l1descInx = fp->descriptor; + args.len = nbytes; + + buf.buf = buffer; + buf.len = nbytes; + + ret = rcDataObjRead(irods.conn, &args, &buf); + if (ret < 0) set_errno(ret); + return ret; +} + +static ssize_t irods_write(hFILE *fpv, const void *buffer, size_t nbytes) +{ + hFILE_irods *fp = (hFILE_irods *) fpv; + openedDataObjInp_t args; + bytesBuf_t buf; + int ret; + + memset(&args, 0, sizeof args); + args.l1descInx = fp->descriptor; + args.len = nbytes; + + buf.buf = (void *) buffer; // ...the iRODS API is not const-correct here + buf.len = nbytes; + + ret = rcDataObjWrite(irods.conn, &args, &buf); + if (ret < 0) set_errno(ret); + return ret; +} + +static off_t irods_seek(hFILE *fpv, off_t offset, int whence) +{ + hFILE_irods *fp = (hFILE_irods *) fpv; + openedDataObjInp_t args; + fileLseekOut_t *out = NULL; + int ret; + + memset(&args, 0, sizeof args); + args.l1descInx = fp->descriptor; + args.offset = offset; + args.whence = whence; + + ret = rcDataObjLseek(irods.conn, &args, &out); + + if (out) { offset = out->offset; free(out); } + else offset = -1; + if (ret < 0) { set_errno(ret); return -1; } + return offset; +} + +static int irods_flush(hFILE *fpv) +{ +// FIXME rcDataObjFsync() doesn't seem to function as expected. +// For now, flush is a no-op: see https://github.com/samtools/htslib/issues/168 +#if 0 + hFILE_irods *fp = (hFILE_irods *) fpv; + openedDataObjInp_t args; + int ret; + + memset(&args, 0, sizeof args); + args.l1descInx = fp->descriptor; + + ret = rcDataObjFsync(irods.conn, &args); + if (ret < 0) set_errno(ret); + return ret; +#endif + return 0; +} + +static int irods_close(hFILE *fpv) +{ + hFILE_irods *fp = (hFILE_irods *) fpv; + openedDataObjInp_t args; + int ret; + + memset(&args, 0, sizeof args); + args.l1descInx = fp->descriptor; + + ret = rcDataObjClose(irods.conn, &args); + if (ret < 0) set_errno(ret); + return ret; +} + +static const struct hFILE_backend irods_backend = +{ + irods_read, irods_write, irods_seek, irods_flush, irods_close +}; + +hFILE *hopen_irods(const char *filename, const char *mode) +{ + hFILE_irods *fp; + rodsPath_t path; + dataObjInp_t args; + int ret; + + // Initialise the iRODS connection if this is the first use. + if (irods.conn == NULL) { if (irods_init() < 0) return NULL; } + + if (strncmp(filename, "irods:", 6) == 0) filename += 6; + else { errno = EINVAL; return NULL; } + + fp = (hFILE_irods *) hfile_init(sizeof (hFILE_irods), mode, 0); + if (fp == NULL) return NULL; + + strncpy(path.inPath, filename, MAX_NAME_LEN-1); + path.inPath[MAX_NAME_LEN-1] = '\0'; + + ret = parseRodsPath(&path, &irods.env); + if (ret < 0) goto error; + + memset(&args, 0, sizeof args); + strcpy(args.objPath, path.outPath); + args.openFlags = hfile_oflags(mode); + if (args.openFlags & O_CREAT) { + args.createMode = 0666; + addKeyVal(&args.condInput, DEST_RESC_NAME_KW,irods.env.rodsDefResource); + } + + ret = rcDataObjOpen(irods.conn, &args); + if (ret < 0) goto error; + fp->descriptor = ret; + + fp->base.backend = &irods_backend; + return &fp->base; + +error: + hfile_destroy((hFILE *) fp); + set_errno(ret); + return NULL; +}