1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <kfs/extern.h>
28
29 #include <klib/defs.h>
30 #include <byteswap.h>
31 #include <klib/rc.h>
32 #include <kfs/file.h>
33 #include <kfs/sra.h>
34 /* #include <kfs/toc.h> */
35 #include <klib/log.h>
36 #include "toc-priv.h"
37
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41
42 #include <sysalloc.h>
43
44
45 struct KToc;
46 struct KDirectory;
47
48
49
50 static
51 const KSraHeader ksraheader_v1 =
52 {
53 { 'N', 'C','B', 'I' },
54 { '.', 's','r', 'a' },
55 eSraByteOrderTag,
56 1
57 };
58
SraHeaderSize(const KSraHeader * self)59 LIB_EXPORT size_t CC SraHeaderSize ( const KSraHeader * self )
60 {
61 /* self can be NULL */
62 return sizeof ( KSraHeader );
63 }
64
65 static
add_filler(uint64_t z,KSRAFileAlignment a)66 uint64_t add_filler (uint64_t z, KSRAFileAlignment a)
67 {
68 if (a > 1)
69 {
70 uint64_t m = (uint64_t)a - 1;
71 return (z + m) & ~ m;
72 }
73 return z;
74 }
75
SraHeaderInit(KSraHeader * self,size_t treesize,KSRAFileAlignment alignment)76 static void SraHeaderInit (KSraHeader * self, size_t treesize, KSRAFileAlignment alignment)
77 {
78 memmove (self, &ksraheader_v1, sizeof ksraheader_v1);
79 self->u.v1.file_offset = add_filler (sizeof * self + treesize, alignment);
80 }
81
SraHeaderMake(KSraHeader ** pself,size_t treesize,KSRAFileAlignment alignment)82 rc_t SraHeaderMake (KSraHeader ** pself, size_t treesize, KSRAFileAlignment alignment)
83 {
84 KSraHeader * self = malloc (sizeof (KSraHeader));
85 if (self == NULL)
86 return RC ( rcFS, rcToc, rcConstructing, rcMemory, rcExhausted );
87 SraHeaderInit (self, treesize, alignment);
88 *pself = self;
89 return 0;
90 }
91
92
SraHeaderValidate(const KSraHeader * self,bool * reverse,uint32_t * _version,size_t bytes_available)93 static rc_t SraHeaderValidate ( const KSraHeader * self, bool * reverse, uint32_t * _version, size_t bytes_available )
94 {
95 uint64_t offset;
96 rc_t rc;
97 uint32_t version;
98 bool rev;
99
100 if (reverse != NULL)
101 *reverse = false;
102 if (_version != NULL)
103 *_version = 0;
104
105 if (bytes_available < 8)
106 return RC (rcFS, rcArc, rcParsing, rcHeader, rcInsufficient);
107
108 if (memcmp ((void*)self, &ksraheader_v1,
109 sizeof (ksraheader_v1.ncbi) + sizeof (ksraheader_v1.sra)) != 0)
110 return RC (rcFS, rcArc, rcParsing, rcHeader, rcInvalid);
111
112 if (bytes_available < 12)
113 return 0;
114
115 switch (self->byte_order)
116 {
117 default:
118 return RC (rcFS, rcArc, rcParsing, rcHeader, rcCorrupt);
119 case eSraByteOrderTag:
120 rev = false;
121 break;
122 case eSraByteOrderReverse:
123 rev = true;
124 break;
125 }
126 rc = 0;
127
128 if (bytes_available < 16)
129 return 0;
130
131 version = rev ? bswap_32 (self->version) : self->version;
132 offset = rev ? bswap_64 (self->u.v1.file_offset) : self->u.v1.file_offset;
133
134 if (version > FS_SRA_CUR_VERSION)
135 rc = RC (rcFS, rcArc, rcParsing, rcHeader, rcUnsupported);
136
137 /* 4 is minimum size for a TOC */
138 else if (offset < (sizeof ksraheader_v1 + 4))
139 return RC (rcFS, rcArc, rcParsing, rcHeader, rcCorrupt);
140
141 if (reverse != NULL)
142 *reverse = rev;
143 if (_version != NULL)
144 *_version = version;
145
146 return rc;
147 }
148
SraHeaderGetFileOffset(const KSraHeader * self)149 LIB_EXPORT uint64_t CC SraHeaderGetFileOffset ( const KSraHeader * self )
150 {
151 if ( self -> byte_order == eSraByteOrderReverse )
152 return bswap_64 ( self->u.v1.file_offset );
153 return self->u.v1.file_offset;
154 }
155
156 static
KTocParseRead(const KFile * f,uint64_t p,void * b,size_t z,size_t * n)157 rc_t KTocParseRead (const KFile * f, uint64_t p, void * b, size_t z, size_t * n)
158 {
159 rc_t rc;
160 size_t a;
161 size_t t;
162
163 rc = 0;
164 for (a = 0; a < z; a += t)
165 {
166 rc = KFileRead (f, p + a, (uint8_t*)b + a, z - a, &t);
167 if (rc != 0)
168 return rc;
169 if (t == 0)
170 break;
171 }
172 if (a < z)
173 rc = RC (rcFS, rcToc, rcParsing, rcFile, rcTooShort);
174 *n = a;
175 return rc;
176 }
177
178
179 static
KTocParseReadPBSTree(struct KToc * self,const KFile * file,uint64_t endpos,void ** header)180 rc_t KTocParseReadPBSTree (struct KToc * self, const KFile * file, uint64_t endpos, void ** header)
181 {
182 rc_t rc;
183 uint64_t toc_pos;
184 uint64_t end_pos;
185 size_t num_read;
186 size_t tree_size;
187
188 rc = 0;
189 toc_pos = SraHeaderSize(NULL);
190 end_pos = endpos;
191
192 if (end_pos <= toc_pos)
193 {
194 /* rc = RC (rcFS, rcToc, rc */
195 }
196 tree_size = (size_t)(end_pos - toc_pos);
197
198 *header = malloc (tree_size);
199 if (*header == NULL)
200 {
201 rc = RC (rcFS, rcToc, rcParsing, rcMemory, rcExhausted);
202 }
203 else
204 {
205 rc = KTocParseRead (file, toc_pos, *header, tree_size, &num_read);
206 if (rc == 0)
207 {
208 return 0;
209 }
210 free (*header);
211 *header = NULL;
212 }
213 return rc;
214 }
215
216 static
KArcParseSRAInt(struct KToc * self,const void * kvoid,bool (CC * ignored)(const struct KDirectory *,const char *,void *),void * ignored_data,bool unbounded,bool silent)217 rc_t CC KArcParseSRAInt ( struct KToc * self,
218 const void * kvoid,
219 bool ( CC * ignored ) ( const struct KDirectory *, const char *, void * ),
220 void * ignored_data,
221 bool unbounded,
222 bool silent )
223 {
224 uint64_t arcsize;
225 rc_t rc;
226 bool reverse;
227 uint32_t version;
228 KSraHeader header;
229 size_t num_read;
230 size_t all_read;
231 const KFile * file;
232 void * pbstreeBuffer;
233 /* uint64_t toc_offset; */
234 /* uint64_t file_offset; */
235
236 rc = 0;
237 if ( kvoid == NULL )
238 {
239 rc = RC ( rcFS, rcToc, rcParsing, rcParam, rcNull );
240 if ( !silent )
241 LOGERR ( klogErr, rc, "File parameter null for parsing .sra" );
242 return rc;
243 }
244 file = kvoid;
245
246 rc = KFileSize ( file, &arcsize );
247 if (rc)
248 {
249 if ( unbounded )
250 arcsize = ( (uint64_t)0 ) - 1;
251 else
252 {
253 rc = RC ( rcFS, rcToc, rcParsing, rcFile, rcIncorrect );
254 if ( !silent )
255 LOGERR ( klogErr, rc, "Can't determine archive file size" );
256 return rc;
257 }
258 }
259
260 for ( num_read = all_read = 0; all_read < sizeof (header); all_read += num_read )
261 {
262 rc = KTocParseRead ( file, 0, &header, sizeof (header), &num_read );
263 if ( num_read == 0 )
264 {
265 rc = RC ( rcFS, rcToc, rcParsing, rcFile, rcTooShort );
266 break;
267 }
268 }
269 if ( rc != 0 )
270 {
271 if ( !silent )
272 LOGERR ( klogErr, rc, "error reading file to parse .sra" );
273 return rc;
274 }
275
276 /* version is ignored at this point as there is only one version */
277 rc = SraHeaderValidate ( &header, &reverse, &version, sizeof header );
278 if ( rc != 0 )
279 {
280 if ( !silent )
281 LOGERR ( klogErr, rc, "File header invalid for .sra header" );
282 return rc;
283 }
284
285 switch ( version )
286 {
287 default:
288 rc = RC ( rcFS, rcToc, rcParsing, rcFileFormat, rcBadVersion );
289 if ( !silent )
290 LOGERR ( klogInt, rc, "Incompatible file version" );
291 break;
292 case 1:
293 rc = KTocParseReadPBSTree ( self, file, SraHeaderGetFileOffset (&header),
294 &pbstreeBuffer );
295 if ( rc != 0 )
296 {
297 if ( !silent )
298 LOGERR ( klogErr, rc, "File TOC not read for .sra header" );
299 break;
300 }
301 else
302 {
303 uint64_t offset;
304 offset = SraHeaderGetFileOffset (&header);
305 rc = KTocInflatePBSTree ( self, arcsize, pbstreeBuffer,
306 (uint32_t)(offset - sizeof (header)),
307 offset,
308 reverse, "" );
309 free ( pbstreeBuffer );
310 if ( rc != 0 && !silent )
311 {
312 LOGERR (klogErr, rc, "File TOC not valid for .sra");
313 }
314 /* else */
315 /* { */
316 /* rc = KTocParseSraDirectory (self, bst, ""); */
317 /* if (rc == 0) */
318 /* return 0; */
319 /* } */
320 }
321 break;
322 }
323 return rc;
324 }
325
KArcParseSRA(struct KToc * self,const void * kvoid,bool (CC * ignored)(const struct KDirectory *,const char *,void *),void * ignored_data)326 LIB_EXPORT rc_t CC KArcParseSRA ( struct KToc * self,
327 const void * kvoid,
328 bool (CC*ignored) (const struct KDirectory*, const char*, void*),
329 void *ignored_data )
330 {
331 return KArcParseSRAInt ( self, kvoid, ignored, ignored_data, false, false );
332 }
333
334
KArcParseSRA_silent(struct KToc * self,const void * kvoid,bool (CC * ignored)(const struct KDirectory *,const char *,void *),void * ignored_data)335 LIB_EXPORT rc_t CC KArcParseSRA_silent ( struct KToc * self,
336 const void * kvoid,
337 bool (CC*ignored) (const struct KDirectory*, const char*, void*),
338 void *ignored_data )
339 {
340 return KArcParseSRAInt ( self, kvoid, ignored, ignored_data, false, true );
341 }
342
KArcParseSRAUnbounded(struct KToc * self,const void * kvoid,bool (CC * ignored)(const struct KDirectory *,const char *,void *),void * ignored_data)343 LIB_EXPORT rc_t CC KArcParseSRAUnbounded ( struct KToc * self,
344 const void * kvoid,
345 bool (CC*ignored) (const struct KDirectory*, const char*, void*),
346 void *ignored_data )
347 {
348 return KArcParseSRAInt ( self, kvoid, ignored, ignored_data, true, false );
349 }
350
KArcParseSRAUnbounded_silent(struct KToc * self,const void * kvoid,bool (CC * ignored)(const struct KDirectory *,const char *,void *),void * ignored_data)351 LIB_EXPORT rc_t CC KArcParseSRAUnbounded_silent ( struct KToc * self,
352 const void * kvoid,
353 bool (CC*ignored) (const struct KDirectory*, const char*, void*),
354 void *ignored_data )
355 {
356 return KArcParseSRAInt ( self, kvoid, ignored, ignored_data, true, false );
357 }
358
359
KDirectoryVOpenSraArchiveRead(struct KDirectory const * self,struct KDirectory const ** sra_dir,int chroot,const char * path,va_list args)360 LIB_EXPORT rc_t CC KDirectoryVOpenSraArchiveRead ( struct KDirectory const *self,
361 struct KDirectory const **sra_dir, int chroot, const char *path, va_list args )
362 {
363 /* respond properly to va_list */
364 char full [ 4096 ];
365 int len = vsnprintf ( full, sizeof full, path, args );
366 if ( len < 0 )
367 return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcExcessive );
368
369 /* putting off parameter validation into this call */
370 return KDirectoryOpenArcDirRead (self, sra_dir, chroot, full, tocKFile,
371 KArcParseSRA, NULL, NULL);
372 }
373
374
KDirectoryOpenSraArchiveRead(struct KDirectory const * self,struct KDirectory const ** sra_dir,int chroot,const char * path,...)375 LIB_EXPORT rc_t CC KDirectoryOpenSraArchiveRead ( struct KDirectory const *self,
376 struct KDirectory const **sra_dir, int chroot, const char *path, ... )
377 {
378 rc_t rc;
379 va_list args;
380
381 va_start ( args, path );
382 rc = KDirectoryVOpenSraArchiveRead ( self, sra_dir, chroot, path, args );
383 va_end ( args );
384
385 return rc;
386 }
387
388
KDirectoryVOpenSraArchiveRead_silent(struct KDirectory const * self,struct KDirectory const ** sra_dir,int chroot,const char * path,va_list args)389 LIB_EXPORT rc_t CC KDirectoryVOpenSraArchiveRead_silent ( struct KDirectory const *self,
390 struct KDirectory const **sra_dir, int chroot, const char *path, va_list args )
391 {
392 /* respond properly to va_list */
393 char full [ 4096 ];
394 int len = vsnprintf ( full, sizeof full, path, args );
395 if ( len < 0 )
396 return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcExcessive );
397
398 /* putting off parameter validation into this call */
399 return KDirectoryOpenArcDirRead_silent ( self, sra_dir, false, full, tocKFile,
400 KArcParseSRA_silent, NULL, NULL );
401 }
402
403
KDirectoryOpenSraArchiveRead_silent(struct KDirectory const * self,struct KDirectory const ** sra_dir,int chroot,const char * path,...)404 LIB_EXPORT rc_t CC KDirectoryOpenSraArchiveRead_silent ( struct KDirectory const *self,
405 struct KDirectory const **sra_dir, int chroot, const char *path, ... )
406 {
407 rc_t rc;
408 va_list args;
409
410 va_start ( args, path );
411 rc = KDirectoryVOpenSraArchiveRead_silent ( self, sra_dir, chroot, path, args );
412 va_end ( args );
413
414 return rc;
415 }
416
417
KDirectoryVOpenSraArchiveReadUnbounded_silent_preopened(struct KDirectory const * self,struct KDirectory const ** sra_dir,int chroot,const struct KFile * f,const char * path,va_list args)418 LIB_EXPORT rc_t CC KDirectoryVOpenSraArchiveReadUnbounded_silent_preopened ( struct KDirectory const *self,
419 struct KDirectory const **sra_dir, int chroot, const struct KFile * f, const char *path, va_list args )
420 {
421 /* respond properly to va_list */
422 char full [ 4096 ];
423 int len = vsnprintf ( full, sizeof full, path, args );
424 if ( len < 0 || len >= sizeof full )
425 return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcExcessive );
426
427 /* putting off parameter validation into this call */
428 return KDirectoryOpenArcDirRead_silent_preopened ( self, sra_dir, false, full, tocKFile,
429 ( void* ) f, KArcParseSRAUnbounded_silent, NULL, NULL );
430 }
431
432
KDirectoryOpenSraArchiveReadUnbounded_silent_preopened(struct KDirectory const * self,struct KDirectory const ** sra_dir,int chroot,const struct KFile * f,const char * path,...)433 LIB_EXPORT rc_t CC KDirectoryOpenSraArchiveReadUnbounded_silent_preopened ( struct KDirectory const *self,
434 struct KDirectory const **sra_dir, int chroot, const struct KFile * f, const char *path, ... )
435 {
436 rc_t rc;
437 va_list args;
438
439 va_start ( args, path );
440 rc = KDirectoryVOpenSraArchiveReadUnbounded_silent_preopened ( self, sra_dir, chroot, f, path, args );
441 va_end ( args );
442
443 return rc;
444 }
445
446
KDirectoryVOpenSraArchiveReadUnbounded(struct KDirectory const * self,struct KDirectory const ** sra_dir,int chroot,const char * path,va_list args)447 LIB_EXPORT rc_t CC KDirectoryVOpenSraArchiveReadUnbounded ( struct KDirectory const *self,
448 struct KDirectory const **sra_dir, int chroot, const char *path, va_list args )
449 {
450 /* respond properly to va_list */
451 char full [ 4096 ];
452 int len = vsnprintf ( full, sizeof full, path, args );
453 if ( len < 0 )
454 return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcExcessive );
455
456 /* putting off parameter validation into this call */
457 return KDirectoryOpenArcDirRead (self, sra_dir, false, full, tocKFile,
458 KArcParseSRAUnbounded, NULL, NULL);
459 }
460
461
KDirectoryOpenSraArchiveReadUnbounded(struct KDirectory const * self,struct KDirectory const ** sra_dir,int chroot,const char * path,...)462 LIB_EXPORT rc_t CC KDirectoryOpenSraArchiveReadUnbounded ( struct KDirectory const *self,
463 struct KDirectory const **sra_dir, int chroot, const char *path, ... )
464 {
465 rc_t rc;
466 va_list args;
467
468 va_start ( args, path );
469 rc = KDirectoryVOpenSraArchiveReadUnbounded (self, sra_dir, chroot, path, args);
470 va_end ( args );
471
472 return rc;
473 }
474
475
KFileIsSRA(const char * b,size_t z)476 LIB_EXPORT rc_t CC KFileIsSRA (const char * b, size_t z)
477 {
478 const KSraHeader * h = (const KSraHeader *)b;
479
480 if (SraHeaderValidate (h, NULL, NULL, z) == 0)
481 return 0;
482
483 return RC (rcFS, rcFile, rcIdentifying, rcBuffer, rcWrongType);
484 }
485
486 /* end of file */
487