compiler/clib: #error if not cpu specific implementation of setjmp(), longjmp(),...
[AROS.git] / compiler / clib / __fdesc.c
blobad6e7d949a342e82cae0cc781e103e8afb8087ad
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 void __getfdarray(APTR *arrayptr, int *slotsptr)
33 struct aroscbase *aroscbase = __GM_GetBase();
35 *arrayptr = aroscbase->acb_fd_array;
36 *slotsptr = aroscbase->acb_numslots;
39 void __setfdarray(APTR array, int slots)
41 struct aroscbase *aroscbase = __GM_GetBase();
42 aroscbase->acb_fd_array = array;
43 aroscbase->acb_numslots = slots;
46 void __setfdarraybase(struct aroscbase *aroscbase2)
48 struct aroscbase *aroscbase = __GM_GetBase();
50 aroscbase->acb_fd_array = aroscbase2->acb_fd_array;
51 aroscbase->acb_numslots = aroscbase2->acb_numslots;
54 int __getfdslots(void)
56 struct aroscbase *aroscbase = __GM_GetBase();
57 return aroscbase->acb_numslots;
60 fdesc *__getfdesc(register int fd)
62 struct aroscbase *aroscbase = __GM_GetBase();
63 return ((aroscbase->acb_numslots>fd) && (fd>=0))?aroscbase->acb_fd_array[fd]:NULL;
66 void __setfdesc(register int fd, fdesc *desc)
68 struct aroscbase *aroscbase = __GM_GetBase();
69 /* FIXME: Check if fd is in valid range... */
70 aroscbase->acb_fd_array[fd] = desc;
73 int __getfirstfd(register int startfd)
75 struct aroscbase *aroscbase = __GM_GetBase();
76 /* FIXME: Check if fd is in valid range... */
77 for (
79 startfd < aroscbase->acb_numslots && aroscbase->acb_fd_array[startfd];
80 startfd++
83 return startfd;
86 int __getfdslot(int wanted_fd)
88 struct aroscbase *aroscbase = __GM_GetBase();
89 if (wanted_fd>=aroscbase->acb_numslots)
91 void *tmp;
93 tmp = AllocPooled(aroscbase->acb_internalpool, (wanted_fd+1)*sizeof(fdesc *));
95 if (!tmp) return -1;
97 if (aroscbase->acb_fd_array)
99 size_t size = aroscbase->acb_numslots*sizeof(fdesc *);
100 CopyMem(aroscbase->acb_fd_array, tmp, size);
101 FreePooled(aroscbase->acb_internalpool, aroscbase->acb_fd_array, size);
104 aroscbase->acb_fd_array = tmp;
106 bzero(aroscbase->acb_fd_array + aroscbase->acb_numslots, (wanted_fd - aroscbase->acb_numslots + 1) * sizeof(fdesc *));
107 aroscbase->acb_numslots = wanted_fd+1;
109 else if (wanted_fd < 0)
111 errno = EINVAL;
112 return -1;
114 else if (aroscbase->acb_fd_array[wanted_fd])
116 close(wanted_fd);
119 return wanted_fd;
122 LONG __oflags2amode(int flags)
124 LONG openmode = -1;
126 /* filter out invalid modes */
127 switch (flags & (O_CREAT|O_TRUNC|O_EXCL))
129 case O_EXCL:
130 case O_EXCL|O_TRUNC:
131 return -1;
134 /* Sorted in 'trumping' order. Ie if
135 * O_WRITE is on, that overrides O_READ.
136 * Similarly, O_CREAT overrides O_WRITE.
138 if (flags & O_RDONLY) openmode = MODE_OLDFILE;
139 if (flags & O_WRONLY) openmode = MODE_OLDFILE;
140 if (flags & O_RDWR) openmode = MODE_OLDFILE;
141 if (flags & O_READ) openmode = MODE_OLDFILE;
142 if (flags & O_WRITE) openmode = MODE_READWRITE;
143 if (flags & O_CREAT) openmode = MODE_NEWFILE;
144 if (flags & O_APPEND) /* Handled later */;
145 if (flags & O_TRUNC) /* Handled later */;
146 if (flags & O_EXEC) /* Ignored */;
147 if (flags & O_NONBLOCK) /* Ignored */;
149 return openmode;
152 int __open(int wanted_fd, const char *pathname, int flags, int mode)
154 struct aroscbase *aroscbase = __GM_GetBase();
155 BPTR fh = BNULL, lock = BNULL;
156 fdesc *currdesc = NULL;
157 fcb *cblock = NULL;
158 struct FileInfoBlock *fib = NULL;
159 LONG openmode = __oflags2amode(flags);
161 if (aroscbase->acb_doupath && pathname[0] == '\0')
163 /* On *nix "" is not really a valid file name. */
164 errno = ENOENT;
165 return -1;
168 pathname = __path_u2a(pathname);
169 if (!pathname) return -1;
171 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd, pathname, flags, mode));
173 if (openmode == -1)
175 errno = EINVAL;
176 D(bug( "__open: exiting with error EINVAL\n"));
177 return -1;
180 cblock = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR);
181 if (!cblock) { D(bug("__open: no memory [1]\n")); goto err; }
182 currdesc = __alloc_fdesc();
183 if (!currdesc) { D(bug("__open: no memory [2]\n")); goto err; }
184 currdesc->fdflags = 0;
185 currdesc->fcb = cblock;
187 wanted_fd = __getfdslot(wanted_fd);
188 if (wanted_fd == -1) { D(bug("__open: no free fd\n")); goto err; }
190 lock = Lock((char *)pathname, SHARED_LOCK);
191 if (!lock)
193 if (IoErr() == ERROR_OBJECT_WRONG_TYPE)
196 Needed for sfs file system which reports this error number on a
197 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
199 errno = ENOTDIR;
200 goto err;
205 (IoErr() != ERROR_OBJECT_NOT_FOUND) ||
206 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
207 (IoErr() == ERROR_OBJECT_NOT_FOUND && !(flags & O_CREAT))
210 errno = __arosc_ioerr2errno(IoErr());
211 goto err;
214 else
216 /* If the file exists, but O_EXCL is set, then return an error */
217 if (flags & O_EXCL)
219 errno = EEXIST;
220 goto err;
223 fib = AllocDosObject(DOS_FIB, NULL);
224 if (!fib)
226 errno = __arosc_ioerr2errno(IoErr());
227 goto err;
230 if (!Examine(lock, fib))
233 The filesystem in which the file resides doesn't support
234 the EXAMINE action. It might be broken or might also not
235 be a filesystem at all. So let's assume the file is not a
236 diretory.
238 fib->fib_DirEntryType = 0;
241 /* FIXME: implement softlink handling */
243 /* Check if it's a directory or a softlink.
244 Softlinks are not handled yet, though */
245 if (fib->fib_DirEntryType > 0)
247 /* A directory cannot be opened for writing */
248 if (openmode != MODE_OLDFILE)
250 errno = EISDIR;
251 goto err;
254 fh = lock;
255 FreeDosObject(DOS_FIB, fib);
256 currdesc->fcb->isdir = 1;
258 goto success;
260 FreeDosObject(DOS_FIB, fib);
261 fib = NULL;
264 /* the file exists and it's not a directory or the file doesn't exist */
266 if (lock)
268 UnLock(lock);
269 lock = BNULL;
272 if (!(fh = Open ((char *)pathname, openmode)) )
274 ULONG ioerr = IoErr();
275 D(bug("__open: Open ioerr=%d\n", ioerr));
276 errno = __arosc_ioerr2errno(ioerr);
277 goto err;
280 /* Handle O_TRUNC */
281 if((flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)))
283 if(SetFileSize(fh, 0, OFFSET_BEGINNING) != 0)
285 ULONG ioerr = IoErr();
286 /* Ignore error if ACTION_SET_FILE_SIZE is not implemented */
287 if(ioerr != ERROR_NOT_IMPLEMENTED)
289 D(bug("__open: SetFileSize ioerr=%d\n", ioerr));
290 errno = __arosc_ioerr2errno(ioerr);
291 goto err;
296 /* Handle O_APPEND */
297 if((flags & O_APPEND) && (flags & (O_RDWR | O_WRONLY)))
299 if(Seek(fh, 0, OFFSET_END) != 0) {
300 errno = __arosc_ioerr2errno(IoErr());
301 goto err;
306 success:
307 currdesc->fcb->fh = fh;
308 currdesc->fcb->flags = flags;
309 currdesc->fcb->opencount = 1;
311 __setfdesc(wanted_fd, currdesc);
313 D(bug("__open: exiting fd=%d\n", wanted_fd));
315 return wanted_fd;
317 err:
318 if (fib) FreeDosObject(DOS_FIB, fib);
319 if (cblock) FreeVec(cblock);
320 if (currdesc) __free_fdesc(currdesc);
321 if (fh && fh != lock) Close(fh);
322 if (lock) UnLock(lock);
324 D(bug("__open: exiting with error %d\n", errno ));
326 return -1;
329 fdesc *__alloc_fdesc(void)
331 struct aroscbase *aroscbase = __GM_GetBase();
332 fdesc * desc;
334 desc = AllocPooled(aroscbase->acb_internalpool, sizeof(fdesc));
336 D(bug("Allocated fdesc %x from %x pool\n", desc, aroscbase->acb_internalpool));
338 return desc;
341 void __free_fdesc(fdesc *desc)
343 struct aroscbase *aroscbase = __GM_GetBase();
344 D(bug("Freeing fdesc %x from %x pool\n", desc, aroscbase->acb_internalpool));
345 FreePooled(aroscbase->acb_internalpool, desc, sizeof(fdesc));
349 struct __reg_fdarray {
350 struct MinNode node;
351 struct Task *task;
352 fdesc **fdarray;
353 int numslots;
356 /* Some local variables for register_init_fdarray */
357 static struct SignalSemaphore __fdsem;
358 static struct MinList __fdreglist;
360 int __init_vars(void)
362 InitSemaphore(&__fdsem);
363 NEWLIST(&__fdreglist);
365 return TRUE;
368 int __register_init_fdarray(struct aroscbase *base)
370 /* arosc privdata should not be used inside this function,
371 * this function is called before aroscbase is initialized
373 struct __reg_fdarray *regnode = AllocVec(sizeof(struct __reg_fdarray), MEMF_ANY|MEMF_CLEAR);
375 if (regnode == NULL)
376 return 0;
378 regnode->task = FindTask(NULL);
379 regnode->fdarray = base->acb_fd_array;
380 regnode->numslots = base->acb_numslots;
382 D(bug("Allocated regnode: %p, fdarray: %p, numslots: %d\n",
383 regnode, regnode->fdarray, regnode->numslots
386 ObtainSemaphore(&__fdsem);
387 AddHead((struct List *)&__fdreglist, (struct Node *)regnode);
388 ReleaseSemaphore(&__fdsem);
390 return 1;
393 /* FIXME: perhaps this has to be handled in a different way... */
394 int __init_stdfiles(struct aroscbase *aroscbase)
396 struct Process *me;
397 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
398 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
399 int res = __getfdslot(2);
403 res == -1 ||
404 !(infcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
405 !(indesc = __alloc_fdesc()) ||
406 !(outfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
407 !(outdesc = __alloc_fdesc()) ||
408 !(errfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
409 !(errdesc = __alloc_fdesc())
412 if(infcb)
413 FreeVec(infcb);
414 if(indesc)
415 __free_fdesc(indesc);
416 if(outfcb)
417 FreeVec(outfcb);
418 if(outdesc)
419 __free_fdesc(outdesc);
420 if(errfcb)
421 FreeVec(errfcb);
422 if(errdesc)
423 __free_fdesc(errdesc);
424 SetIoErr(ERROR_NO_FREE_STORE);
425 return 0;
428 indesc->fdflags = 0;
429 outdesc->fdflags = 0;
430 errdesc->fdflags = 0;
432 indesc->fcb = infcb;
433 outdesc->fcb = outfcb;
434 errdesc->fcb = errfcb;
436 me = (struct Process *)FindTask (NULL);
437 indesc->fcb->fh = Input();
438 outdesc->fcb->fh = Output();
439 errdesc->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
441 indesc->fcb->flags = O_RDONLY;
442 outdesc->fcb->flags = O_WRONLY | O_APPEND;
443 errdesc->fcb->flags = O_WRONLY | O_APPEND;
445 indesc->fcb->opencount = outdesc->fcb->opencount = errdesc->fcb->opencount = 1;
446 indesc->fcb->privflags = outdesc->fcb->privflags = errdesc->fcb->privflags = _FCB_DONTCLOSE_FH;
448 aroscbase->acb_fd_array[STDIN_FILENO] = indesc;
449 aroscbase->acb_fd_array[STDOUT_FILENO] = outdesc;
450 aroscbase->acb_fd_array[STDERR_FILENO] = errdesc;
452 return 1;
455 static int __copy_fdarray(fdesc **__src_fd_array, int numslots)
457 struct aroscbase *aroscbase = __GM_GetBase();
458 int i;
460 for(i = numslots - 1; i >= 0; i--)
462 if(__src_fd_array[i])
464 if(__getfdslot(i) != i)
465 return 0;
467 if((aroscbase->acb_fd_array[i] = __alloc_fdesc()) == NULL)
468 return 0;
470 aroscbase->acb_fd_array[i]->fdflags = __src_fd_array[i]->fdflags;
471 aroscbase->acb_fd_array[i]->fcb = __src_fd_array[i]->fcb;
472 aroscbase->acb_fd_array[i]->fcb->opencount++;
476 return 1;
479 int __init_fd(struct aroscbase *aroscbase)
481 struct __reg_fdarray *regnodeit, *regnode = NULL;
482 struct Task *self = FindTask(NULL);
484 ObtainSemaphore(&__fdsem);
485 ForeachNode(&__fdreglist, regnodeit)
487 if (regnodeit->task == self)
489 regnode = regnodeit;
491 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
492 regnode, regnode->fdarray, regnode->numslots
494 Remove((struct Node *)regnode);
495 break;
498 ReleaseSemaphore(&__fdsem);
500 if (regnode == NULL)
501 return __init_stdfiles(aroscbase);
502 else
504 int ok = __copy_fdarray(regnode->fdarray, regnode->numslots);
506 FreeVec(regnode);
508 return ok;
512 void __exit_fd(struct aroscbase *aroscbase)
514 int i = aroscbase->acb_numslots;
515 while (i)
517 if (aroscbase->acb_fd_array[--i])
518 close(i);
522 void __close_on_exec_fdescs(void)
524 struct aroscbase *aroscbase = __GM_GetBase();
526 int i;
527 fdesc *fd;
529 for (i = aroscbase->acb_numslots - 1; i >= 0; i--)
531 if ((fd = __getfdesc(i)) != NULL)
533 D(bug("__close_fdesc_on_exec: checking fd %d\n", i));
534 if (fd->fdflags & FD_CLOEXEC)
536 D(bug("__close_fdesc_on_exec: closing fd %d\n", i));
537 close(i);
543 #include <stdio.h>
545 void __updatestdio(void)
547 struct aroscbase *aroscbase = __GM_GetBase();
548 struct Process *me;
550 me = (struct Process *)FindTask(NULL);
552 fflush(stdin);
553 fflush(stdout);
554 fflush(stderr);
556 aroscbase->acb_fd_array[STDIN_FILENO]->fcb->fh = Input();
557 aroscbase->acb_fd_array[STDOUT_FILENO]->fcb->fh = Output();
558 aroscbase->acb_fd_array[STDERR_FILENO]->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
560 aroscbase->acb_fd_array[STDIN_FILENO]->fcb->privflags =
561 aroscbase->acb_fd_array[STDOUT_FILENO]->fcb->privflags =
562 aroscbase->acb_fd_array[STDERR_FILENO]->fcb->privflags = _FCB_DONTCLOSE_FH;
565 ADD2INIT(__init_vars, 0);
566 ADD2OPENLIB(__init_fd, 2);
567 ADD2CLOSELIB(__exit_fd, 2);