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 #include <kfs/impl.h>
29 #include <klib/rc.h>
30 #include <kproc/timeout.h>
31 #include <klib/status.h>
32 #include <os-native.h>
33 #include <sysalloc.h>
34 
35 #include <assert.h>
36 
37 /*--------------------------------------------------------------------------
38  * KFile
39  *  a file
40  */
41 
42 /* Destroy
43  *  destroy file
44  */
KFileDestroy_v1(KFile_v1 * self)45 LIB_EXPORT rc_t CC KFileDestroy_v1 ( KFile_v1 *self )
46 {
47     if ( self == NULL )
48         return RC ( rcFS, rcFile, rcDestroying, rcSelf, rcNull );
49 
50     switch ( self -> vt -> v1 . maj )
51     {
52     case 1:
53         return ( * self -> vt -> v1 . destroy ) ( self );
54     }
55 
56     return RC ( rcFS, rcFile, rcDestroying, rcInterface, rcBadVersion );
57 }
58 
59 /* GetSysFile
60  *  returns an underlying system file object
61  *  and starting offset to contiguous region
62  *  suitable for memory mapping, or NULL if
63  *  no such file is available.
64  */
KFileGetSysFile_v1(const KFile_v1 * self,uint64_t * offset)65 LIB_EXPORT struct KSysFile_v1 * CC KFileGetSysFile_v1 ( const KFile_v1 *self, uint64_t *offset )
66 {
67     if ( offset != NULL )
68     {
69         * offset = 0;
70         if ( self != NULL )
71         {
72             switch ( self -> vt -> v1 . maj )
73             {
74             case 1:
75                 return ( * self -> vt -> v1 . get_sysfile ) ( self, offset );
76             }
77         }
78     }
79     return NULL;
80 }
81 
82 /* AddRef
83  *  creates a new reference
84  *  ignores NULL references
85  */
KFileAddRef(const KFile_v1 * self)86 LIB_EXPORT rc_t CC KFileAddRef ( const KFile_v1 *self )
87 {
88     if ( self != NULL )
89     {
90         switch ( KRefcountAdd ( & self -> refcount, "KFile" ) )
91         {
92         case krefLimit:
93             return RC ( rcFS, rcFile, rcAttaching, rcRange, rcExcessive );
94         case krefNegative:
95             return RC ( rcFS, rcFile, rcAttaching, rcSelf, rcInvalid );
96         default:
97             break;
98         }
99     }
100     return 0;
101 }
102 
103 /* Release
104  *  discard reference to file
105  *  ignores NULL references
106  */
KFileRelease_v1(const KFile_v1 * self)107 LIB_EXPORT rc_t CC KFileRelease_v1 ( const KFile_v1 *self )
108 {
109     if ( self != NULL )
110     {
111         switch ( KRefcountDrop ( & self -> refcount, "KFile" ) )
112         {
113         case krefWhack:
114             if ( self -> dir != NULL )
115                 return KDirectoryDestroyFile_v1 ( self -> dir, ( KFile_v1 * ) self );
116             return KFileDestroy_v1 ( ( KFile_v1 * ) self );
117         case krefNegative:
118             return RC ( rcFS, rcFile, rcReleasing, rcRange, rcExcessive );
119         default:
120             break;
121         }
122     }
123 
124     return 0;
125 }
126 
127 /* RandomAccess
128  *  ALMOST by definition, the file is random access
129  *  certain file types ( notably compressors ) will refuse random access
130  *
131  *  returns 0 if random access, error code otherwise
132  */
KFileRandomAccess_v1(const KFile_v1 * self)133 LIB_EXPORT rc_t CC KFileRandomAccess_v1 ( const KFile_v1 *self )
134 {
135     if ( self == NULL )
136         return RC ( rcFS, rcFile, rcAccessing, rcSelf, rcNull );
137 
138     switch ( self -> vt -> v1 . maj )
139     {
140     case 1:
141         return ( * self -> vt -> v1 . random_access ) ( self );
142     }
143 
144     return RC ( rcFS, rcFile, rcAccessing, rcInterface, rcBadVersion );
145 }
146 
147 /* Type
148  *  returns a KFileDesc
149  *  not intended to be a content type,
150  *  but rather an implementation class
151  */
KFileType_v1(const KFile_v1 * self)152 LIB_EXPORT uint32_t CC KFileType_v1 ( const KFile_v1 *self )
153 {
154     if ( self == NULL )
155         return kfdNull;
156 
157     switch ( self -> vt -> v1 . maj )
158     {
159     case 1:
160         if ( self -> vt -> v1 . min >= 1 )
161             return ( * self -> vt -> v1 . get_type ) ( self );
162         break;
163     }
164 
165     return kfdInvalid;
166 }
167 
168 /* Size
169  *  returns size in bytes of file
170  *
171  *  "size" [ OUT ] - return parameter for file size
172  */
KFileSize_v1(const KFile_v1 * self,uint64_t * size)173 LIB_EXPORT rc_t CC KFileSize_v1 ( const KFile_v1 *self, uint64_t *size )
174 {
175     if ( size == NULL )
176         return RC ( rcFS, rcFile, rcAccessing, rcParam, rcNull );
177 
178     * size = 0;
179 
180     if ( self == NULL )
181         return RC ( rcFS, rcFile, rcAccessing, rcSelf, rcNull );
182 
183     switch ( self -> vt -> v1 . maj )
184     {
185     case 1:
186         return ( * self -> vt -> v1 . get_size ) ( self, size );
187     }
188 
189     return RC ( rcFS, rcFile, rcAccessing, rcInterface, rcBadVersion );
190 }
191 
192 /* SetSize
193  *  sets size in bytes of file
194  *
195  *  "size" [ IN ] - new file size
196  */
KFileSetSize_v1(KFile_v1 * self,uint64_t size)197 LIB_EXPORT rc_t CC KFileSetSize_v1 ( KFile_v1 *self, uint64_t size )
198 {
199     if ( self == NULL )
200         return RC ( rcFS, rcFile, rcResizing, rcSelf, rcNull );
201 
202     if ( ! self -> write_enabled )
203         return RC ( rcFS, rcFile, rcResizing, rcFile, rcNoPerm );
204 
205     switch ( self -> vt -> v1 . maj )
206     {
207     case 1:
208         return ( * self -> vt -> v1 . set_size ) ( self, size );
209     }
210 
211     return RC ( rcFS, rcFile, rcResizing, rcInterface, rcBadVersion );
212 }
213 
214 /* Read
215  *  read file from known position
216  *
217  *  "pos" [ IN ] - starting position within file
218  *
219  *  "buffer" [ OUT ] and "bsize" [ IN ] - return buffer for read
220  *
221  *  "num_read" [ OUT ] - number of bytes actually read
222  */
KFileRead_v1(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)223 LIB_EXPORT rc_t CC KFileRead_v1 ( const KFile_v1 *self, uint64_t pos,
224     void *buffer, size_t bsize, size_t *num_read )
225 {
226     if ( num_read == NULL )
227         return RC ( rcFS, rcFile, rcReading, rcParam, rcNull );
228 
229     * num_read = 0;
230 
231     if ( self == NULL )
232         return RC ( rcFS, rcFile, rcReading, rcSelf, rcNull );
233 
234     if ( ! self -> read_enabled )
235         return RC ( rcFS, rcFile, rcReading, rcFile, rcNoPerm );
236 
237     if ( buffer == NULL )
238         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcNull );
239     if ( bsize == 0 )
240         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcInsufficient );
241 
242     switch ( self -> vt -> v1 . maj )
243     {
244     case 1:
245         return ( * self -> vt -> v1 . read ) ( self, pos, buffer, bsize, num_read );
246     }
247 
248     return RC ( rcFS, rcFile, rcReading, rcInterface, rcBadVersion );
249 }
250 
KFileTimedRead_v1(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read,struct timeout_t * tm)251 LIB_EXPORT rc_t CC KFileTimedRead_v1 ( const KFile_v1 *self, uint64_t pos,
252     void *buffer, size_t bsize, size_t *num_read, struct timeout_t *tm )
253 {
254     if ( num_read == NULL )
255         return RC ( rcFS, rcFile, rcReading, rcParam, rcNull );
256 
257     * num_read = 0;
258 
259     if ( self == NULL )
260         return RC ( rcFS, rcFile, rcReading, rcSelf, rcNull );
261 
262     if ( ! self -> read_enabled )
263         return RC ( rcFS, rcFile, rcReading, rcFile, rcNoPerm );
264 
265     if ( buffer == NULL )
266         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcNull );
267     if ( bsize == 0 )
268         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcInsufficient );
269 
270     switch ( self -> vt -> v1 . maj )
271     {
272     case 1:
273         if ( self -> vt -> v1 . min >= 2 )
274             return ( * self -> vt -> v1 . timed_read ) ( self, pos, buffer, bsize, num_read, tm );
275         if ( tm == NULL )
276             return ( * self -> vt -> v1 . read ) ( self, pos, buffer, bsize, num_read );
277         break;
278     }
279 
280     return RC ( rcFS, rcFile, rcReading, rcInterface, rcBadVersion );
281 }
282 
283 /* ReadAll
284  *  read from file until "bsize" bytes have been retrieved
285  *  or until end-of-input
286  *
287  *  "pos" [ IN ] - starting position within file
288  *
289  *  "buffer" [ OUT ] and "bsize" [ IN ] - return buffer for read
290  *
291  *  "num_read" [ OUT ] - return parameter giving number of bytes
292  *  actually read. when returned value is zero and return code is
293  *  also zero, interpreted as end of file.
294  */
KFileReadAll_v1(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)295 LIB_EXPORT rc_t CC KFileReadAll_v1 ( const KFile_v1 *self, uint64_t pos,
296     void *buffer, size_t bsize, size_t *num_read )
297 {
298     rc_t rc;
299     uint8_t *b;
300     size_t total, count;
301 
302     if ( num_read == NULL )
303         return RC ( rcFS, rcFile, rcReading, rcParam, rcNull );
304 
305     * num_read = 0;
306 
307     if ( self == NULL )
308         return RC ( rcFS, rcFile, rcReading, rcSelf, rcNull );
309 
310     if ( ! self -> read_enabled )
311         return RC ( rcFS, rcFile, rcReading, rcFile, rcNoPerm );
312 
313     if ( buffer == NULL )
314         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcNull );
315     if ( bsize == 0 )
316         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcInsufficient );
317 
318     STATUS ( STAT_GEEK, "%s ( %p, %lu, %p, %zu )\n", __func__, self, pos, buffer, bsize );
319 
320     switch ( self -> vt -> v1 . maj )
321     {
322     case 1:
323         count = 0;
324         rc = ( * self -> vt -> v1 . read ) ( self, pos, buffer, bsize, & count );
325         total = count;
326 
327         STATUS ( STAT_GEEK, "%s initial read rc = %R, count = %zu\n", __func__, rc, count );
328 
329         if ( rc == 0 && count != 0 && count < bsize )
330         {
331             if ( self -> vt -> v1 . min >= 2 )
332             {
333                 timeout_t no_block;
334                 TimeoutInit ( & no_block, 0 );
335 
336                 STATUS ( STAT_GEEK, "%s using non-blocking read-all\n", __func__ );
337 
338                 for ( b = buffer; total < bsize; total += count )
339                 {
340                     count = 0;
341                     rc = ( * self -> vt -> v1 . timed_read ) ( self, pos + total, b + total, bsize - total, & count, & no_block );
342                     STATUS ( STAT_GEEK, "%s ( %p, %lu, %p, %zu, [ %zu ] )\n", __func__, self, pos + total, b + total, bsize - total, count );
343                     if ( rc != 0 )
344                     {
345                         STATUS ( STAT_GEEK, "%s - breaking loop with rc = %R\n", __func__, rc );
346                         break;
347                     }
348                     if ( count == 0 )
349                     {
350                         STATUS ( STAT_GEEK, "%s - breaking loop with count == 0\n", __func__ );
351                         break;
352                     }
353                 }
354             }
355             else
356             {
357                 STATUS ( STAT_GEEK, "%s using blocking read-all\n", __func__ );
358 
359                 for ( b = buffer; total < bsize; total += count )
360                 {
361                     count = 0;
362                     rc = ( * self -> vt -> v1 . read ) ( self, pos + total, b + total, bsize - total, & count );
363                     STATUS ( STAT_GEEK, "%s ( %p, %lu, %p, %zu, [ %zu ] )\n", __func__, self, pos + total, b + total, bsize - total, count );
364                     if ( rc != 0 )
365                     {
366                         STATUS ( STAT_GEEK, "%s - breaking loop with rc = %R\n", __func__, rc );
367                         break;
368                     }
369                     if ( count == 0 )
370                     {
371                         STATUS ( STAT_GEEK, "%s - breaking loop with count == 0\n", __func__ );
372                         break;
373                     }
374                 }
375             }
376         }
377         break;
378     default:
379         return RC ( rcFS, rcFile, rcReading, rcInterface, rcBadVersion );
380     }
381 
382     if ( total != 0 )
383     {
384         * num_read = total;
385         return 0;
386     }
387 
388     return rc;
389 }
390 
KFileTimedReadAll_v1(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read,struct timeout_t * tm)391 LIB_EXPORT rc_t CC KFileTimedReadAll_v1 ( const KFile_v1 *self, uint64_t pos,
392     void *buffer, size_t bsize, size_t *num_read, struct timeout_t *tm )
393 {
394     rc_t rc;
395     uint8_t *b;
396     size_t total, count;
397 
398     if ( num_read == NULL )
399         return RC ( rcFS, rcFile, rcReading, rcParam, rcNull );
400 
401     * num_read = 0;
402 
403     if ( self == NULL )
404         return RC ( rcFS, rcFile, rcReading, rcSelf, rcNull );
405 
406     if ( ! self -> read_enabled )
407         return RC ( rcFS, rcFile, rcReading, rcFile, rcNoPerm );
408 
409     if ( buffer == NULL )
410         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcNull );
411     if ( bsize == 0 )
412         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcInsufficient );
413 
414     switch ( self -> vt -> v1 . maj )
415     {
416     case 1:
417         if ( self -> vt -> v1 . min >= 2 )
418         {
419             count = 0;
420             rc = ( * self -> vt -> v1 . timed_read ) ( self, pos, buffer, bsize, & count, tm );
421             total = count;
422 
423             if ( rc == 0 && count != 0 && count < bsize )
424             {
425                 timeout_t no_block;
426                 TimeoutInit ( & no_block, 0 );
427 
428                 for ( b = buffer; total < bsize; total += count )
429                 {
430                     count = 0;
431                     rc = ( * self -> vt -> v1 . timed_read ) ( self, pos + total, b + total, bsize - total, & count, & no_block );
432                     if ( rc != 0 )
433                         break;
434                     if ( count == 0 )
435                         break;
436                 }
437             }
438             break;
439         }
440 
441         STATUS ( STAT_GEEK, "%s - target %p is not capable of receiving timed read message\n", __func__, self );
442         if ( tm == NULL )
443         {
444             STATUS ( STAT_GEEK, "%s - no timeout specified - call will succeed\n", __func__ );
445             for ( rc = 0, b = buffer, total = 0; total < bsize; total += count )
446             {
447                 count = 0;
448                 rc = ( * self -> vt -> v1 . read ) ( self, pos + total, b + total, bsize - total, & count );
449                 if ( rc != 0 )
450                     break;
451                 if ( count == 0 )
452                     break;
453             }
454             break;
455         }
456 
457         STATUS ( STAT_GEEK, "%s - timeout specified - call will fail\n", __func__ );
458 
459         /* no break */
460     default:
461         return RC ( rcFS, rcFile, rcReading, rcInterface, rcBadVersion );
462     }
463 
464     if ( total != 0 )
465     {
466         * num_read = total;
467         return 0;
468     }
469 
470     return rc;
471 }
472 
473 /* ReadExactly
474  * TimedReadExactly
475  *  read from file until "bytes" have been retrieved
476  *  or return incomplete transfer error
477  *
478  *  "pos" [ IN ] - starting position within file
479  *
480  *  "buffer" [ OUT ] and "bytes" [ IN ] - return buffer for read
481  *
482  *  "tm" [ IN/OUT, NULL OKAY ] - an optional indicator of
483  *  blocking behavior. not all implementations will support
484  *  timed reads. a NULL timeout will block indefinitely,
485  *  a value of "tm->mS == 0" will have non-blocking behavior
486  *  if supported by implementation, and "tm->mS > 0" will indicate
487  *  a maximum wait timeout.
488  */
KFileReadExactly_v1(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bytes)489 LIB_EXPORT rc_t CC KFileReadExactly_v1 ( const KFile_v1 *self,
490     uint64_t pos, void *buffer, size_t bytes )
491 {
492     rc_t rc;
493     uint8_t *b;
494     size_t total, count;
495 
496     if ( self == NULL )
497         return RC ( rcFS, rcFile, rcReading, rcSelf, rcNull );
498 
499     if ( ! self -> read_enabled )
500         return RC ( rcFS, rcFile, rcReading, rcFile, rcNoPerm );
501 
502     if ( bytes == 0 )
503         return 0;
504     if ( buffer == NULL )
505         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcNull );
506 
507     switch ( self -> vt -> v1 . maj )
508     {
509     case 1:
510         for ( b = buffer, total = 0; total < bytes; total += count )
511         {
512             count = 0;
513             rc = ( * self -> vt -> v1 . read ) ( self, pos + total, b + total, bytes - total, & count );
514             if ( rc != 0 )
515             {
516                 if ( GetRCObject ( rc ) != ( enum RCObject ) rcTimeout || GetRCState ( rc ) != rcExhausted )
517                     break;
518             }
519             else if ( count == 0 )
520             {
521                 rc = RC ( rcFS, rcFile, rcReading, rcTransfer, rcIncomplete );
522                 break;
523             }
524         }
525         break;
526     default:
527         rc = RC ( rcFS, rcFile, rcReading, rcInterface, rcBadVersion );
528     }
529 
530     return rc;
531 }
532 
KFileTimedReadExactly_v1(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bytes,struct timeout_t * tm)533 LIB_EXPORT rc_t CC KFileTimedReadExactly_v1 ( const KFile_v1 *self,
534     uint64_t pos, void *buffer, size_t bytes, struct timeout_t *tm )
535 {
536     rc_t rc;
537     uint8_t *b;
538     size_t total, count;
539 
540     if ( self == NULL )
541         return RC ( rcFS, rcFile, rcReading, rcSelf, rcNull );
542 
543     if ( ! self -> read_enabled )
544         return RC ( rcFS, rcFile, rcReading, rcFile, rcNoPerm );
545 
546     if ( bytes == 0 )
547         return 0;
548     if ( buffer == NULL )
549         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcNull );
550 
551     switch ( self -> vt -> v1 . maj )
552     {
553     case 1:
554         if ( self -> vt -> v1 . min >= 2 )
555         {
556             for ( b = buffer, total = 0; total < bytes; total += count )
557             {
558                 count = 0;
559                 rc = ( * self -> vt -> v1 . timed_read ) ( self, pos + total, b + total, bytes - total, & count, tm );
560                 if ( rc != 0 )
561                 {
562                     if ( tm != NULL )
563                         break;
564                     if ( GetRCObject ( rc ) != ( enum RCObject ) rcTimeout || GetRCState ( rc ) != rcExhausted )
565                         break;
566                 }
567                 else if ( count == 0 )
568                 {
569                     rc = RC ( rcFS, rcFile, rcReading, rcTransfer, rcIncomplete );
570                     break;
571                 }
572             }
573             break;
574         }
575 
576         if ( tm == NULL )
577         {
578             for ( b = buffer, total = 0; total < bytes; total += count )
579             {
580                 count = 0;
581                 rc = ( * self -> vt -> v1 . read ) ( self, pos + total, b + total, bytes - total, & count );
582                 if ( rc != 0 )
583                 {
584                     if ( GetRCObject ( rc ) != ( enum RCObject ) rcTimeout || GetRCState ( rc ) != rcExhausted )
585                         break;
586                 }
587                 else if ( count == 0 )
588                 {
589                     rc = RC ( rcFS, rcFile, rcReading, rcTransfer, rcIncomplete );
590                     break;
591                 }
592             }
593             break;
594         }
595 
596         /* no break */
597     default:
598         return RC ( rcFS, rcFile, rcReading, rcInterface, rcBadVersion );
599     }
600 
601     return rc;
602 }
603 
604 
605 /* ReadChunked
606  * TimedReadChunked
607  *  behaves like Read or TimedRead,
608  *  except that bytes read are delivered via callback message
609  *  there may be multiple such messages, allowing a long
610  *  synchronous read with multiple intermediate delivery.
611  */
KFileReadChunked_v1(const KFile_v1 * self,uint64_t pos,struct KChunkReader * chunks,size_t bytes,size_t * num_read)612 LIB_EXPORT rc_t CC KFileReadChunked_v1 ( const KFile_v1 *self, uint64_t pos,
613     struct KChunkReader * chunks, size_t bytes, size_t * num_read )
614 {
615     if ( num_read == NULL )
616         return RC ( rcFS, rcFile, rcReading, rcParam, rcNull );
617 
618     * num_read = 0;
619 
620     if ( self == NULL )
621         return RC ( rcFS, rcFile, rcReading, rcSelf, rcNull );
622 
623     if ( ! self -> read_enabled )
624         return RC ( rcFS, rcFile, rcReading, rcFile, rcNoPerm );
625 
626     if ( chunks == NULL )
627         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcNull );
628     if ( bytes == 0 )
629         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcInsufficient );
630 
631     switch ( self -> vt -> v1 . maj )
632     {
633     case 1:
634         if ( self -> vt -> v1 . min >= 3 )
635             return ( * self -> vt -> v1 . read_chunked ) ( self, pos, chunks, bytes, num_read );
636         break;
637     }
638 
639     return RC ( rcFS, rcFile, rcReading, rcInterface, rcBadVersion );
640 }
641 
KFileTimedReadChunked_v1(const KFile_v1 * self,uint64_t pos,struct KChunkReader * chunks,size_t bytes,size_t * num_read,struct timeout_t * tm)642 LIB_EXPORT rc_t CC KFileTimedReadChunked_v1 ( const KFile_v1 *self, uint64_t pos,
643     struct KChunkReader * chunks, size_t bytes, size_t * num_read, struct timeout_t *tm )
644 {
645     if ( num_read == NULL )
646         return RC ( rcFS, rcFile, rcReading, rcParam, rcNull );
647 
648     * num_read = 0;
649 
650     if ( self == NULL )
651         return RC ( rcFS, rcFile, rcReading, rcSelf, rcNull );
652 
653     if ( ! self -> read_enabled )
654         return RC ( rcFS, rcFile, rcReading, rcFile, rcNoPerm );
655 
656     if ( chunks == NULL )
657         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcNull );
658     if ( bytes == 0 )
659         return RC ( rcFS, rcFile, rcReading, rcBuffer, rcInsufficient );
660 
661     switch ( self -> vt -> v1 . maj )
662     {
663     case 1:
664         if ( self -> vt -> v1 . min >= 3 )
665             return ( * self -> vt -> v1 . timed_read_chunked ) ( self, pos, chunks, bytes, num_read, tm );
666         break;
667     }
668 
669     return RC ( rcFS, rcFile, rcReading, rcInterface, rcBadVersion );
670 }
671 
672 
673 /* Write
674  *  write file at known position
675  *
676  *  "pos" [ IN ] - starting position within file
677  *
678  *  "buffer" [ IN ] and "size" [ IN ] - data to be written
679  *
680  *  "num_writ" [ OUT ] - number of bytes actually written
681  */
KFileWrite_v1(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ)682 LIB_EXPORT rc_t CC KFileWrite_v1 ( KFile_v1 *self, uint64_t pos,
683     const void *buffer, size_t size, size_t *num_writ )
684 {
685     size_t ignore;
686     if ( num_writ == NULL )
687         num_writ = & ignore;
688 
689     * num_writ = 0;
690 
691     if ( self == NULL )
692         return RC ( rcFS, rcFile, rcWriting, rcSelf, rcNull );
693 
694     if ( ! self -> write_enabled )
695         return RC ( rcFS, rcFile, rcWriting, rcFile, rcNoPerm );
696 
697     if ( size == 0 )
698         return 0;
699     if ( buffer == NULL )
700         return RC ( rcFS, rcFile, rcWriting, rcBuffer, rcNull );
701 
702     switch ( self -> vt -> v1 . maj )
703     {
704     case 1:
705         return ( * self -> vt -> v1 . write ) ( self, pos, buffer, size, num_writ );
706     }
707 
708     return RC ( rcFS, rcFile, rcWriting, rcInterface, rcBadVersion );
709 }
710 
KFileTimedWrite_v1(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ,struct timeout_t * tm)711 LIB_EXPORT rc_t CC KFileTimedWrite_v1 ( KFile_v1 *self, uint64_t pos,
712     const void *buffer, size_t size, size_t *num_writ, struct timeout_t *tm )
713 {
714     size_t ignore;
715     if ( num_writ == NULL )
716         num_writ = & ignore;
717 
718     * num_writ = 0;
719 
720     if ( self == NULL )
721         return RC ( rcFS, rcFile, rcWriting, rcSelf, rcNull );
722 
723     if ( ! self -> write_enabled )
724         return RC ( rcFS, rcFile, rcWriting, rcFile, rcNoPerm );
725 
726     if ( size == 0 )
727         return 0;
728     if ( buffer == NULL )
729         return RC ( rcFS, rcFile, rcWriting, rcBuffer, rcNull );
730 
731     switch ( self -> vt -> v1 . maj )
732     {
733     case 1:
734         if ( self -> vt -> v1 . min >= 2 )
735             return ( * self -> vt -> v1 . timed_write ) ( self, pos, buffer, size, num_writ, tm );
736         if ( tm == NULL )
737             return ( * self -> vt -> v1 . write ) ( self, pos, buffer, size, num_writ );
738         break;
739     }
740 
741     return RC ( rcFS, rcFile, rcWriting, rcInterface, rcBadVersion );
742 }
743 
744 /* WriteAll
745  *  write from file until "size" bytes have been transferred
746  *  or until no further progress can be made
747  *
748  *  "pos" [ IN ] - starting position within file
749  *
750  *  "buffer" [ IN ] and "size" [ IN ] - data to be written
751  *
752  *  "num_writ" [ OUT, NULL OKAY ] - optional return parameter
753  *  giving number of bytes actually written
754  */
KFileWriteAll_v1(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ)755 LIB_EXPORT rc_t CC KFileWriteAll_v1 ( KFile_v1 *self, uint64_t pos,
756     const void *buffer, size_t size, size_t *num_writ )
757 {
758     rc_t rc;
759     const uint8_t *b;
760     size_t total, count;
761 
762     size_t ignore;
763     if ( num_writ == NULL )
764         num_writ = & ignore;
765 
766     * num_writ = 0;
767 
768     if ( self == NULL )
769         return RC ( rcFS, rcFile, rcWriting, rcSelf, rcNull );
770 
771     if ( ! self -> write_enabled )
772         return RC ( rcFS, rcFile, rcWriting, rcFile, rcNoPerm );
773 
774     if ( size == 0 )
775         return 0;
776     if ( buffer == NULL )
777         return RC ( rcFS, rcFile, rcWriting, rcBuffer, rcNull );
778 
779     switch ( self -> vt -> v1 . maj )
780     {
781     case 1:
782         count = 0;
783         rc = ( * self -> vt -> v1 . write ) ( self, pos, buffer, size, & count );
784         total = count;
785 
786         if ( rc == 0 && count != 0 && count < size )
787         {
788             if ( self -> vt -> v1 . min >= 2 )
789             {
790                 timeout_t no_block;
791                 TimeoutInit ( & no_block, 0 );
792 
793                 for ( b = buffer; total < size; total += count )
794                 {
795                     count = 0;
796                     rc = ( * self -> vt -> v1 . timed_write ) ( self, pos + total, b + total, size - total, & count, & no_block );
797                     if ( rc != 0 )
798                         break;
799                     if ( count == 0 )
800                         break;
801                 }
802             }
803             else
804             {
805                 for ( b = buffer; total < size; total += count )
806                 {
807                     count = 0;
808                     rc = ( * self -> vt -> v1 . write ) ( self, pos + total, b + total, size - total, & count );
809                     if ( rc != 0 )
810                         break;
811                     if ( count == 0 )
812                         break;
813                 }
814             }
815         }
816         break;
817     default:
818         return RC ( rcFS, rcFile, rcWriting, rcInterface, rcBadVersion );
819     }
820 
821     * num_writ = total;
822     if ( total == size )
823         return 0;
824     if ( rc == 0 )
825         return RC ( rcFS, rcFile, rcWriting, rcTransfer, rcIncomplete );
826     return rc;
827 }
828 
KFileTimedWriteAll_v1(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ,struct timeout_t * tm)829 LIB_EXPORT rc_t CC KFileTimedWriteAll_v1 ( KFile_v1 *self, uint64_t pos,
830     const void *buffer, size_t size, size_t *num_writ, struct timeout_t *tm )
831 {
832     rc_t rc;
833     const uint8_t *b;
834     size_t total, count;
835 
836     size_t ignore;
837     if ( num_writ == NULL )
838         num_writ = & ignore;
839 
840     * num_writ = 0;
841 
842     if ( self == NULL )
843         return RC ( rcFS, rcFile, rcWriting, rcSelf, rcNull );
844 
845     if ( ! self -> write_enabled )
846         return RC ( rcFS, rcFile, rcWriting, rcFile, rcNoPerm );
847 
848     if ( size == 0 )
849         return 0;
850     if ( buffer == NULL )
851         return RC ( rcFS, rcFile, rcWriting, rcBuffer, rcNull );
852 
853     switch ( self -> vt -> v1 . maj )
854     {
855     case 1:
856         if ( self -> vt -> v1 . min >= 2 )
857         {
858             for ( rc = 0, b = buffer, total = 0; total < size; total += count )
859             {
860                 count = 0;
861                 rc = ( * self -> vt -> v1 . timed_write ) ( self, pos + total, b + total, size - total, & count, tm );
862                 if ( rc != 0 )
863                     break;
864                 if ( count == 0 )
865                     break;
866             }
867             break;
868         }
869 
870         if ( tm == NULL )
871         {
872             for ( rc = 0, b = buffer, total = 0; total < size; total += count )
873             {
874                 count = 0;
875                 rc = ( * self -> vt -> v1 . write ) ( self, pos + total, b + total, size - total, & count );
876                 if ( rc != 0 )
877                     break;
878                 if ( count == 0 )
879                     break;
880             }
881             break;
882         }
883 
884         /* no break */
885 
886     default:
887         return RC ( rcFS, rcFile, rcWriting, rcInterface, rcBadVersion );
888     }
889 
890     * num_writ = total;
891     if ( total == size )
892         return 0;
893     if ( rc == 0 )
894         return RC ( rcFS, rcFile, rcWriting, rcTransfer, rcIncomplete );
895     return rc;
896 }
897 
898 /* WriteExactly
899  *  write from file until "size" bytes have been transferred
900  *
901  *  "pos" [ IN ] - starting position within file
902  *
903  *  "buffer" [ IN ] and "size" [ IN ] - data to be written
904  */
KFileWriteExactly_v1(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size)905 LIB_EXPORT rc_t CC KFileWriteExactly_v1 ( KFile_v1 *self, uint64_t pos,
906     const void *buffer, size_t size )
907 {
908     rc_t rc;
909     const uint8_t *b;
910     size_t total, count;
911 
912     if ( self == NULL )
913         return RC ( rcFS, rcFile, rcWriting, rcSelf, rcNull );
914 
915     if ( ! self -> write_enabled )
916         return RC ( rcFS, rcFile, rcWriting, rcFile, rcNoPerm );
917 
918     if ( size == 0 )
919         return 0;
920     if ( buffer == NULL )
921         return RC ( rcFS, rcFile, rcWriting, rcBuffer, rcNull );
922 
923     switch ( self -> vt -> v1 . maj )
924     {
925     case 1:
926         for ( b = buffer, total = 0; total < size; total += count )
927         {
928             count = 0;
929             rc = ( * self -> vt -> v1 . write ) ( self, pos + total, b + total, size - total, & count );
930             if ( rc != 0 )
931             {
932                 if ( GetRCObject ( rc ) != ( enum RCObject ) rcTimeout || GetRCState ( rc ) != rcExhausted )
933                     break;
934             }
935             else if ( count == 0 )
936             {
937                 rc = RC ( rcFS, rcFile, rcWriting, rcTransfer, rcIncomplete );
938                 break;
939             }
940         }
941         break;
942     default:
943         rc = RC ( rcFS, rcFile, rcWriting, rcInterface, rcBadVersion );
944     }
945 
946     return rc;
947 }
948 
KFileTimedWriteExactly_v1(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,struct timeout_t * tm)949 LIB_EXPORT rc_t CC KFileTimedWriteExactly_v1 ( KFile_v1 *self, uint64_t pos,
950     const void *buffer, size_t size, struct timeout_t *tm )
951 {
952     rc_t rc;
953     const uint8_t *b;
954     size_t total, count;
955 
956     if ( self == NULL )
957         return RC ( rcFS, rcFile, rcWriting, rcSelf, rcNull );
958 
959     if ( ! self -> write_enabled )
960         return RC ( rcFS, rcFile, rcWriting, rcFile, rcNoPerm );
961 
962     if ( size == 0 )
963         return 0;
964     if ( buffer == NULL )
965         return RC ( rcFS, rcFile, rcWriting, rcBuffer, rcNull );
966 
967     switch ( self -> vt -> v1 . maj )
968     {
969     case 1:
970         if ( self -> vt -> v1 . min >= 2 )
971         {
972             for ( b = buffer, total = 0; total < size; total += count )
973             {
974                 count = 0;
975                 rc = ( * self -> vt -> v1 . timed_write ) ( self, pos + total, b + total, size - total, & count, tm );
976                 if ( rc != 0 )
977                 {
978                     if ( tm != NULL )
979                         break;
980                     if ( GetRCObject ( rc ) != ( enum RCObject ) rcTimeout || GetRCState ( rc ) != rcExhausted )
981                         break;
982                 }
983                 else if ( count == 0 )
984                 {
985                     rc = RC ( rcFS, rcFile, rcWriting, rcTransfer, rcIncomplete );
986                     break;
987                 }
988             }
989             break;
990         }
991 
992         if ( tm == NULL )
993         {
994             for ( b = buffer, total = 0; total < size; total += count )
995             {
996                 count = 0;
997                 rc = ( * self -> vt -> v1 . write ) ( self, pos + total, b + total, size - total, & count );
998                 if ( rc != 0 )
999                 {
1000                     if ( GetRCObject ( rc ) != ( enum RCObject ) rcTimeout || GetRCState ( rc ) != rcExhausted )
1001                         break;
1002                 }
1003                 else if ( count == 0 )
1004                 {
1005                     rc = RC ( rcFS, rcFile, rcWriting, rcTransfer, rcIncomplete );
1006                     break;
1007                 }
1008             }
1009             break;
1010         }
1011 
1012         /* no break */
1013 
1014     default:
1015         rc = RC ( rcFS, rcFile, rcWriting, rcInterface, rcBadVersion );
1016     }
1017 
1018     return rc;
1019 }
1020 
1021 /* Init
1022  *  initialize a newly allocated file object
1023  */
KFileInit(KFile_v1 * self,const KFile_vt * vt,const char * classname,const char * fname,bool read_enabled,bool write_enabled)1024 LIB_EXPORT rc_t CC KFileInit ( KFile_v1 *self, const KFile_vt *vt,
1025     const char *classname, const char *fname,
1026     bool read_enabled, bool write_enabled )
1027 {
1028     if ( self == NULL )
1029         return RC ( rcFS, rcFile, rcConstructing, rcSelf, rcNull );
1030     if ( vt == NULL )
1031         return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1032     switch ( vt -> v1 . maj )
1033     {
1034     case 0:
1035         return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcInvalid );
1036 
1037     case 1:
1038         switch ( vt -> v1 . min )
1039         {
1040             /* ADD NEW MINOR VERSION CASES HERE */
1041         case 3:
1042 #if _DEBUGGING
1043             if ( vt -> v1 . timed_read_chunked == NULL ||
1044                  vt -> v1 . read_chunked == NULL )
1045                 return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1046 #endif
1047         case 2:
1048 #if _DEBUGGING
1049             if ( vt -> v1 . timed_write == NULL ||
1050                  vt -> v1 . timed_read == NULL )
1051                 return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1052 #endif
1053         case 1:
1054 #if _DEBUGGING
1055             if ( vt -> v1 . get_type == NULL )
1056                 return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1057 #endif
1058             /* no break */
1059         case 0:
1060 #if _DEBUGGING
1061         if ( vt -> v1 . write == NULL         ||
1062              vt -> v1 . read == NULL          ||
1063              vt -> v1 . set_size == NULL      ||
1064              vt -> v1 . get_size == NULL      ||
1065              vt -> v1 . random_access == NULL ||
1066              vt -> v1 . get_sysfile == NULL   ||
1067              vt -> v1 . destroy == NULL )
1068         return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1069 #endif
1070             break;
1071         default:
1072             return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcBadVersion );
1073         }
1074         break;
1075 
1076     default:
1077         return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcBadVersion );
1078     }
1079 
1080     self -> vt = vt;
1081     self -> dir = NULL;
1082     KRefcountInit ( & self -> refcount, 1, classname, "init", fname );
1083     self -> read_enabled = ( uint8_t ) ( read_enabled != 0 );
1084     self -> write_enabled = ( uint8_t ) ( write_enabled != 0 );
1085 
1086     return 0;
1087 }
1088 
1089 
1090 /*--------------------------------------------------------------------------
1091  *
1092  */
1093 
1094 
1095 #undef KFileRelease
KFileRelease(const KFile_v1 * self)1096 LIB_EXPORT rc_t CC KFileRelease ( const KFile_v1 *self )
1097 {
1098     return KFileRelease_v1 ( self );
1099 }
1100 
1101 #undef KFileRandomAccess
KFileRandomAccess(const KFile_v1 * self)1102 LIB_EXPORT rc_t CC KFileRandomAccess ( const KFile_v1 *self )
1103 {
1104     return KFileRandomAccess_v1 ( self );
1105 }
1106 
1107 #undef KFileType
KFileType(const KFile_v1 * self)1108 LIB_EXPORT uint32_t CC KFileType ( const KFile_v1 *self )
1109 {
1110     return KFileType_v1 ( self );
1111 }
1112 
1113 #undef KFileSize
KFileSize(const KFile_v1 * self,uint64_t * size)1114 LIB_EXPORT rc_t CC KFileSize ( const KFile_v1 *self, uint64_t *size )
1115 {
1116     return KFileSize_v1 ( self, size );
1117 }
1118 
1119 #undef KFileSetSize
KFileSetSize(KFile_v1 * self,uint64_t size)1120 LIB_EXPORT rc_t CC KFileSetSize ( KFile_v1 *self, uint64_t size )
1121 {
1122     return KFileSetSize_v1 ( self, size );
1123 }
1124 
1125 #undef KFileRead
KFileRead(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)1126 LIB_EXPORT rc_t CC KFileRead ( const KFile_v1 *self, uint64_t pos,
1127     void *buffer, size_t bsize, size_t *num_read )
1128 {
1129     return KFileRead_v1 ( self, pos, buffer, bsize, num_read );
1130 }
1131 
1132 #undef KFileTimedRead
KFileTimedRead(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read,struct timeout_t * tm)1133 LIB_EXPORT rc_t CC KFileTimedRead ( const KFile_v1 *self, uint64_t pos,
1134     void *buffer, size_t bsize, size_t *num_read, struct timeout_t *tm )
1135 {
1136     return KFileTimedRead_v1 ( self, pos, buffer, bsize, num_read, tm );
1137 }
1138 
1139 #undef KFileReadAll
KFileReadAll(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)1140 LIB_EXPORT rc_t CC KFileReadAll ( const KFile_v1 *self, uint64_t pos,
1141     void *buffer, size_t bsize, size_t *num_read )
1142 {
1143     return KFileReadAll_v1 ( self, pos, buffer, bsize, num_read );
1144 }
1145 
1146 #undef KFileTimedReadAll
KFileTimedReadAll(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read,struct timeout_t * tm)1147 LIB_EXPORT rc_t CC KFileTimedReadAll ( const KFile_v1 *self, uint64_t pos,
1148     void *buffer, size_t bsize, size_t *num_read, struct timeout_t *tm )
1149 {
1150     return KFileTimedReadAll_v1 ( self, pos, buffer, bsize, num_read, tm );
1151 }
1152 
1153 #undef KFileReadExactly
KFileReadExactly(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bytes)1154 LIB_EXPORT rc_t CC KFileReadExactly ( const KFile_v1 *self,
1155     uint64_t pos, void *buffer, size_t bytes )
1156 {
1157     return KFileReadExactly_v1 ( self, pos, buffer, bytes );
1158 }
1159 
1160 #undef KFileTimedReadExactly
KFileTimedReadExactly(const KFile_v1 * self,uint64_t pos,void * buffer,size_t bytes,struct timeout_t * tm)1161 LIB_EXPORT rc_t CC KFileTimedReadExactly ( const KFile_v1 *self,
1162     uint64_t pos, void *buffer, size_t bytes, struct timeout_t *tm )
1163 {
1164     return KFileTimedReadExactly_v1 ( self, pos, buffer, bytes, tm );
1165 }
1166 
1167 #undef KFileWrite
KFileWrite(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ)1168 LIB_EXPORT rc_t CC KFileWrite ( KFile_v1 *self, uint64_t pos,
1169     const void *buffer, size_t size, size_t *num_writ )
1170 {
1171     return KFileWrite_v1 ( self, pos, buffer, size, num_writ );
1172 }
1173 
1174 #undef KFileTimedWrite
KFileTimedWrite(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ,struct timeout_t * tm)1175 LIB_EXPORT rc_t CC KFileTimedWrite ( KFile_v1 *self, uint64_t pos,
1176     const void *buffer, size_t size, size_t *num_writ, struct timeout_t *tm )
1177 {
1178     return KFileTimedWrite_v1 ( self, pos, buffer, size, num_writ, tm );
1179 }
1180 
1181 #undef KFileWriteAll
KFileWriteAll(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ)1182 LIB_EXPORT rc_t CC KFileWriteAll ( KFile_v1 *self, uint64_t pos,
1183     const void *buffer, size_t size, size_t *num_writ )
1184 {
1185     return KFileWriteAll_v1 ( self, pos, buffer, size, num_writ );
1186 }
1187 
1188 #undef KFileTimedWriteAll
KFileTimedWriteAll(KFile_v1 * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ,struct timeout_t * tm)1189 LIB_EXPORT rc_t CC KFileTimedWriteAll ( KFile_v1 *self, uint64_t pos,
1190     const void *buffer, size_t size, size_t *num_writ, struct timeout_t *tm )
1191 {
1192     return KFileTimedWriteAll_v1 ( self, pos, buffer, size, num_writ, tm );
1193 }
1194 
1195 #if 0
1196 #undef KFileWriteExactly
1197 LIB_EXPORT rc_t CC KFileWriteExactly ( KFile_v1 *self,
1198     uint64_t pos, const void *buffer, size_t bytes )
1199 {
1200     return KFileWriteExactly_v1 ( self, pos, buffer, bytes );
1201 }
1202 
1203 #undef KFileTimedWriteExactly
1204 LIB_EXPORT rc_t CC KFileTimedWriteExactly ( KFile_v1 *self,
1205     uint64_t pos, const void *buffer, size_t bytes, struct timeout_t *tm )
1206 {
1207     return KFileTimedWriteExactly_v1 ( self, pos, buffer, bytes, tm );
1208 }
1209 #endif
1210 
1211 #undef KFileMakeStdIn
KFileMakeStdIn(const KFile_v1 ** std_in)1212 LIB_EXPORT rc_t CC KFileMakeStdIn ( const KFile_v1 **std_in )
1213 {
1214     return KFileMakeStdIn_v1 ( std_in );
1215 }
1216 
1217 #undef KFileMakeStdOut
KFileMakeStdOut(KFile_v1 ** std_out)1218 LIB_EXPORT rc_t CC KFileMakeStdOut ( KFile_v1 **std_out )
1219 {
1220     return KFileMakeStdOut_v1 ( std_out );
1221 }
1222 
1223 #undef KFileMakeStdErr
KFileMakeStdErr(KFile_v1 ** std_err)1224 LIB_EXPORT rc_t CC KFileMakeStdErr ( KFile_v1 **std_err )
1225 {
1226     return KFileMakeStdErr_v1 ( std_err );
1227 }
1228