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