clean up bcm bases and add primecell peripheral defines
[AROS.git] / compiler / clib / __fdesc.c
blobe9e33db3ed47771066b4cf92dfffe787950c847a
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 = __aros_getbase_aroscbase();
35 *arrayptr = aroscbase->acb_fd_array;
36 *slotsptr = aroscbase->acb_numslots;
39 void __setfdarray(APTR array, int slots)
41 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
42 aroscbase->acb_fd_array = array;
43 aroscbase->acb_numslots = slots;
46 void __setfdarraybase(struct aroscbase *aroscbase2)
48 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
50 aroscbase->acb_fd_array = aroscbase2->acb_fd_array;
51 aroscbase->acb_numslots = aroscbase2->acb_numslots;
54 int __getfdslots(void)
56 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
57 return aroscbase->acb_numslots;
60 fdesc *__getfdesc(register int fd)
62 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
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 = __aros_getbase_aroscbase();
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 = __aros_getbase_aroscbase();
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 = __aros_getbase_aroscbase();
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 memset(
107 aroscbase->acb_fd_array + aroscbase->acb_numslots,
109 (wanted_fd - aroscbase->acb_numslots + 1) * sizeof(fdesc *)
111 aroscbase->acb_numslots = wanted_fd+1;
113 else if (wanted_fd < 0)
115 errno = EINVAL;
116 return -1;
118 else if (aroscbase->acb_fd_array[wanted_fd])
120 close(wanted_fd);
123 return wanted_fd;
126 LONG __oflags2amode(int flags)
128 LONG openmode = -1;
130 /* filter out invalid modes */
131 switch (flags & (O_CREAT|O_TRUNC|O_EXCL))
133 case O_EXCL:
134 case O_EXCL|O_TRUNC:
135 return -1;
138 /* Sorted in 'trumping' order. Ie if
139 * O_WRITE is on, that overrides O_READ.
140 * Similarly, O_CREAT overrides O_WRITE.
142 if (flags & O_RDONLY) openmode = MODE_OLDFILE;
143 if (flags & O_WRONLY) openmode = MODE_OLDFILE;
144 if (flags & O_RDWR) openmode = MODE_OLDFILE;
145 if (flags & O_READ) openmode = MODE_OLDFILE;
146 if (flags & O_WRITE) openmode = MODE_READWRITE;
147 if (flags & O_CREAT) openmode = MODE_NEWFILE;
148 if (flags & O_APPEND) /* Handled later */;
149 if (flags & O_TRUNC) /* Handled later */;
150 if (flags & O_EXEC) /* Ignored */;
151 if (flags & O_NONBLOCK) /* Ignored */;
153 return openmode;
156 int __open(int wanted_fd, const char *pathname, int flags, int mode)
158 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
159 BPTR fh = BNULL, lock = BNULL;
160 fdesc *currdesc = NULL;
161 fcb *cblock = NULL;
162 struct FileInfoBlock *fib = NULL;
163 LONG openmode = __oflags2amode(flags);
165 if (aroscbase->acb_doupath && pathname[0] == '\0')
167 /* On *nix "" is not really a valid file name. */
168 errno = ENOENT;
169 return -1;
172 pathname = __path_u2a(pathname);
173 if (!pathname) return -1;
175 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd, pathname, flags, mode));
177 if (openmode == -1)
179 errno = EINVAL;
180 D(bug( "__open: exiting with error EINVAL\n"));
181 return -1;
184 cblock = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR);
185 if (!cblock) { D(bug("__open: no memory [1]\n")); goto err; }
186 currdesc = __alloc_fdesc();
187 if (!currdesc) { D(bug("__open: no memory [2]\n")); goto err; }
188 currdesc->fdflags = 0;
189 currdesc->fcb = cblock;
191 wanted_fd = __getfdslot(wanted_fd);
192 if (wanted_fd == -1) { D(bug("__open: no free fd\n")); goto err; }
194 lock = Lock((char *)pathname, SHARED_LOCK);
195 if (!lock)
197 if (IoErr() == ERROR_OBJECT_WRONG_TYPE)
200 Needed for sfs file system which reports this error number on a
201 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
203 errno = ENOTDIR;
204 goto err;
209 (IoErr() != ERROR_OBJECT_NOT_FOUND) ||
210 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
211 (IoErr() == ERROR_OBJECT_NOT_FOUND && !(flags & O_CREAT))
214 errno = __arosc_ioerr2errno(IoErr());
215 goto err;
218 else
220 /* If the file exists, but O_EXCL is set, then return an error */
221 if (flags & O_EXCL)
223 errno = EEXIST;
224 goto err;
227 fib = AllocDosObject(DOS_FIB, NULL);
228 if (!fib)
230 errno = __arosc_ioerr2errno(IoErr());
231 goto err;
234 if (!Examine(lock, fib))
237 The filesystem in which the file resides doesn't support
238 the EXAMINE action. It might be broken or might also not
239 be a filesystem at all. So let's assume the file is not a
240 diretory.
242 fib->fib_DirEntryType = 0;
245 /* FIXME: implement softlink handling */
247 /* Check if it's a directory or a softlink.
248 Softlinks are not handled yet, though */
249 if (fib->fib_DirEntryType > 0)
251 /* A directory cannot be opened for writing */
252 if (openmode != MODE_OLDFILE)
254 errno = EISDIR;
255 goto err;
258 fh = lock;
259 FreeDosObject(DOS_FIB, fib);
260 currdesc->fcb->isdir = 1;
262 goto success;
264 FreeDosObject(DOS_FIB, fib);
265 fib = NULL;
268 /* the file exists and it's not a directory or the file doesn't exist */
270 if (lock)
272 UnLock(lock);
273 lock = BNULL;
276 if (!(fh = Open ((char *)pathname, openmode)) )
278 ULONG ioerr = IoErr();
279 D(bug("__open: Open ioerr=%d\n", ioerr));
280 errno = __arosc_ioerr2errno(ioerr);
281 goto err;
284 /* Handle O_TRUNC */
285 if((flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)))
287 if(SetFileSize(fh, 0, OFFSET_BEGINNING) != 0)
289 ULONG ioerr = IoErr();
290 /* Ignore error if ACTION_SET_FILE_SIZE is not implemented */
291 if(ioerr != ERROR_NOT_IMPLEMENTED &&
292 ioerr != ERROR_ACTION_NOT_KNOWN)
294 D(bug("__open: SetFileSize ioerr=%d\n", ioerr));
295 errno = __arosc_ioerr2errno(ioerr);
296 goto err;
301 /* Handle O_APPEND */
302 if((flags & O_APPEND) && (flags & (O_RDWR | O_WRONLY)))
304 if(Seek(fh, 0, OFFSET_END) != 0) {
305 errno = __arosc_ioerr2errno(IoErr());
306 goto err;
311 success:
312 currdesc->fcb->fh = fh;
313 currdesc->fcb->flags = flags;
314 currdesc->fcb->opencount = 1;
316 __setfdesc(wanted_fd, currdesc);
318 D(bug("__open: exiting fd=%d\n", wanted_fd));
320 return wanted_fd;
322 err:
323 if (fib) FreeDosObject(DOS_FIB, fib);
324 if (cblock) FreeVec(cblock);
325 if (currdesc) __free_fdesc(currdesc);
326 if (fh && fh != lock) Close(fh);
327 if (lock) UnLock(lock);
329 D(bug("__open: exiting with error %d\n", errno ));
331 return -1;
334 fdesc *__alloc_fdesc(void)
336 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
337 fdesc * desc;
339 desc = AllocPooled(aroscbase->acb_internalpool, sizeof(fdesc));
341 D(bug("Allocated fdesc %x from %x pool\n", desc, aroscbase->acb_internalpool));
343 return desc;
346 void __free_fdesc(fdesc *desc)
348 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
349 D(bug("Freeing fdesc %x from %x pool\n", desc, aroscbase->acb_internalpool));
350 FreePooled(aroscbase->acb_internalpool, desc, sizeof(fdesc));
354 struct __reg_fdarray {
355 struct MinNode node;
356 struct Task *task;
357 fdesc **fdarray;
358 int numslots;
361 /* Some local variables for register_init_fdarray */
362 static struct SignalSemaphore __fdsem;
363 static struct MinList __fdreglist;
365 int __init_vars(struct ExecBase *SysBase)
367 InitSemaphore(&__fdsem);
368 NEWLIST(&__fdreglist);
370 return TRUE;
373 int __register_init_fdarray(struct aroscbase *base)
375 /* arosc privdata should not be used inside this function,
376 * this function is called before aroscbase is initialized
378 struct __reg_fdarray *regnode = AllocVec(sizeof(struct __reg_fdarray), MEMF_ANY|MEMF_CLEAR);
380 if (regnode == NULL)
381 return 0;
383 regnode->task = FindTask(NULL);
384 regnode->fdarray = base->acb_fd_array;
385 regnode->numslots = base->acb_numslots;
387 D(bug("Allocated regnode: %p, fdarray: %p, numslots: %d\n",
388 regnode, regnode->fdarray, regnode->numslots
391 ObtainSemaphore(&__fdsem);
392 AddHead((struct List *)&__fdreglist, (struct Node *)regnode);
393 ReleaseSemaphore(&__fdsem);
395 return 1;
398 /* FIXME: perhaps this has to be handled in a different way... */
399 int __init_stdfiles(struct aroscbase *aroscbase)
401 struct Process *me;
402 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
403 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
404 int res = __getfdslot(2);
408 res == -1 ||
409 !(infcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
410 !(indesc = __alloc_fdesc()) ||
411 !(outfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
412 !(outdesc = __alloc_fdesc()) ||
413 !(errfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
414 !(errdesc = __alloc_fdesc())
417 if(infcb)
418 FreeVec(infcb);
419 if(indesc)
420 __free_fdesc(indesc);
421 if(outfcb)
422 FreeVec(outfcb);
423 if(outdesc)
424 __free_fdesc(outdesc);
425 if(errfcb)
426 FreeVec(errfcb);
427 if(errdesc)
428 __free_fdesc(errdesc);
429 SetIoErr(ERROR_NO_FREE_STORE);
430 return 0;
433 indesc->fdflags = 0;
434 outdesc->fdflags = 0;
435 errdesc->fdflags = 0;
437 indesc->fcb = infcb;
438 outdesc->fcb = outfcb;
439 errdesc->fcb = errfcb;
441 me = (struct Process *)FindTask (NULL);
442 indesc->fcb->fh = Input();
443 outdesc->fcb->fh = Output();
444 errdesc->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
446 indesc->fcb->flags = O_RDONLY;
447 outdesc->fcb->flags = O_WRONLY | O_APPEND;
448 errdesc->fcb->flags = O_WRONLY | O_APPEND;
450 indesc->fcb->opencount = outdesc->fcb->opencount = errdesc->fcb->opencount = 1;
451 indesc->fcb->privflags = outdesc->fcb->privflags = errdesc->fcb->privflags = _FCB_DONTCLOSE_FH;
453 aroscbase->acb_fd_array[STDIN_FILENO] = indesc;
454 aroscbase->acb_fd_array[STDOUT_FILENO] = outdesc;
455 aroscbase->acb_fd_array[STDERR_FILENO] = errdesc;
457 return 1;
460 static int __copy_fdarray(fdesc **__src_fd_array, int numslots)
462 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
463 int i;
465 for(i = numslots - 1; i >= 0; i--)
467 if(__src_fd_array[i])
469 if(__getfdslot(i) != i)
470 return 0;
472 if((aroscbase->acb_fd_array[i] = __alloc_fdesc()) == NULL)
473 return 0;
475 aroscbase->acb_fd_array[i]->fdflags = __src_fd_array[i]->fdflags;
476 aroscbase->acb_fd_array[i]->fcb = __src_fd_array[i]->fcb;
477 aroscbase->acb_fd_array[i]->fcb->opencount++;
481 return 1;
484 int __init_fd(struct aroscbase *aroscbase)
486 struct __reg_fdarray *regnodeit, *regnode = NULL;
487 struct Task *self = FindTask(NULL);
489 ObtainSemaphore(&__fdsem);
490 ForeachNode(&__fdreglist, regnodeit)
492 if (regnodeit->task == self)
494 regnode = regnodeit;
496 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
497 regnode, regnode->fdarray, regnode->numslots
499 Remove((struct Node *)regnode);
500 break;
503 ReleaseSemaphore(&__fdsem);
505 if (regnode == NULL)
506 return __init_stdfiles(aroscbase);
507 else
509 int ok = __copy_fdarray(regnode->fdarray, regnode->numslots);
511 FreeVec(regnode);
513 return ok;
517 void __exit_fd(struct aroscbase *aroscbase)
519 int i = aroscbase->acb_numslots;
520 while (i)
522 if (aroscbase->acb_fd_array[--i])
523 close(i);
527 void __close_on_exec_fdescs(void)
529 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
531 int i;
532 fdesc *fd;
534 for (i = aroscbase->acb_numslots - 1; i >= 0; i--)
536 if ((fd = __getfdesc(i)) != NULL)
538 D(bug("__close_fdesc_on_exec: checking fd %d\n", i));
539 if (fd->fdflags & FD_CLOEXEC)
541 D(bug("__close_fdesc_on_exec: closing fd %d\n", i));
542 close(i);
548 #include <stdio.h>
550 void __updatestdio(void)
552 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
553 struct Process *me;
555 me = (struct Process *)FindTask(NULL);
557 fflush(stdin);
558 fflush(stdout);
559 fflush(stderr);
561 aroscbase->acb_fd_array[STDIN_FILENO]->fcb->fh = Input();
562 aroscbase->acb_fd_array[STDOUT_FILENO]->fcb->fh = Output();
563 aroscbase->acb_fd_array[STDERR_FILENO]->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
565 aroscbase->acb_fd_array[STDIN_FILENO]->fcb->privflags =
566 aroscbase->acb_fd_array[STDOUT_FILENO]->fcb->privflags =
567 aroscbase->acb_fd_array[STDERR_FILENO]->fcb->privflags = _FCB_DONTCLOSE_FH;
570 ADD2INIT(__init_vars, 0);
571 ADD2OPENLIB(__init_fd, 2);
572 ADD2CLOSELIB(__exit_fd, 2);