compiler/clib: Rename IoErr2errno() to __arosc_ioerr2errno(); function is now defined...
[AROS.git] / compiler / clib / __fdesc.c
blob486e934e5c2954687601022ae05ee4b5722b8c87
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 File descriptors handling internals.
6 */
8 #include "__arosc_privdata.h"
10 #include <string.h>
11 #include <fcntl.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <errno.h>
16 #define DEBUG 0
18 #include <proto/exec.h>
19 #include <proto/dos.h>
20 #include <exec/memory.h>
21 #include <exec/semaphores.h>
22 #include <dos/dos.h>
23 #include <aros/symbolsets.h>
24 #include <aros/debug.h>
25 #include "__fdesc.h"
26 #include "__upath.h"
28 static struct SignalSemaphore __fdsem;
29 static struct MinList __fdreglist;
31 int __getfdslots(void)
33 struct aroscbase *aroscbase = __GM_GetBase();
34 return aroscbase->acb_numslots;
37 fdesc *__getfdesc(register int fd)
39 struct aroscbase *aroscbase = __GM_GetBase();
40 return ((aroscbase->acb_numslots>fd) && (fd>=0))?aroscbase->acb_fd_array[fd]:NULL;
43 void __setfdesc(register int fd, fdesc *desc)
45 struct aroscbase *aroscbase = __GM_GetBase();
46 /* FIXME: Check if fd is in valid range... */
47 aroscbase->acb_fd_array[fd] = desc;
50 int __getfirstfd(register int startfd)
52 struct aroscbase *aroscbase = __GM_GetBase();
53 /* FIXME: Check if fd is in valid range... */
54 for (
56 startfd < aroscbase->acb_numslots && aroscbase->acb_fd_array[startfd];
57 startfd++
60 return startfd;
63 int __getfdslot(int wanted_fd)
65 struct aroscbase *aroscbase = __GM_GetBase();
66 if (wanted_fd>=aroscbase->acb_numslots)
68 void *tmp;
70 tmp = AllocPooled(aroscbase->acb_fd_mempool, (wanted_fd+1)*sizeof(fdesc *));
72 if (!tmp) return -1;
74 if (aroscbase->acb_fd_array)
76 size_t size = aroscbase->acb_numslots*sizeof(fdesc *);
77 CopyMem(aroscbase->acb_fd_array, tmp, size);
78 FreePooled(aroscbase->acb_fd_mempool, aroscbase->acb_fd_array, size);
81 aroscbase->acb_fd_array = tmp;
83 bzero(aroscbase->acb_fd_array + aroscbase->acb_numslots, (wanted_fd - aroscbase->acb_numslots + 1) * sizeof(fdesc *));
84 aroscbase->acb_numslots = wanted_fd+1;
86 else if (wanted_fd < 0)
88 errno = EINVAL;
89 return -1;
91 else if (aroscbase->acb_fd_array[wanted_fd])
93 close(wanted_fd);
96 return wanted_fd;
99 LONG __oflags2amode(int flags)
101 LONG openmode = -1;
103 /* filter out invalid modes */
104 switch (flags & (O_CREAT|O_TRUNC|O_EXCL))
106 case O_EXCL:
107 case O_EXCL|O_TRUNC:
108 return -1;
111 /* Sorted in 'trumping' order. Ie if
112 * O_WRITE is on, that overrides O_READ.
113 * Similarly, O_CREAT overrides O_WRITE.
115 if (flags & O_RDONLY) openmode = MODE_OLDFILE;
116 if (flags & O_WRONLY) openmode = MODE_OLDFILE;
117 if (flags & O_RDWR) openmode = MODE_OLDFILE;
118 if (flags & O_READ) openmode = MODE_OLDFILE;
119 if (flags & O_WRITE) openmode = MODE_READWRITE;
120 if (flags & O_CREAT) openmode = MODE_NEWFILE;
121 if (flags & O_APPEND) /* Handled later */;
122 if (flags & O_TRUNC) /* Handled later */;
123 if (flags & O_EXEC) /* Ignored */;
124 if (flags & O_NONBLOCK) /* Ignored */;
126 return openmode;
129 int __open(int wanted_fd, const char *pathname, int flags, int mode)
131 struct aroscbase *aroscbase = __GM_GetBase();
132 BPTR fh = BNULL, lock = BNULL;
133 fdesc *currdesc = NULL;
134 fcb *cblock = NULL;
135 struct FileInfoBlock *fib = NULL;
136 LONG openmode = __oflags2amode(flags);
138 if (aroscbase->acb_doupath && pathname[0] == '\0')
140 /* On *nix "" is not really a valid file name. */
141 errno = ENOENT;
142 return -1;
145 pathname = __path_u2a(pathname);
146 if (!pathname) return -1;
148 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd, pathname, flags, mode));
150 if (openmode == -1)
152 errno = EINVAL;
153 D(bug( "__open: exiting with error EINVAL\n"));
154 return -1;
157 cblock = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR);
158 if (!cblock) { D(bug("__open: no memory [1]\n")); goto err; }
159 currdesc = __alloc_fdesc();
160 if (!currdesc) { D(bug("__open: no memory [2]\n")); goto err; }
161 currdesc->fdflags = 0;
162 currdesc->fcb = cblock;
164 wanted_fd = __getfdslot(wanted_fd);
165 if (wanted_fd == -1) { D(bug("__open: no free fd\n")); goto err; }
167 lock = Lock((char *)pathname, SHARED_LOCK);
168 if (!lock)
170 if (IoErr() == ERROR_OBJECT_WRONG_TYPE)
173 Needed for sfs file system which reports this error number on a
174 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
176 errno = ENOTDIR;
177 goto err;
182 (IoErr() != ERROR_OBJECT_NOT_FOUND) ||
183 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
184 (IoErr() == ERROR_OBJECT_NOT_FOUND && !(flags & O_CREAT))
187 errno = __arosc_ioerr2errno(IoErr());
188 goto err;
191 else
193 /* If the file exists, but O_EXCL is set, then return an error */
194 if (flags & O_EXCL)
196 errno = EEXIST;
197 goto err;
200 fib = AllocDosObject(DOS_FIB, NULL);
201 if (!fib)
203 errno = __arosc_ioerr2errno(IoErr());
204 goto err;
207 if (!Examine(lock, fib))
210 The filesystem in which the file resides doesn't support
211 the EXAMINE action. It might be broken or might also not
212 be a filesystem at all. So let's assume the file is not a
213 diretory.
215 fib->fib_DirEntryType = 0;
218 /* FIXME: implement softlink handling */
220 /* Check if it's a directory or a softlink.
221 Softlinks are not handled yet, though */
222 if (fib->fib_DirEntryType > 0)
224 /* A directory cannot be opened for writing */
225 if (openmode != MODE_OLDFILE)
227 errno = EISDIR;
228 goto err;
231 fh = lock;
232 FreeDosObject(DOS_FIB, fib);
233 currdesc->fcb->isdir = 1;
235 goto success;
237 FreeDosObject(DOS_FIB, fib);
238 fib = NULL;
241 /* the file exists and it's not a directory or the file doesn't exist */
243 if (lock)
245 UnLock(lock);
246 lock = BNULL;
249 if (!(fh = Open ((char *)pathname, openmode)) )
251 ULONG ioerr = IoErr();
252 D(bug("__open: Open ioerr=%d\n", ioerr));
253 errno = __arosc_ioerr2errno(ioerr);
254 goto err;
257 /* Handle O_TRUNC */
258 if((flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)))
260 if(SetFileSize(fh, 0, OFFSET_BEGINNING) != 0)
262 ULONG ioerr = IoErr();
263 /* Ignore error if ACTION_SET_FILE_SIZE is not implemented */
264 if(ioerr != ERROR_NOT_IMPLEMENTED)
266 D(bug("__open: SetFileSize ioerr=%d\n", ioerr));
267 errno = __arosc_ioerr2errno(ioerr);
268 goto err;
273 /* Handle O_APPEND */
274 if((flags & O_APPEND) && (flags & (O_RDWR | O_WRONLY)))
276 if(Seek(fh, 0, OFFSET_END) != 0) {
277 errno = __arosc_ioerr2errno(IoErr());
278 goto err;
283 success:
284 currdesc->fcb->fh = fh;
285 currdesc->fcb->flags = flags;
286 currdesc->fcb->opencount = 1;
288 __setfdesc(wanted_fd, currdesc);
290 D(bug("__open: exiting fd=%d\n", wanted_fd));
292 return wanted_fd;
294 err:
295 if (fib) FreeDosObject(DOS_FIB, fib);
296 if (cblock) FreeVec(cblock);
297 if (currdesc) __free_fdesc(currdesc);
298 if (fh && fh != lock) Close(fh);
299 if (lock) UnLock(lock);
301 D(bug("__open: exiting with error %d\n", errno ));
303 return -1;
306 fdesc *__alloc_fdesc(void)
308 struct aroscbase *aroscbase = __GM_GetBase();
309 fdesc * desc;
311 desc = AllocPooled(aroscbase->acb_fd_mempool, sizeof(fdesc));
313 D(bug("Allocated fdesc %x from %x pool\n", desc, aroscbase->acb_fd_mempool));
315 return desc;
318 void __free_fdesc(fdesc *desc)
320 struct aroscbase *aroscbase = __GM_GetBase();
321 D(bug("Freeing fdesc %x from %x pool\n", desc, aroscbase->acb_fd_mempool));
322 FreePooled(aroscbase->acb_fd_mempool, desc, sizeof(fdesc));
326 struct __reg_fdarray {
327 struct MinNode node;
328 struct Task *task;
329 fdesc **fdarray;
330 int numslots;
333 /* Some local variables for register_init_fdarray */
334 static struct SignalSemaphore __fdsem;
335 static struct MinList __fdreglist;
337 int __init_vars(void)
339 InitSemaphore(&__fdsem);
340 NEWLIST(&__fdreglist);
342 return TRUE;
345 int __register_init_fdarray(struct aroscbase *base)
347 /* arosc privdata should not be used inside this function,
348 * this function is called before aroscbase is initialized
350 struct __reg_fdarray *regnode = AllocVec(sizeof(struct __reg_fdarray), MEMF_ANY|MEMF_CLEAR);
352 if (regnode == NULL)
353 return 0;
355 regnode->task = FindTask(NULL);
356 regnode->fdarray = base->acb_fd_array;
357 regnode->numslots = base->acb_numslots;
359 D(bug("Allocated regnode: %p, fdarray: %p, numslots: %d\n",
360 regnode, regnode->fdarray, regnode->numslots
363 ObtainSemaphore(&__fdsem);
364 AddHead((struct List *)&__fdreglist, (struct Node *)regnode);
365 ReleaseSemaphore(&__fdsem);
367 return 1;
370 /* FIXME: perhaps this has to be handled in a different way... */
371 int __init_stdfiles(struct aroscbase *aroscbase)
373 struct Process *me;
374 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
375 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
376 int res = __getfdslot(2);
380 res == -1 ||
381 !(infcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
382 !(indesc = __alloc_fdesc()) ||
383 !(outfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
384 !(outdesc = __alloc_fdesc()) ||
385 !(errfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
386 !(errdesc = __alloc_fdesc())
389 if(infcb)
390 FreeVec(infcb);
391 if(indesc)
392 __free_fdesc(indesc);
393 if(outfcb)
394 FreeVec(outfcb);
395 if(outdesc)
396 __free_fdesc(outdesc);
397 if(errfcb)
398 FreeVec(errfcb);
399 if(errdesc)
400 __free_fdesc(errdesc);
401 SetIoErr(ERROR_NO_FREE_STORE);
402 return 0;
405 indesc->fdflags = 0;
406 outdesc->fdflags = 0;
407 errdesc->fdflags = 0;
409 indesc->fcb = infcb;
410 outdesc->fcb = outfcb;
411 errdesc->fcb = errfcb;
413 me = (struct Process *)FindTask (NULL);
414 indesc->fcb->fh = Input();
415 outdesc->fcb->fh = Output();
416 errdesc->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
418 indesc->fcb->flags = O_RDONLY;
419 outdesc->fcb->flags = O_WRONLY | O_APPEND;
420 errdesc->fcb->flags = O_WRONLY | O_APPEND;
422 indesc->fcb->opencount = outdesc->fcb->opencount = errdesc->fcb->opencount = 1;
423 indesc->fcb->privflags = outdesc->fcb->privflags = errdesc->fcb->privflags = _FCB_DONTCLOSE_FH;
425 aroscbase->acb_fd_array[STDIN_FILENO] = indesc;
426 aroscbase->acb_fd_array[STDOUT_FILENO] = outdesc;
427 aroscbase->acb_fd_array[STDERR_FILENO] = errdesc;
429 return 1;
432 static int __copy_fdarray(fdesc **__src_fd_array, int numslots)
434 struct aroscbase *aroscbase = __GM_GetBase();
435 int i;
437 for(i = numslots - 1; i >= 0; i--)
439 if(__src_fd_array[i])
441 if(__getfdslot(i) != i)
442 return 0;
444 if((aroscbase->acb_fd_array[i] = __alloc_fdesc()) == NULL)
445 return 0;
447 aroscbase->acb_fd_array[i]->fdflags = __src_fd_array[i]->fdflags;
448 aroscbase->acb_fd_array[i]->fcb = __src_fd_array[i]->fcb;
449 aroscbase->acb_fd_array[i]->fcb->opencount++;
453 return 1;
456 int __init_fd(struct aroscbase *aroscbase)
458 struct __reg_fdarray *regnodeit, *regnode = NULL;
459 struct Task *self = FindTask(NULL);
461 aroscbase->acb_fd_mempool = CreatePool(MEMF_PUBLIC, 16*sizeof(fdesc), 16*sizeof(fdesc));
463 ObtainSemaphore(&__fdsem);
464 ForeachNode(&__fdreglist, regnodeit)
466 if (regnodeit->task == self)
468 regnode = regnodeit;
470 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
471 regnode, regnode->fdarray, regnode->numslots
473 Remove((struct Node *)regnode);
474 break;
477 ReleaseSemaphore(&__fdsem);
479 if (regnode == NULL)
480 return __init_stdfiles(aroscbase);
481 else
483 int ok = __copy_fdarray(regnode->fdarray, regnode->numslots);
485 FreeVec(regnode);
487 return ok;
491 void __exit_fd(struct aroscbase *aroscbase)
493 int i = aroscbase->acb_numslots;
494 while (i)
496 if (aroscbase->acb_fd_array[--i])
497 close(i);
499 DeletePool(aroscbase->acb_fd_mempool);
502 #include <stdio.h>
504 void __updatestdio(void)
506 struct aroscbase *aroscbase = __GM_GetBase();
507 struct Process *me;
509 me = (struct Process *)FindTask(NULL);
511 fflush(stdin);
512 fflush(stdout);
513 fflush(stderr);
515 aroscbase->acb_fd_array[STDIN_FILENO]->fcb->fh = Input();
516 aroscbase->acb_fd_array[STDOUT_FILENO]->fcb->fh = Output();
517 aroscbase->acb_fd_array[STDERR_FILENO]->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
519 aroscbase->acb_fd_array[STDIN_FILENO]->fcb->privflags =
520 aroscbase->acb_fd_array[STDOUT_FILENO]->fcb->privflags =
521 aroscbase->acb_fd_array[STDERR_FILENO]->fcb->privflags = _FCB_DONTCLOSE_FH;
524 ADD2INIT(__init_vars, 0);
525 ADD2OPENLIB(__init_fd, 2);
526 ADD2CLOSELIB(__exit_fd, 2);