comparison ezBAMQC/src/htslib/hfile_irods.c @ 0:dfa3745e5fd8

Uploaded
author youngkim
date Thu, 24 Mar 2016 17:12:52 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:dfa3745e5fd8
1 /* hfile_irods.c -- iRODS backend for low-level file streams.
2
3 Copyright (C) 2013, 2015 Genome Research Ltd.
4
5 Author: John Marshall <jm18@sanger.ac.uk>
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 DEALINGS IN THE SOFTWARE. */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include "hfile_internal.h"
30
31 #include <rcConnect.h>
32 #include <dataObjOpen.h>
33 #include <dataObjRead.h>
34 #include <dataObjWrite.h>
35 #include <dataObjFsync.h>
36 #include <dataObjLseek.h>
37 #include <dataObjClose.h>
38
39 typedef struct {
40 hFILE base;
41 int descriptor;
42 } hFILE_irods;
43
44 static int status_errno(int status)
45 {
46 switch (status) {
47 case SYS_NO_API_PRIV: return EACCES;
48 case SYS_MALLOC_ERR: return ENOMEM;
49 case SYS_OUT_OF_FILE_DESC: return ENFILE;
50 case SYS_BAD_FILE_DESCRIPTOR: return EBADF;
51 case CAT_NO_ROWS_FOUND: return ENOENT;
52 case CATALOG_ALREADY_HAS_ITEM_BY_THAT_NAME: return EEXIST;
53 default: return EIO;
54 }
55 }
56
57 static void set_errno(int status)
58 {
59 int err = abs(status) % 1000;
60 errno = err? err : status_errno(status);
61 }
62
63 static struct {
64 rcComm_t *conn;
65 rodsEnv env;
66 } irods = { NULL };
67
68 static void irods_exit()
69 {
70 (void) rcDisconnect(irods.conn);
71 irods.conn = NULL;
72 }
73
74 static int irods_init()
75 {
76 rErrMsg_t err;
77 int ret;
78
79 ret = getRodsEnv(&irods.env);
80 if (ret < 0) goto error;
81
82 irods.conn = rcConnect(irods.env.rodsHost, irods.env.rodsPort,
83 irods.env.rodsUserName, irods.env.rodsZone,
84 NO_RECONN, &err);
85 if (irods.conn == NULL) { ret = err.status; goto error; }
86
87 if (strcmp(irods.env.rodsUserName, PUBLIC_USER_NAME) != 0) {
88 ret = clientLogin(irods.conn);
89 if (ret != 0) goto error;
90 }
91
92 // In the unlikely event atexit() fails, it's better to succeed here and
93 // carry on and do the I/O; then eventually when the program exits, we'll
94 // merely disconnect from the server uncleanly, as if we had aborted.
95 (void) atexit(irods_exit);
96
97 return 0;
98
99 error:
100 if (irods.conn) { (void) rcDisconnect(irods.conn); }
101 irods.conn = NULL;
102 set_errno(ret);
103 return -1;
104 }
105
106 static ssize_t irods_read(hFILE *fpv, void *buffer, size_t nbytes)
107 {
108 hFILE_irods *fp = (hFILE_irods *) fpv;
109 openedDataObjInp_t args;
110 bytesBuf_t buf;
111 int ret;
112
113 memset(&args, 0, sizeof args);
114 args.l1descInx = fp->descriptor;
115 args.len = nbytes;
116
117 buf.buf = buffer;
118 buf.len = nbytes;
119
120 ret = rcDataObjRead(irods.conn, &args, &buf);
121 if (ret < 0) set_errno(ret);
122 return ret;
123 }
124
125 static ssize_t irods_write(hFILE *fpv, const void *buffer, size_t nbytes)
126 {
127 hFILE_irods *fp = (hFILE_irods *) fpv;
128 openedDataObjInp_t args;
129 bytesBuf_t buf;
130 int ret;
131
132 memset(&args, 0, sizeof args);
133 args.l1descInx = fp->descriptor;
134 args.len = nbytes;
135
136 buf.buf = (void *) buffer; // ...the iRODS API is not const-correct here
137 buf.len = nbytes;
138
139 ret = rcDataObjWrite(irods.conn, &args, &buf);
140 if (ret < 0) set_errno(ret);
141 return ret;
142 }
143
144 static off_t irods_seek(hFILE *fpv, off_t offset, int whence)
145 {
146 hFILE_irods *fp = (hFILE_irods *) fpv;
147 openedDataObjInp_t args;
148 fileLseekOut_t *out = NULL;
149 int ret;
150
151 memset(&args, 0, sizeof args);
152 args.l1descInx = fp->descriptor;
153 args.offset = offset;
154 args.whence = whence;
155
156 ret = rcDataObjLseek(irods.conn, &args, &out);
157
158 if (out) { offset = out->offset; free(out); }
159 else offset = -1;
160 if (ret < 0) { set_errno(ret); return -1; }
161 return offset;
162 }
163
164 static int irods_flush(hFILE *fpv)
165 {
166 // FIXME rcDataObjFsync() doesn't seem to function as expected.
167 // For now, flush is a no-op: see https://github.com/samtools/htslib/issues/168
168 #if 0
169 hFILE_irods *fp = (hFILE_irods *) fpv;
170 openedDataObjInp_t args;
171 int ret;
172
173 memset(&args, 0, sizeof args);
174 args.l1descInx = fp->descriptor;
175
176 ret = rcDataObjFsync(irods.conn, &args);
177 if (ret < 0) set_errno(ret);
178 return ret;
179 #endif
180 return 0;
181 }
182
183 static int irods_close(hFILE *fpv)
184 {
185 hFILE_irods *fp = (hFILE_irods *) fpv;
186 openedDataObjInp_t args;
187 int ret;
188
189 memset(&args, 0, sizeof args);
190 args.l1descInx = fp->descriptor;
191
192 ret = rcDataObjClose(irods.conn, &args);
193 if (ret < 0) set_errno(ret);
194 return ret;
195 }
196
197 static const struct hFILE_backend irods_backend =
198 {
199 irods_read, irods_write, irods_seek, irods_flush, irods_close
200 };
201
202 hFILE *hopen_irods(const char *filename, const char *mode)
203 {
204 hFILE_irods *fp;
205 rodsPath_t path;
206 dataObjInp_t args;
207 int ret;
208
209 // Initialise the iRODS connection if this is the first use.
210 if (irods.conn == NULL) { if (irods_init() < 0) return NULL; }
211
212 if (strncmp(filename, "irods:", 6) == 0) filename += 6;
213 else { errno = EINVAL; return NULL; }
214
215 fp = (hFILE_irods *) hfile_init(sizeof (hFILE_irods), mode, 0);
216 if (fp == NULL) return NULL;
217
218 strncpy(path.inPath, filename, MAX_NAME_LEN-1);
219 path.inPath[MAX_NAME_LEN-1] = '\0';
220
221 ret = parseRodsPath(&path, &irods.env);
222 if (ret < 0) goto error;
223
224 memset(&args, 0, sizeof args);
225 strcpy(args.objPath, path.outPath);
226 args.openFlags = hfile_oflags(mode);
227 if (args.openFlags & O_CREAT) {
228 args.createMode = 0666;
229 addKeyVal(&args.condInput, DEST_RESC_NAME_KW,irods.env.rodsDefResource);
230 }
231
232 ret = rcDataObjOpen(irods.conn, &args);
233 if (ret < 0) goto error;
234 fp->descriptor = ret;
235
236 fp->base.backend = &irods_backend;
237 return &fp->base;
238
239 error:
240 hfile_destroy((hFILE *) fp);
241 set_errno(ret);
242 return NULL;
243 }