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