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 #include <kfs/extern.h>
27 /* #include <klib/container.h> */
28 /* #include <klib/vector.h> */
29 /* #include <klib/pbstree.h> */
30 /* #include <klib/text.h> */
31 /* #include <kfs/file.h> */
32 /* #include <assert.h> */
33 /* #include <limits.h> */
34 /* #include <stdio.h> */
35 /* #include <stdlib.h> */
36 /* #include <string.h> */
37
38 /* #include <klib/container.h> */
39 /* #include <klib/vector.h> */
40 /* #include <klib/pbstree.h> */
41 /* #include <klib/text.h> */
42 #include <klib/log.h>
43 #include <klib/rc.h>
44 #include <kfs/file.h>
45 #include <kfs/teefile.h>
46 #include <sysalloc.h>
47
48 #include <assert.h>
49 /* #include <limits.h> */
50 /* #include <stdio.h> */
51 #include <stdlib.h>
52 /* #include <string.h> */
53
54 /* ======================================================================
55 * KTeeFile
56 * a file inside an archive
57 */
58
59 /* -----
60 * define the specific types to be used in the templatish/inheritancish
61 * definition of vtables and their elements
62 */
63 #define KFILE_IMPL struct KTeeFile
64 #include <kfs/impl.h>
65
66 static rc_t CC KTeeFileDestroy (KTeeFile *self);
67 static struct KSysFile *CC KTeeFileGetSysFile (const KTeeFile *self,
68 uint64_t *offset);
69 static rc_t CC KTeeFileRandomAccessRead (const KTeeFile *self);
70 static rc_t CC KTeeFileRandomAccessUpdate (const KTeeFile *self);
71 static uint32_t CC KTeeFileType (const KTeeFile *self);
72 static rc_t CC KTeeFileSize (const KTeeFile *self, uint64_t *size);
73 static rc_t CC KTeeFileSetSizeRead (KTeeFile *self, uint64_t size);
74 static rc_t CC KTeeFileSetSizeUpdate (KTeeFile *self, uint64_t size);
75 static rc_t CC KTeeFileRead (const KTeeFile *self, uint64_t pos,
76 void *buffer, size_t bsize, size_t *num_read);
77 static rc_t CC KTeeFileWriteRead (KTeeFile *self, uint64_t pos, const void *buffer,
78 size_t size, size_t *num_writ);
79 static rc_t CC KTeeFileWriteUpdate (KTeeFile *self, uint64_t pos, const void *buffer,
80 size_t size, size_t *num_writ);
81
82
83 static const KFile_vt_v1 vtKTeeFileRead =
84 {
85 /* version */
86 1, 1,
87
88 /* 1.0 */
89 KTeeFileDestroy,
90 KTeeFileGetSysFile,
91 KTeeFileRandomAccessRead,
92 KTeeFileSize,
93 KTeeFileSetSizeRead,
94 KTeeFileRead,
95 KTeeFileWriteRead,
96
97 /* 1.1 */
98 KTeeFileType
99 };
100 static const KFile_vt_v1 vtKTeeFileUpdate =
101 {
102 /* version */
103 1, 1,
104
105 /* 1.0 */
106 KTeeFileDestroy,
107 KTeeFileGetSysFile,
108 KTeeFileRandomAccessUpdate,
109 KTeeFileSize,
110 KTeeFileSetSizeUpdate,
111 KTeeFileRead,
112 KTeeFileWriteUpdate,
113
114 /* 1.1 */
115 KTeeFileType
116 };
117
118
119 /*-----------------------------------------------------------------------
120 * KTeeFile
121 * an archive file including tar and sra
122 */
123 struct KTeeFile
124 {
125 KFile dad;
126 uint64_t maxposition;
127 KFile * original;
128 KFile * copy;
129 };
130
131 static
KTeeFileSeek(const KTeeFile * cself,uint64_t pos)132 rc_t KTeeFileSeek (const KTeeFile *cself, uint64_t pos)
133 {
134 KTeeFile * self;
135 rc_t rc = 0;
136 size_t num_read;
137 uint8_t buff [ 32 * 1024 ];
138
139 self = (KTeeFile *)cself;
140 /* seek to "pos" */
141 while (self->maxposition < pos)
142 {
143 /* maximum to read in this buffer */
144 size_t to_read = sizeof buff;
145 if (self->maxposition + sizeof buff > pos )
146 to_read = (size_t) (pos - self->maxposition);
147
148 /* read bytes */
149 rc = KFileRead (&self->dad, self->maxposition, buff, to_read, &num_read );
150 if ( rc != 0 )
151 break;
152
153 /* detect EOF */
154 if (num_read == 0)
155 {
156 break;
157 }
158 }
159
160 return rc;
161 }
162
163
164 /* ----------------------------------------------------------------------
165 * KTeeFileMake
166 * create a new file object
167 */
168
169 static
KTeeFileMake(KTeeFile ** self,KFile * original,KFile * copy,const KFile_vt * vt,bool read_enabled,bool write_enabled)170 rc_t KTeeFileMake (KTeeFile ** self,
171 KFile * original,
172 KFile * copy,
173 const KFile_vt * vt,
174 bool read_enabled,
175 bool write_enabled)
176 {
177 rc_t rc;
178 KTeeFile * pF;
179
180 /* -----
181 * we can not accept any of the three pointer parameters as NULL
182 */
183 assert (self != NULL);
184 assert (original != NULL);
185 assert (copy != NULL);
186
187 /* -----
188 * the enables should be true or false
189 */
190 assert ((read_enabled == true)||(read_enabled == false));
191 assert ((write_enabled == true)||(write_enabled == false));
192
193 /* -----
194 * get space for the object
195 */
196 pF = malloc (sizeof (KTeeFile));
197 if (pF == NULL) /* allocation failed */
198 {
199 /* fail */
200 rc = RC (rcFS, rcFile, rcConstructing, rcMemory, rcExhausted);
201 }
202 else
203 {
204 rc = KFileInit (&pF->dad, /* initialize base class */
205 vt, /* VTable for KTeeFile */
206 "KTeeFile", "no-name",
207 read_enabled, /* read allowed */
208 write_enabled); /* write disallowed */
209 if (rc == 0)
210 {
211 /* take over the existing KFile Reference for original and copy*/
212 /* succeed */
213 pF->original = original;
214 pF->copy = copy;
215 pF->maxposition = 0;
216 *self = pF;
217 return 0;
218 }
219 /* fail */
220 free (pF);
221 }
222 return rc;
223 }
224
KFileMakeTeeRead(const KFile ** self,const KFile * original,KFile * copy)225 LIB_EXPORT rc_t CC KFileMakeTeeRead (const KFile ** self, const KFile * original, KFile * copy)
226 {
227 return KTeeFileMake ((KTeeFile **)self, (KFile*)original, copy,
228 (const KFile_vt*)&vtKTeeFileRead, true, false);
229 }
230
KFileMakeTeeUpdate(KFile ** self,KFile * original,KFile * copy)231 LIB_EXPORT rc_t CC KFileMakeTeeUpdate (KFile ** self, KFile * original, KFile * copy)
232 {
233 return KTeeFileMake ((KTeeFile **)self, original, copy,
234 (const KFile_vt*)&vtKTeeFileUpdate, true, true);
235 }
236
237 /* ----------------------------------------------------------------------
238 * Destroy
239 *
240 */
241 static
KTeeFileDestroy(KTeeFile * self)242 rc_t CC KTeeFileDestroy (KTeeFile *self)
243 {
244 rc_t rc;
245 uint64_t last_max;
246
247 assert (self != NULL);
248
249 do
250 {
251 last_max = self->maxposition;
252
253 /* keep seeking ahead by a Gigabyte until we read no more */
254 rc = KTeeFileSeek (self, last_max + 1024*1024*1024);
255 if (rc != 0)
256 return rc;
257
258 } while (last_max < self->maxposition);
259
260 rc = KFileRelease (self->original);
261 if ( rc == 0 )
262 {
263 KFileRelease (self->copy);
264 free (self);
265 }
266 return rc;
267 }
268
269 /* ----------------------------------------------------------------------
270 * GetSysFile
271 * returns an underlying system file object
272 * and starting offset to contiguous region
273 * suitable for memory mapping, or NULL if
274 * no such file is available.
275 *
276 * We cant allow memory mapping a tee file as the read?writes ar needed
277 * to trigger the writes to the copy KFile
278 */
279
280 static
KTeeFileGetSysFile(const KTeeFile * self,uint64_t * offset)281 struct KSysFile *CC KTeeFileGetSysFile (const KTeeFile *self, uint64_t *offset)
282 {
283 /* parameters must be non-NULL */
284 assert (self != NULL);
285 assert (offset != NULL);
286
287 return NULL;
288 }
289
290 /* ----------------------------------------------------------------------
291 * RandomAccess
292 *
293 * returns 0 if random access, error code otherwise
294 *
295 * Update needs to be able to seek both original and copy while read
296 * only needs to be able to seek the original.
297 */
298 static
KTeeFileRandomAccessUpdate(const KTeeFile * self)299 rc_t CC KTeeFileRandomAccessUpdate (const KTeeFile *self)
300 {
301 rc_t rc;
302 assert (self != NULL);
303 rc = KFileRandomAccess (self->original);
304 if (rc == 0)
305 rc = KFileRandomAccess (self->copy);
306 return rc;
307 }
308 static
KTeeFileRandomAccessRead(const KTeeFile * self)309 rc_t CC KTeeFileRandomAccessRead (const KTeeFile *self)
310 {
311 rc_t rc;
312 assert (self != NULL);
313 rc = KFileRandomAccess (self->original);
314 return rc;
315 }
316
317 /* ----------------------------------------------------------------------
318 * Type
319 * returns a KFileDesc
320 * not intended to be a content type,
321 * but rather an implementation class
322 */
323 static
KTeeFileType(const KTeeFile * self)324 uint32_t CC KTeeFileType (const KTeeFile *self)
325 {
326 return KFileType (self->original);
327 }
328
329
330 /* ----------------------------------------------------------------------
331 * Size
332 * returns size in bytes of file
333 *
334 * "size" [ OUT ] - return parameter for file size
335 */
336 static
KTeeFileSize(const KTeeFile * self,uint64_t * size)337 rc_t CC KTeeFileSize (const KTeeFile *self, uint64_t *size)
338 {
339 rc_t rc;
340 uint64_t fsize;
341
342 assert (self != NULL);
343 assert (size != NULL);
344
345 rc = KFileSize (self->original, &fsize);
346
347 if (rc == 0)
348 {
349 /* success */
350 *size = fsize;
351 }
352 /* pass along RC value */
353 return rc;
354 }
355
356 /* ----------------------------------------------------------------------
357 * SetSize
358 * sets size in bytes of file
359 *
360 * "size" [ IN ] - new file size
361 */
362 static
KTeeFileSetSizeUpdate(KTeeFile * self,uint64_t size)363 rc_t CC KTeeFileSetSizeUpdate (KTeeFile *self, uint64_t size)
364 {
365 rc_t rc;
366
367 rc = KFileSetSize (self->original, size);
368 if (rc == 0)
369 rc = KFileSetSize (self->copy, size);
370 return rc;
371 }
372 static
KTeeFileSetSizeRead(KTeeFile * self,uint64_t size)373 rc_t CC KTeeFileSetSizeRead (KTeeFile *self, uint64_t size)
374 {
375 return RC (rcFS, rcFile, rcUpdating, rcSelf, rcUnsupported);
376 }
377
378 /* ----------------------------------------------------------------------
379 * Read
380 * read file from known position
381 *
382 * "pos" [ IN ] - starting position within file
383 *
384 * "buffer" [ OUT ] and "bsize" [ IN ] - return buffer for read
385 *
386 * "num_read" [ OUT, NULL OKAY ] - optional return parameter
387 * giving number of bytes actually read
388 */
389 static
KTeeFileRead(const KTeeFile * cself,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)390 rc_t CC KTeeFileRead (const KTeeFile *cself,
391 uint64_t pos,
392 void *buffer,
393 size_t bsize,
394 size_t *num_read)
395 {
396 KTeeFile * self;
397 uint64_t maxposition;
398 size_t read;
399 size_t written;
400 size_t sofar;
401 rc_t rc;
402
403
404 /* -----
405 * self and buffer were validated as not NULL before calling here
406 *
407 * So get the KTTOCNode type: chunked files and contiguous files
408 * are read differently.
409 */
410 assert (cself != NULL);
411 assert (buffer != NULL);
412 assert (num_read != NULL);
413 assert (bsize != 0);
414
415 rc = 0;
416 read = 0;
417 self = (KTeeFile*)cself;
418 maxposition = self->maxposition;
419 if (pos > maxposition)
420 rc = KTeeFileSeek (self, pos);
421 if (rc == 0)
422 {
423 rc = KFileRead (self->original, pos, buffer, bsize, &read);
424 if (rc == 0)
425 {
426 if (pos + read > maxposition)
427 {
428 for ( sofar = (size_t)( maxposition - pos );
429 sofar < read;
430 sofar += written)
431 {
432 rc = KFileWrite (self->copy, pos + sofar, (uint8_t*)buffer + sofar,
433 read - sofar, &written);
434 if (rc != 0)
435 break;
436 if (written == 0)
437 {
438 LOGERR (klogErr, rc, "Failure to write to copy in KTeeFileRead");
439 rc = RC (rcFS, rcFile, rcReading, rcFile, rcIncomplete);
440 break;
441 }
442 }
443 maxposition = pos + sofar;
444 if (maxposition > self->maxposition)
445 self->maxposition = maxposition;
446 }
447 }
448 }
449 *num_read = read;
450 return rc;
451 }
452
453 /* ----------------------------------------------------------------------
454 * Write
455 * write file at known position
456 *
457 * "pos" [ IN ] - starting position within file
458 *
459 * "buffer" [ IN ] and "size" [ IN ] - data to be written
460 *
461 * "num_writ" [ OUT, NULL OKAY ] - optional return parameter
462 * giving number of bytes actually written
463 *
464 * Unsupported as we now treat archives as READ ONLY
465 */
466 static
KTeeFileWriteUpdate(KTeeFile * self,uint64_t pos,const void * buffer,size_t bsize,size_t * num_writ)467 rc_t CC KTeeFileWriteUpdate (KTeeFile *self, uint64_t pos,
468 const void *buffer, size_t bsize,
469 size_t *num_writ)
470 {
471 uint64_t max_position;
472 size_t writ;
473 size_t written;
474 size_t sofar;
475 rc_t rc;
476
477 assert (self != NULL);
478 assert (buffer != NULL);
479 assert (num_writ != NULL);
480 assert (bsize != 0);
481
482 writ = 0;
483 rc = 0;
484 if (pos > self->maxposition)
485 rc = KTeeFileSeek (self, pos);
486 if (rc == 0)
487 {
488 rc = KFileWrite (self->original, pos, buffer, bsize, &writ);
489 if (rc == 0)
490 {
491 for ( sofar = written = 0; sofar < writ; sofar += written)
492 {
493 rc = KFileWrite (self->copy, pos + sofar, (uint8_t*)buffer + sofar,
494 writ - sofar, &written);
495 if (rc != 0)
496 break;
497 if (written == 0)
498 {
499 rc = RC (rcFS, rcFile, rcReading, rcFile, rcIncomplete);
500 LOGERR (klogErr, rc, "Failure to write to copy in KTeeFileWrite");
501 break;
502 }
503 }
504 max_position = pos + sofar;
505 if (max_position > self->maxposition)
506 self->maxposition = max_position;
507 }
508 }
509 *num_writ = writ;
510 return rc;
511 }
512 static
KTeeFileWriteRead(KTeeFile * self,uint64_t pos,const void * buffer,size_t bsize,size_t * num_writ)513 rc_t CC KTeeFileWriteRead (KTeeFile *self, uint64_t pos,
514 const void *buffer, size_t bsize,
515 size_t *num_writ)
516 {
517 assert (self != NULL);
518 assert (buffer != NULL);
519 assert (num_writ != NULL);
520 assert (bsize != 0);
521
522 *num_writ = 0;
523 return RC (rcFS, rcFile, rcWriting, rcSelf, rcUnsupported);
524 }
525
526 /* ----------------------------------------------------------------------
527 *
528 */
529
530
531 /* end of file teefile.c */
532
533