source: mainline/uspace/lib/c/generic/io/io.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 17.8 KB
Line 
1/*
2 * Copyright (c) 2005 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35#include <stdio.h>
36#include <assert.h>
37#include <str.h>
38#include <errno.h>
39#include <stdbool.h>
40#include <stdlib.h>
41#include <async.h>
42#include <io/kio.h>
43#include <vfs/vfs.h>
44#include <vfs/vfs_sess.h>
45#include <vfs/inbox.h>
46#include <ipc/loc.h>
47#include <adt/list.h>
48#include "../private/io.h"
49#include "../private/stdio.h"
50
51static void _ffillbuf(FILE *stream);
52static void _fflushbuf(FILE *stream);
53
54static FILE stdin_null = {
55 .fd = -1,
56 .pos = 0,
57 .error = true,
58 .eof = true,
59 .kio = false,
60 .sess = NULL,
61 .btype = _IONBF,
62 .buf = NULL,
63 .buf_size = 0,
64 .buf_head = NULL,
65 .buf_tail = NULL,
66 .buf_state = _bs_empty
67};
68
69static FILE stdout_kio = {
70 .fd = -1,
71 .pos = 0,
72 .error = false,
73 .eof = false,
74 .kio = true,
75 .sess = NULL,
76 .btype = _IOLBF,
77 .buf = NULL,
78 .buf_size = BUFSIZ,
79 .buf_head = NULL,
80 .buf_tail = NULL,
81 .buf_state = _bs_empty
82};
83
84static FILE stderr_kio = {
85 .fd = -1,
86 .pos = 0,
87 .error = false,
88 .eof = false,
89 .kio = true,
90 .sess = NULL,
91 .btype = _IONBF,
92 .buf = NULL,
93 .buf_size = 0,
94 .buf_head = NULL,
95 .buf_tail = NULL,
96 .buf_state = _bs_empty
97};
98
99FILE *stdin = NULL;
100FILE *stdout = NULL;
101FILE *stderr = NULL;
102
103static LIST_INITIALIZE(files);
104
105void __stdio_init(void)
106{
107 /* The first three standard file descriptors are assigned for compatibility.
108 * This will probably be removed later.
109 */
110 int infd = inbox_get("stdin");
111 if (infd >= 0) {
112 int stdinfd = -1;
113 (void) vfs_clone(infd, -1, false, &stdinfd);
114 assert(stdinfd == 0);
115 vfs_open(stdinfd, MODE_READ);
116 stdin = fdopen(stdinfd, "r");
117 } else {
118 stdin = &stdin_null;
119 list_append(&stdin->link, &files);
120 }
121
122 int outfd = inbox_get("stdout");
123 if (outfd >= 0) {
124 int stdoutfd = -1;
125 (void) vfs_clone(outfd, -1, false, &stdoutfd);
126 assert(stdoutfd <= 1);
127 while (stdoutfd < 1)
128 (void) vfs_clone(outfd, -1, false, &stdoutfd);
129 vfs_open(stdoutfd, MODE_APPEND);
130 stdout = fdopen(stdoutfd, "a");
131 } else {
132 stdout = &stdout_kio;
133 list_append(&stdout->link, &files);
134 }
135
136 int errfd = inbox_get("stderr");
137 if (errfd >= 0) {
138 int stderrfd = -1;
139 (void) vfs_clone(errfd, -1, false, &stderrfd);
140 assert(stderrfd <= 2);
141 while (stderrfd < 2)
142 (void) vfs_clone(errfd, -1, false, &stderrfd);
143 vfs_open(stderrfd, MODE_APPEND);
144 stderr = fdopen(stderrfd, "a");
145 } else {
146 stderr = &stderr_kio;
147 list_append(&stderr->link, &files);
148 }
149}
150
151void __stdio_done(void)
152{
153 while (!list_empty(&files)) {
154 FILE *file = list_get_instance(list_first(&files), FILE, link);
155 fclose(file);
156 }
157}
158
159static bool parse_mode(const char *fmode, int *mode, bool *create, bool *truncate)
160{
161 /* Parse mode except first character. */
162 const char *mp = fmode;
163 if (*mp++ == 0) {
164 errno = EINVAL;
165 return false;
166 }
167
168 if ((*mp == 'b') || (*mp == 't'))
169 mp++;
170
171 bool plus;
172 if (*mp == '+') {
173 mp++;
174 plus = true;
175 } else
176 plus = false;
177
178 if (*mp != 0) {
179 errno = EINVAL;
180 return false;
181 }
182
183 *create = false;
184 *truncate = false;
185
186 /* Parse first character of fmode and determine mode for vfs_open(). */
187 switch (fmode[0]) {
188 case 'r':
189 *mode = plus ? MODE_READ | MODE_WRITE : MODE_READ;
190 break;
191 case 'w':
192 *mode = plus ? MODE_READ | MODE_WRITE : MODE_WRITE;
193 *create = true;
194 if (!plus)
195 *truncate = true;
196 break;
197 case 'a':
198 /* TODO: a+ must read from beginning, append to the end. */
199 if (plus) {
200 errno = ENOTSUP;
201 return false;
202 }
203
204 *mode = MODE_APPEND | (plus ? MODE_READ | MODE_WRITE : MODE_WRITE);
205 *create = true;
206 break;
207 default:
208 errno = EINVAL;
209 return false;
210 }
211
212 return true;
213}
214
215/** Set stream buffer. */
216void setvbuf(FILE *stream, void *buf, int mode, size_t size)
217{
218 stream->btype = mode;
219 stream->buf = buf;
220 stream->buf_size = size;
221 stream->buf_head = stream->buf;
222 stream->buf_tail = stream->buf;
223 stream->buf_state = _bs_empty;
224}
225
226/** Set stream buffer.
227 *
228 * When @p buf is NULL, the stream is set as unbuffered, otherwise
229 * full buffering is enabled.
230 */
231void setbuf(FILE *stream, void *buf)
232{
233 if (buf == NULL) {
234 setvbuf(stream, NULL, _IONBF, BUFSIZ);
235 } else {
236 setvbuf(stream, buf, _IOFBF, BUFSIZ);
237 }
238}
239
240static void _setvbuf(FILE *stream)
241{
242 /* FIXME: Use more complex rules for setting buffering options. */
243
244 switch (stream->fd) {
245 case 1:
246 setvbuf(stream, NULL, _IOLBF, BUFSIZ);
247 break;
248 case 0:
249 case 2:
250 setvbuf(stream, NULL, _IONBF, 0);
251 break;
252 default:
253 setvbuf(stream, NULL, _IOFBF, BUFSIZ);
254 }
255}
256
257/** Allocate stream buffer. */
258static int _fallocbuf(FILE *stream)
259{
260 assert(stream->buf == NULL);
261
262 stream->buf = malloc(stream->buf_size);
263 if (stream->buf == NULL) {
264 errno = ENOMEM;
265 return EOF;
266 }
267
268 stream->buf_head = stream->buf;
269 stream->buf_tail = stream->buf;
270 return 0;
271}
272
273/** Open a stream.
274 *
275 * @param path Path of the file to open.
276 * @param mode Mode string, (r|w|a)[b|t][+].
277 *
278 */
279FILE *fopen(const char *path, const char *fmode)
280{
281 int mode;
282 bool create;
283 bool truncate;
284
285 if (!parse_mode(fmode, &mode, &create, &truncate))
286 return NULL;
287
288 /* Open file. */
289 FILE *stream = malloc(sizeof(FILE));
290 if (stream == NULL) {
291 errno = ENOMEM;
292 return NULL;
293 }
294
295 int flags = WALK_REGULAR;
296 if (create)
297 flags |= WALK_MAY_CREATE;
298 int file;
299 errno_t rc = vfs_lookup(path, flags, &file);
300 if (rc != EOK) {
301 errno = rc;
302 free(stream);
303 return NULL;
304 }
305
306 rc = vfs_open(file, mode);
307 if (rc != EOK) {
308 errno = rc;
309 vfs_put(file);
310 free(stream);
311 return NULL;
312 }
313
314 if (truncate) {
315 rc = vfs_resize(file, 0);
316 if (rc != EOK) {
317 errno = rc;
318 vfs_put(file);
319 free(stream);
320 return NULL;
321 }
322 }
323
324 stream->fd = file;
325 stream->pos = 0;
326 stream->error = false;
327 stream->eof = false;
328 stream->kio = false;
329 stream->sess = NULL;
330 stream->need_sync = false;
331 _setvbuf(stream);
332 stream->ungetc_chars = 0;
333
334 list_append(&stream->link, &files);
335
336 return stream;
337}
338
339FILE *fdopen(int fd, const char *mode)
340{
341 /* Open file. */
342 FILE *stream = malloc(sizeof(FILE));
343 if (stream == NULL) {
344 errno = ENOMEM;
345 return NULL;
346 }
347
348 stream->fd = fd;
349 stream->pos = 0;
350 stream->error = false;
351 stream->eof = false;
352 stream->kio = false;
353 stream->sess = NULL;
354 stream->need_sync = false;
355 _setvbuf(stream);
356 stream->ungetc_chars = 0;
357
358 list_append(&stream->link, &files);
359
360 return stream;
361}
362
363
364static int _fclose_nofree(FILE *stream)
365{
366 errno_t rc = 0;
367
368 fflush(stream);
369
370 if (stream->sess != NULL)
371 async_hangup(stream->sess);
372
373 if (stream->fd >= 0)
374 rc = vfs_put(stream->fd);
375
376 list_remove(&stream->link);
377
378 if (rc != EOK) {
379 errno = rc;
380 return EOF;
381 }
382
383 return 0;
384}
385
386int fclose(FILE *stream)
387{
388 int rc = _fclose_nofree(stream);
389
390 if ((stream != &stdin_null)
391 && (stream != &stdout_kio)
392 && (stream != &stderr_kio))
393 free(stream);
394
395 return rc;
396}
397
398FILE *freopen(const char *path, const char *mode, FILE *stream)
399{
400 FILE *nstr;
401
402 if (path == NULL) {
403 /* Changing mode is not supported */
404 return NULL;
405 }
406
407 (void) _fclose_nofree(stream);
408 nstr = fopen(path, mode);
409 if (nstr == NULL) {
410 free(stream);
411 return NULL;
412 }
413
414 list_remove(&nstr->link);
415 *stream = *nstr;
416 list_append(&stream->link, &files);
417
418 free(nstr);
419
420 return stream;
421}
422
423/** Read from a stream (unbuffered).
424 *
425 * @param buf Destination buffer.
426 * @param size Size of each record.
427 * @param nmemb Number of records to read.
428 * @param stream Pointer to the stream.
429 *
430 * @return Number of elements successfully read. On error this is less than
431 * nmemb, stream error indicator is set and errno is set.
432 */
433static size_t _fread(void *buf, size_t size, size_t nmemb, FILE *stream)
434{
435 errno_t rc;
436 size_t nread;
437
438 if (size == 0 || nmemb == 0)
439 return 0;
440
441 rc = vfs_read(stream->fd, &stream->pos, buf, size * nmemb, &nread);
442 if (rc != EOK) {
443 errno = rc;
444 stream->error = true;
445 } else if (nread == 0) {
446 stream->eof = true;
447 }
448
449 return (nread / size);
450}
451
452/** Write to a stream (unbuffered).
453 *
454 * @param buf Source buffer.
455 * @param size Size of each record.
456 * @param nmemb Number of records to write.
457 * @param stream Pointer to the stream.
458 *
459 * @return Number of elements successfully written. On error this is less than
460 * nmemb, stream error indicator is set and errno is set.
461 */
462static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
463{
464 errno_t rc;
465 size_t nwritten;
466
467 if (size == 0 || nmemb == 0)
468 return 0;
469
470 if (stream->kio) {
471 rc = kio_write(buf, size * nmemb, &nwritten);
472 if (rc != EOK) {
473 stream->error = true;
474 nwritten = 0;
475 }
476 } else {
477 rc = vfs_write(stream->fd, &stream->pos, buf, size * nmemb,
478 &nwritten);
479 if (rc != EOK) {
480 errno = rc;
481 stream->error = true;
482 }
483 }
484
485 if (nwritten > 0)
486 stream->need_sync = true;
487
488 return (nwritten / size);
489}
490
491/** Read some data in stream buffer.
492 *
493 * On error, stream error indicator is set and errno is set.
494 */
495static void _ffillbuf(FILE *stream)
496{
497 errno_t rc;
498 size_t nread;
499
500 stream->buf_head = stream->buf_tail = stream->buf;
501
502 rc = vfs_read(stream->fd, &stream->pos, stream->buf, stream->buf_size,
503 &nread);
504 if (rc != EOK) {
505 errno = rc;
506 stream->error = true;
507 return;
508 }
509
510 if (nread == 0) {
511 stream->eof = true;
512 return;
513 }
514
515 stream->buf_head += nread;
516 stream->buf_state = _bs_read;
517}
518
519/** Write out stream buffer, do not sync stream. */
520static void _fflushbuf(FILE *stream)
521{
522 size_t bytes_used;
523
524 if ((!stream->buf) || (stream->btype == _IONBF) || (stream->error))
525 return;
526
527 bytes_used = stream->buf_head - stream->buf_tail;
528
529 /* If buffer has prefetched read data, we need to seek back. */
530 if (bytes_used > 0 && stream->buf_state == _bs_read)
531 stream->pos -= bytes_used;
532
533 /* If buffer has unwritten data, we need to write them out. */
534 if (bytes_used > 0 && stream->buf_state == _bs_write) {
535 (void) _fwrite(stream->buf_tail, 1, bytes_used, stream);
536 /* On error stream error indicator and errno are set by _fwrite */
537 if (stream->error)
538 return;
539 }
540
541 stream->buf_head = stream->buf;
542 stream->buf_tail = stream->buf;
543 stream->buf_state = _bs_empty;
544}
545
546/** Read from a stream.
547 *
548 * @param dest Destination buffer.
549 * @param size Size of each record.
550 * @param nmemb Number of records to read.
551 * @param stream Pointer to the stream.
552 *
553 */
554size_t fread(void *dest, size_t size, size_t nmemb, FILE *stream)
555{
556 uint8_t *dp;
557 size_t bytes_left;
558 size_t now;
559 size_t data_avail;
560 size_t total_read;
561 size_t i;
562
563 if (size == 0 || nmemb == 0)
564 return 0;
565
566 bytes_left = size * nmemb;
567 total_read = 0;
568 dp = (uint8_t *) dest;
569
570 /* Bytes from ungetc() buffer */
571 while (stream->ungetc_chars > 0 && bytes_left > 0) {
572 *dp++ = stream->ungetc_buf[--stream->ungetc_chars];
573 ++total_read;
574 --bytes_left;
575 }
576
577 /* If not buffered stream, read in directly. */
578 if (stream->btype == _IONBF) {
579 total_read += _fread(dest, 1, bytes_left, stream);
580 return total_read / size;
581 }
582
583 /* Make sure no data is pending write. */
584 if (stream->buf_state == _bs_write)
585 _fflushbuf(stream);
586
587 /* Perform lazy allocation of stream buffer. */
588 if (stream->buf == NULL) {
589 if (_fallocbuf(stream) != 0)
590 return 0; /* Errno set by _fallocbuf(). */
591 }
592
593 while ((!stream->error) && (!stream->eof) && (bytes_left > 0)) {
594 if (stream->buf_head == stream->buf_tail)
595 _ffillbuf(stream);
596
597 if (stream->error || stream->eof) {
598 /* On error errno was set by _ffillbuf() */
599 break;
600 }
601
602 data_avail = stream->buf_head - stream->buf_tail;
603
604 if (bytes_left > data_avail)
605 now = data_avail;
606 else
607 now = bytes_left;
608
609 for (i = 0; i < now; i++) {
610 dp[i] = stream->buf_tail[i];
611 }
612
613 dp += now;
614 stream->buf_tail += now;
615 bytes_left -= now;
616 total_read += now;
617 }
618
619 return (total_read / size);
620}
621
622
623/** Write to a stream.
624 *
625 * @param buf Source buffer.
626 * @param size Size of each record.
627 * @param nmemb Number of records to write.
628 * @param stream Pointer to the stream.
629 *
630 */
631size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
632{
633 uint8_t *data;
634 size_t bytes_left;
635 size_t now;
636 size_t buf_free;
637 size_t total_written;
638 size_t i;
639 uint8_t b;
640 bool need_flush;
641
642 if (size == 0 || nmemb == 0)
643 return 0;
644
645 /* If not buffered stream, write out directly. */
646 if (stream->btype == _IONBF) {
647 now = _fwrite(buf, size, nmemb, stream);
648 fflush(stream);
649 return now;
650 }
651
652 /* Make sure buffer contains no prefetched data. */
653 if (stream->buf_state == _bs_read)
654 _fflushbuf(stream);
655
656 /* Perform lazy allocation of stream buffer. */
657 if (stream->buf == NULL) {
658 if (_fallocbuf(stream) != 0)
659 return 0; /* Errno set by _fallocbuf(). */
660 }
661
662 data = (uint8_t *) buf;
663 bytes_left = size * nmemb;
664 total_written = 0;
665 need_flush = false;
666
667 while ((!stream->error) && (bytes_left > 0)) {
668 buf_free = stream->buf_size - (stream->buf_head - stream->buf);
669 if (bytes_left > buf_free)
670 now = buf_free;
671 else
672 now = bytes_left;
673
674 for (i = 0; i < now; i++) {
675 b = data[i];
676 stream->buf_head[i] = b;
677
678 if ((b == '\n') && (stream->btype == _IOLBF))
679 need_flush = true;
680 }
681
682 data += now;
683 stream->buf_head += now;
684 buf_free -= now;
685 bytes_left -= now;
686 total_written += now;
687 stream->buf_state = _bs_write;
688
689 if (buf_free == 0) {
690 /* Only need to drain buffer. */
691 _fflushbuf(stream);
692 if (!stream->error)
693 need_flush = false;
694 }
695 }
696
697 if (need_flush)
698 fflush(stream);
699
700 return (total_written / size);
701}
702
703int fputc(wchar_t c, FILE *stream)
704{
705 char buf[STR_BOUNDS(1)];
706 size_t sz = 0;
707
708 if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
709 size_t wr = fwrite(buf, 1, sz, stream);
710
711 if (wr < sz)
712 return EOF;
713
714 return (int) c;
715 }
716
717 return EOF;
718}
719
720int putchar(wchar_t c)
721{
722 return fputc(c, stdout);
723}
724
725int fputs(const char *str, FILE *stream)
726{
727 (void) fwrite(str, str_size(str), 1, stream);
728 if (ferror(stream))
729 return EOF;
730 return 0;
731}
732
733int puts(const char *str)
734{
735 return fputs(str, stdout);
736}
737
738int fgetc(FILE *stream)
739{
740 char c;
741
742 /* This could be made faster by only flushing when needed. */
743 if (stdout)
744 fflush(stdout);
745 if (stderr)
746 fflush(stderr);
747
748 if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
749 return EOF;
750
751 return (int) c;
752}
753
754char *fgets(char *str, int size, FILE *stream)
755{
756 int c;
757 int idx;
758
759 idx = 0;
760 while (idx < size - 1) {
761 c = fgetc(stream);
762 if (c == EOF)
763 break;
764
765 str[idx++] = c;
766
767 if (c == '\n')
768 break;
769 }
770
771 if (ferror(stream))
772 return NULL;
773
774 if (idx == 0)
775 return NULL;
776
777 str[idx] = '\0';
778 return str;
779}
780
781int getchar(void)
782{
783 return fgetc(stdin);
784}
785
786int ungetc(int c, FILE *stream)
787{
788 if (c == EOF)
789 return EOF;
790
791 if (stream->ungetc_chars >= UNGETC_MAX)
792 return EOF;
793
794 stream->ungetc_buf[stream->ungetc_chars++] =
795 (uint8_t)c;
796
797 stream->eof = false;
798 return (uint8_t)c;
799}
800
801int fseek64(FILE *stream, off64_t offset, int whence)
802{
803 errno_t rc;
804
805 if (stream->error)
806 return -1;
807
808 _fflushbuf(stream);
809 if (stream->error) {
810 /* errno was set by _fflushbuf() */
811 return -1;
812 }
813
814 stream->ungetc_chars = 0;
815
816 vfs_stat_t st;
817 switch (whence) {
818 case SEEK_SET:
819 stream->pos = offset;
820 break;
821 case SEEK_CUR:
822 stream->pos += offset;
823 break;
824 case SEEK_END:
825 rc = vfs_stat(stream->fd, &st);
826 if (rc != EOK) {
827 errno = rc;
828 stream->error = true;
829 return -1;
830 }
831 stream->pos = st.size + offset;
832 break;
833 }
834
835 stream->eof = false;
836 return 0;
837}
838
839off64_t ftell64(FILE *stream)
840{
841 if (stream->error)
842 return EOF;
843
844 _fflushbuf(stream);
845 if (stream->error) {
846 /* errno was set by _fflushbuf() */
847 return EOF;
848 }
849
850 return stream->pos - stream->ungetc_chars;
851}
852
853int fseek(FILE *stream, long offset, int whence)
854{
855 return fseek64(stream, offset, whence);
856}
857
858long ftell(FILE *stream)
859{
860 off64_t off = ftell64(stream);
861
862 /* The native position is too large for the C99-ish interface. */
863 if (off > LONG_MAX)
864 return EOF;
865
866 return off;
867}
868
869void rewind(FILE *stream)
870{
871 (void) fseek(stream, 0, SEEK_SET);
872}
873
874int fflush(FILE *stream)
875{
876 if (stream->error)
877 return EOF;
878
879 _fflushbuf(stream);
880 if (stream->error) {
881 /* errno was set by _fflushbuf() */
882 return EOF;
883 }
884
885 if (stream->kio) {
886 kio_update();
887 return 0;
888 }
889
890 if ((stream->fd >= 0) && (stream->need_sync)) {
891 errno_t rc;
892
893 /**
894 * Better than syncing always, but probably still not the
895 * right thing to do.
896 */
897 stream->need_sync = false;
898 rc = vfs_sync(stream->fd);
899 if (rc != EOK) {
900 errno = rc;
901 return EOF;
902 }
903
904 return 0;
905 }
906
907 return 0;
908}
909
910int feof(FILE *stream)
911{
912 return stream->eof;
913}
914
915int ferror(FILE *stream)
916{
917 return stream->error;
918}
919
920void clearerr(FILE *stream)
921{
922 stream->eof = false;
923 stream->error = false;
924}
925
926int fileno(FILE *stream)
927{
928 if (stream->kio) {
929 errno = EBADF;
930 return EOF;
931 }
932
933 return stream->fd;
934}
935
936async_sess_t *vfs_fsession(FILE *stream, iface_t iface)
937{
938 if (stream->fd >= 0) {
939 if (stream->sess == NULL)
940 stream->sess = vfs_fd_session(stream->fd, iface);
941
942 return stream->sess;
943 }
944
945 return NULL;
946}
947
948errno_t vfs_fhandle(FILE *stream, int *handle)
949{
950 if (stream->fd >= 0) {
951 *handle = stream->fd;
952 return EOK;
953 }
954
955 return ENOENT;
956}
957
958/** @}
959 */
Note: See TracBrowser for help on using the repository browser.