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