Mercurial > repos > youngkim > ezbamqc
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 } |