Added missing properties.
[AROS.git] / compiler / clib / lseek.c
blob807bb6076f36f68dbdb778d16a28aa61b1cc848b
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 Reposition read/write file offset.
6 */
7 #include <errno.h>
8 #include <dos/dos.h>
9 #include <proto/dos.h>
10 #include <exec/exec.h>
11 #include <proto/exec.h>
12 #include <clib/macros.h>
13 #include "__fdesc.h"
15 /*****************************************************************************
17 NAME */
18 #include <unistd.h>
20 off_t lseek (
22 /* SYNOPSIS */
23 int filedes,
24 off_t offset,
25 int whence)
27 /* FUNCTION
28 Reposition read/write file offset
30 INPUTS
31 filedef - the filedescriptor being modified
32 offset, whence -
33 How to modify the current position. whence
34 can be SEEK_SET, then offset is the absolute position
35 in the file (0 is the first byte), SEEK_CUR then the
36 position will change by offset (ie. -5 means to move
37 5 bytes to the beginning of the file) or SEEK_END.
38 SEEK_END means that the offset is relative to the
39 end of the file (-1 is the last byte and 0 is
40 the EOF).
42 RESULT
43 The new position on success and -1 on error. If an error occurred, the global
44 variable errno is set.
46 NOTES
48 EXAMPLE
50 BUGS
51 File is extended with zeros if desired position is beyond the end of
52 file.
54 Since it's not possible to use Seek() for directories, this
55 implementation fails with EISDIR for directory file descriptors.
57 SEE ALSO
58 fopen(), fwrite()
60 INTERNALS
62 ******************************************************************************/
64 int cnt;
65 fdesc *fdesc = __getfdesc(filedes);
67 if (!fdesc)
69 errno = EBADF;
70 return -1;
73 if(fdesc->fcb->isdir)
75 errno = EISDIR;
76 return -1;
79 switch (whence)
81 case SEEK_SET: whence = OFFSET_BEGINNING; break;
82 case SEEK_CUR: whence = OFFSET_CURRENT; break;
83 case SEEK_END: whence = OFFSET_END; break;
85 default:
86 errno = EINVAL;
87 return -1;
90 cnt = Seek ((BPTR)fdesc->fcb->fh, offset, whence);
92 if (cnt == -1)
94 if(IoErr() == ERROR_SEEK_ERROR)
96 LONG saved_error = IoErr();
97 /* Most likely we tried to seek behind EOF. POSIX lseek allows
98 that, and if anything is written at the end on the gap,
99 reads from the gap should return 0 unless some real data
100 is written there. Since implementing it would be rather
101 difficult, we simply extend the file by writing zeros
102 and hope for the best. */
103 LONG abs_cur_pos = Seek(fdesc->fcb->fh, 0, OFFSET_CURRENT);
104 if(abs_cur_pos == -1)
105 goto error;
106 LONG file_size = Seek(fdesc->fcb->fh, 0, OFFSET_END);
107 if(file_size == -1)
108 goto error;
109 /* Now compute how much we have to extend the file */
110 LONG abs_new_pos = 0;
111 switch(whence)
113 case OFFSET_BEGINNING: abs_new_pos = offset; break;
114 case OFFSET_CURRENT: abs_new_pos = abs_cur_pos + offset; break;
115 case OFFSET_END: abs_new_pos = file_size + offset; break;
117 if(abs_new_pos > abs_cur_pos)
119 ULONG bufsize = 4096;
120 APTR zeros = AllocMem(bufsize, MEMF_ANY | MEMF_CLEAR);
121 if(!zeros)
123 /* Restore previous position */
124 Seek(fdesc->fcb->fh, abs_cur_pos, OFFSET_BEGINNING);
125 errno = ENOMEM;
126 return -1;
129 LONG towrite = abs_new_pos - abs_cur_pos;
132 Write(fdesc->fcb->fh, zeros, MIN(towrite, bufsize));
133 towrite -= bufsize;
135 while(towrite > 0);
137 FreeMem(zeros, bufsize);
139 else
141 /* Hmm, that's strange. Looks like ERROR_SEEK_ERROR has
142 been caused by something else */
143 SetIoErr(saved_error);
144 goto error;
147 else
148 goto error;
151 return Seek((BPTR)fdesc->fcb->fh, 0, OFFSET_CURRENT);
152 error:
153 errno = __arosc_ioerr2errno (IoErr ());
154 return (off_t) -1;
155 } /* lseek */