revert between 56095 -> 55830 in arch
[AROS.git] / compiler / posixc / lseek.c
blob1c09fb3706d63bd0402a0a234e9ba3e950022539
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->privflags & _FCB_ISDIR)
75 errno = EISDIR;
76 return -1;
79 FLUSHONREADCHECK
81 switch (whence)
83 case SEEK_SET: whence = OFFSET_BEGINNING; break;
84 case SEEK_CUR: whence = OFFSET_CURRENT; break;
85 case SEEK_END: whence = OFFSET_END; break;
87 default:
88 errno = EINVAL;
89 return -1;
92 cnt = Seek (fdesc->fcb->handle, offset, whence);
94 if (cnt == -1)
96 if(IoErr() == ERROR_SEEK_ERROR)
98 LONG saved_error = IoErr();
99 /* Most likely we tried to seek behind EOF. POSIX lseek allows
100 that, and if anything is written at the end on the gap,
101 reads from the gap should return 0 unless some real data
102 is written there. Since implementing it would be rather
103 difficult, we simply extend the file by writing zeros
104 and hope for the best. */
105 LONG abs_cur_pos = Seek(fdesc->fcb->handle, 0, OFFSET_CURRENT);
106 if(abs_cur_pos == -1)
107 goto error;
108 LONG file_size = Seek(fdesc->fcb->handle, 0, OFFSET_END);
109 if(file_size == -1)
110 goto error;
111 /* Now compute how much we have to extend the file */
112 LONG abs_new_pos = 0;
113 switch(whence)
115 case OFFSET_BEGINNING: abs_new_pos = offset; break;
116 case OFFSET_CURRENT: abs_new_pos = abs_cur_pos + offset; break;
117 case OFFSET_END: abs_new_pos = file_size + offset; break;
119 if(abs_new_pos > abs_cur_pos)
121 ULONG bufsize = 4096;
122 APTR zeros = AllocMem(bufsize, MEMF_ANY | MEMF_CLEAR);
123 if(!zeros)
125 /* Restore previous position */
126 Seek(fdesc->fcb->handle, abs_cur_pos, OFFSET_BEGINNING);
127 errno = ENOMEM;
128 return -1;
131 LONG towrite = abs_new_pos - abs_cur_pos;
134 Write(fdesc->fcb->handle, zeros, MIN(towrite, bufsize));
135 towrite -= bufsize;
137 while(towrite > 0);
139 FreeMem(zeros, bufsize);
141 else
143 /* Hmm, that's strange. Looks like ERROR_SEEK_ERROR has
144 been caused by something else */
145 SetIoErr(saved_error);
146 goto error;
149 else
150 goto error;
153 return Seek(fdesc->fcb->handle, 0, OFFSET_CURRENT);
154 error:
155 errno = __stdc_ioerr2errno (IoErr ());
156 return (off_t) -1;
157 } /* lseek */