Fixes to typos in comments etc.
[AROS.git] / compiler / posixc / __fdesc.c
blob02a09da1a0142d1637d3e597b346677709cb76f8
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 File descriptor handling internals.
6 */
8 #include LC_LIBDEFS_FILE
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 <dos/stdio.h>
24 #include <aros/symbolsets.h>
25 #include <aros/debug.h>
26 #include "__fdesc.h"
27 #include "__upath.h"
29 /* TODO: Add locking to make filedesc usage thread safe
30 Using vfork()+exec*() filedescriptors may be shared between different
31 tasks. Only one DOS file handle is used between shared file descriptors.
32 DOS file handles are not thread safe so we should add it here to make it
33 thread safe.
34 Possible implementation should look carefully at performance impact.
37 void __getfdarray(APTR *arrayptr, int *slotsptr)
39 struct PosixCIntBase *PosixCBase =
40 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
42 *arrayptr = PosixCBase->fd_array;
43 *slotsptr = PosixCBase->fd_slots;
46 void __setfdarray(APTR array, int slots)
48 struct PosixCIntBase *PosixCBase =
49 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
51 PosixCBase->fd_array = array;
52 PosixCBase->fd_slots = slots;
55 void __setfdarraybase(struct PosixCIntBase *PosixCBase2)
57 struct PosixCIntBase *PosixCBase =
58 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
60 PosixCBase->fd_array = PosixCBase2->fd_array;
61 PosixCBase->fd_slots = PosixCBase2->fd_slots;
64 int __getfdslots(void)
66 struct PosixCIntBase *PosixCBase =
67 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
69 return PosixCBase->fd_slots;
72 fdesc *__getfdesc(register int fd)
74 struct PosixCIntBase *PosixCBase =
75 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
77 return ((PosixCBase->fd_slots>fd) && (fd>=0))?PosixCBase->fd_array[fd]:NULL;
80 void __setfdesc(register int fd, fdesc *desc)
82 struct PosixCIntBase *PosixCBase =
83 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
85 /* FIXME: Check if fd is in valid range... */
86 PosixCBase->fd_array[fd] = desc;
89 int __getfirstfd(register int startfd)
91 struct PosixCIntBase *PosixCBase =
92 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
94 /* FIXME: Check if fd is in valid range... */
95 for (
97 startfd < PosixCBase->fd_slots && PosixCBase->fd_array[startfd];
98 startfd++
101 return startfd;
104 int __getfdslot(int wanted_fd)
106 struct PosixCIntBase *PosixCBase =
107 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
109 if (wanted_fd>=PosixCBase->fd_slots)
111 void *tmp;
113 tmp = AllocPooled(PosixCBase->internalpool, (wanted_fd+1)*sizeof(fdesc *));
115 if (!tmp) return -1;
117 if (PosixCBase->fd_array)
119 size_t size = PosixCBase->fd_slots*sizeof(fdesc *);
120 CopyMem(PosixCBase->fd_array, tmp, size);
121 FreePooled(PosixCBase->internalpool, PosixCBase->fd_array, size);
124 PosixCBase->fd_array = tmp;
125 PosixCBase->fd_slots = wanted_fd+1;
127 else if (wanted_fd < 0)
129 errno = EINVAL;
130 return -1;
132 else if (PosixCBase->fd_array[wanted_fd])
134 close(wanted_fd);
137 return wanted_fd;
140 LONG __oflags2amode(int flags)
142 LONG openmode = -1;
144 /* filter out invalid modes */
145 switch (flags & (O_CREAT|O_TRUNC|O_EXCL))
147 case O_EXCL:
148 case O_EXCL|O_TRUNC:
149 return -1;
152 /* Sorted in 'trumping' order. Ie if
153 * O_WRITE is on, that overrides O_READ.
154 * Similarly, O_CREAT overrides O_WRITE.
156 if (flags & O_RDONLY) openmode = MODE_OLDFILE;
157 if (flags & O_WRONLY) openmode = MODE_OLDFILE;
158 if (flags & O_RDWR) openmode = MODE_OLDFILE;
159 if (flags & O_READ) openmode = MODE_OLDFILE;
160 if (flags & O_WRITE) openmode = MODE_READWRITE;
161 if (flags & O_CREAT) /* Handled later */;
162 if (flags & O_APPEND) /* Handled later */;
163 if (flags & O_TRUNC) /* Handled later */;
164 if (flags & O_EXEC) /* Ignored */;
165 if (flags & O_NONBLOCK) /* Ignored */;
167 return openmode;
170 int __open(int wanted_fd, const char *pathname, int flags, int mode)
172 struct PosixCIntBase *PosixCBase =
173 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
175 BPTR fh = BNULL, lock = BNULL;
176 fdesc *currdesc = NULL;
177 fcb *cblock = NULL;
178 struct FileInfoBlock *fib = NULL;
179 LONG openmode = __oflags2amode(flags);
181 if (PosixCBase->doupath && pathname[0] == '\0')
183 /* On *nix "" is not really a valid file name. */
184 errno = ENOENT;
185 return -1;
188 pathname = __path_u2a(pathname);
189 if (!pathname) return -1;
191 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd, pathname, flags, mode));
193 if (openmode == -1)
195 errno = EINVAL;
196 D(bug( "__open: exiting with error EINVAL\n"));
197 return -1;
200 cblock = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR);
201 if (!cblock) { D(bug("__open: no memory [1]\n")); goto err; }
202 currdesc = __alloc_fdesc();
203 if (!currdesc) { D(bug("__open: no memory [2]\n")); goto err; }
204 currdesc->fdflags = 0;
205 currdesc->fcb = cblock;
207 wanted_fd = __getfdslot(wanted_fd);
208 if (wanted_fd == -1) { D(bug("__open: no free fd\n")); goto err; }
211 * In case of file system, test existance of file. Non-file system handlers (i.e CON:)
212 * support opening a file while not supporting locking.
214 if(IsFileSystem(pathname) == DOSTRUE)
216 lock = Lock((char *)pathname, SHARED_LOCK);
217 if (!lock)
219 if (IoErr() == ERROR_OBJECT_WRONG_TYPE)
222 Needed for sfs file system which reports this error number on a
223 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
225 errno = ENOTDIR;
226 goto err;
231 (IoErr() != ERROR_OBJECT_NOT_FOUND) ||
232 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
233 (IoErr() == ERROR_OBJECT_NOT_FOUND && !(flags & O_CREAT))
236 errno = __stdc_ioerr2errno(IoErr());
237 goto err;
240 else
242 /* If the file exists, but O_EXCL is set, then return an error */
243 if (flags & O_EXCL)
245 errno = EEXIST;
246 goto err;
249 fib = AllocDosObject(DOS_FIB, NULL);
250 if (!fib)
252 errno = __stdc_ioerr2errno(IoErr());
253 goto err;
256 if (!Examine(lock, fib))
259 The filesystem in which the file resides doesn't support
260 the EXAMINE action. It might be broken or might also not
261 be a filesystem at all. So let's assume the file is not a
262 diretory.
264 fib->fib_DirEntryType = 0;
267 /* FIXME: implement softlink handling */
269 /* Check if it's a directory or a softlink.
270 Softlinks are not handled yet, though */
271 if (fib->fib_DirEntryType > 0)
273 /* A directory cannot be opened for writing */
274 if (openmode != MODE_OLDFILE)
276 errno = EISDIR;
277 goto err;
280 fh = lock;
281 FreeDosObject(DOS_FIB, fib);
282 currdesc->fcb->privflags |= _FCB_ISDIR;
284 goto success;
286 FreeDosObject(DOS_FIB, fib);
287 fib = NULL;
291 /* the file exists and it's not a directory or the file doesn't exist */
293 if (lock)
295 UnLock(lock);
296 lock = BNULL;
298 else
300 /* Handle O_CREAT (creates the file only if it does not exist) */
301 if (flags & O_CREAT)
303 BPTR tmp = Open((char *)pathname, MODE_NEWFILE);
304 if (tmp != BNULL) Close(tmp);
305 /* File is closed as O_CREAT does not define access
306 * mode. This is handled by R/W modes.
311 if (!(fh = Open ((char *)pathname, openmode)) )
313 ULONG ioerr = IoErr();
314 D(bug("__open: Open ioerr=%d\n", ioerr));
315 errno = __stdc_ioerr2errno(ioerr);
316 goto err;
319 /* Allow opening NIL: (/dev/null) regardless of additional flags/modes */
320 if (!strcasecmp(pathname, "NIL:"))
321 goto success;
323 /* Handle O_TRUNC */
324 if((flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)))
326 if(SetFileSize(fh, 0, OFFSET_BEGINNING) != 0)
328 ULONG ioerr = IoErr();
329 /* Ignore error if ACTION_SET_FILE_SIZE is not implemented */
330 if(ioerr != ERROR_NOT_IMPLEMENTED &&
331 ioerr != ERROR_ACTION_NOT_KNOWN)
333 D(bug("__open: SetFileSize ioerr=%d\n", ioerr));
334 errno = __stdc_ioerr2errno(ioerr);
335 goto err;
340 /* Handle O_APPEND */
341 if((flags & O_APPEND) && (flags & (O_RDWR | O_WRONLY)))
343 if(Seek(fh, 0, OFFSET_END) != 0) {
344 errno = __stdc_ioerr2errno(IoErr());
345 goto err;
350 success:
351 currdesc->fcb->handle = fh;
352 currdesc->fcb->flags = flags;
353 currdesc->fcb->opencount = 1;
355 __setfdesc(wanted_fd, currdesc);
357 D(bug("__open: exiting fd=%d\n", wanted_fd));
359 return wanted_fd;
361 err:
362 if (fib) FreeDosObject(DOS_FIB, fib);
363 FreeVec(cblock);
364 if (currdesc) __free_fdesc(currdesc);
365 if (fh && fh != lock) Close(fh);
366 if (lock) UnLock(lock);
368 D(bug("__open: exiting with error %d\n", errno ));
370 return -1;
373 fdesc *__alloc_fdesc(void)
375 struct PosixCIntBase *PosixCBase =
376 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
377 fdesc * desc;
379 desc = AllocPooled(PosixCBase->internalpool, sizeof(fdesc));
381 D(bug("Allocated fdesc %x from %x pool\n", desc, PosixCBase->internalpool));
383 return desc;
386 void __free_fdesc(fdesc *desc)
388 struct PosixCIntBase *PosixCBase =
389 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
391 D(bug("Freeing fdesc %x from %x pool\n", desc, PosixCBase->internalpool));
392 FreePooled(PosixCBase->internalpool, desc, sizeof(fdesc));
396 /* FIXME: perhaps this has to be handled in a different way... */
397 int __init_stdfiles(struct PosixCIntBase *PosixCBase)
399 struct Process *me;
400 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
401 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
402 BPTR infh, outfh;
403 int res = __getfdslot(2);
407 res == -1 ||
408 !(infcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
409 !(indesc = __alloc_fdesc()) ||
410 !(outfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
411 !(outdesc = __alloc_fdesc()) ||
412 !(errfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
413 !(errdesc = __alloc_fdesc())
416 FreeVec(infcb);
417 if(indesc)
418 __free_fdesc(indesc);
419 FreeVec(outfcb);
420 if(outdesc)
421 __free_fdesc(outdesc);
422 FreeVec(errfcb);
423 if(errdesc)
424 __free_fdesc(errdesc);
425 SetIoErr(ERROR_NO_FREE_STORE);
426 return 0;
429 me = (struct Process *)FindTask (NULL);
431 infh = Input();
432 infcb->handle = OpenFromLock(DupLockFromFH(infh));
433 infcb->flags = O_RDONLY;
434 infcb->opencount = 1;
435 /* Remove (remaining) command line args on first read */
436 infcb->privflags = _FCB_FLUSHONREAD;
437 /* Use original fh if it can't be duplicated */
438 if (infcb->handle == BNULL)
440 infcb->handle = infh;
441 infcb->privflags |= _FCB_DONTCLOSE_FH;
443 indesc->fcb = infcb;
444 indesc->fdflags = 0;
445 D(bug("[__init_stdfiles]Input(): %p, infcb->handle: %p\n",
446 BADDR(Input()), BADDR(infcb->handle)
449 outfh = Output();
450 outfcb->handle = OpenFromLock(DupLockFromFH(outfh));
451 outfcb->flags = O_WRONLY | O_APPEND;
452 outfcb->opencount = 1;
453 /* Use original fh if it can't be duplicated */
454 if (outfcb->handle == BNULL)
456 outfcb->handle = outfh;
457 outfcb->privflags |= _FCB_DONTCLOSE_FH;
459 outdesc->fcb = outfcb;
460 outdesc->fdflags = 0;
461 D(bug("[__init_stdfiles]Output(): %p, outfcb->handle: %p\n",
462 BADDR(Output()), BADDR(outfcb->handle)
465 /* Normally stderr is expected to be unbuffered for POSIX.
466 We only do this if we can duplicate the handle otherwise
467 we obey the buffering of the error stream as originally set.
469 if (me->pr_CES != BNULL)
471 errfcb->handle = OpenFromLock(DupLockFromFH(me->pr_CES));
472 if (errfcb->handle != BNULL)
473 SetVBuf(errfcb->handle, NULL, BUF_NONE, -1);
474 else /* File handle could not be duplicated; use original */
476 errfcb->handle = me->pr_CES;
477 errfcb->privflags |= _FCB_DONTCLOSE_FH;
480 else
482 errfcb->handle = OpenFromLock(DupLockFromFH(Output()));
483 if (errfcb->handle != BNULL)
484 SetVBuf((BPTR) errfcb->handle, NULL, BUF_NONE, -1);
485 else /* File handle could not be duplicated; use original */
487 errfcb->handle = outfcb->handle;
488 errfcb->privflags = _FCB_DONTCLOSE_FH;
491 errfcb->flags = O_WRONLY | O_APPEND;
492 errfcb->opencount = 1;
493 errdesc->fcb = errfcb;
494 errdesc->fdflags = 0;
495 D(bug("[__init_stdfiles]me->pr_CES: %p, errfcb->handle: %p\n",
496 BADDR(me->pr_CES), BADDR(errfcb->handle)
499 PosixCBase->fd_array[STDIN_FILENO] = indesc;
500 PosixCBase->fd_array[STDOUT_FILENO] = outdesc;
501 PosixCBase->fd_array[STDERR_FILENO] = errdesc;
503 return 1;
506 static int __copy_fdarray(fdesc **__src_fd_array, int fd_slots)
508 struct PosixCIntBase *PosixCBase =
509 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
510 int i;
512 for(i = fd_slots - 1; i >= 0; i--)
514 if(__src_fd_array[i])
516 if(__getfdslot(i) != i)
517 return 0;
519 if((PosixCBase->fd_array[i] = __alloc_fdesc()) == NULL)
520 return 0;
522 PosixCBase->fd_array[i]->fdflags = __src_fd_array[i]->fdflags;
523 PosixCBase->fd_array[i]->fcb = __src_fd_array[i]->fcb;
524 PosixCBase->fd_array[i]->fcb->opencount++;
528 return 1;
531 int __init_fd(struct PosixCIntBase *PosixCBase)
533 struct PosixCIntBase *pPosixCBase =
534 (struct PosixCIntBase *)__GM_GetBaseParent(PosixCBase);
536 D(bug("Found parent PosixCBase %p with flags 0x%x\n",
537 pPosixCBase, pPosixCBase ? pPosixCBase->flags : 0
540 if (pPosixCBase && (pPosixCBase->flags & (VFORK_PARENT | EXEC_PARENT)))
541 return __copy_fdarray(pPosixCBase->fd_array, pPosixCBase->fd_slots);
542 else
543 return __init_stdfiles(PosixCBase);
546 void __exit_fd(struct PosixCIntBase *PosixCBase)
548 int i = PosixCBase->fd_slots;
549 while (i)
551 if (PosixCBase->fd_array[--i])
552 close(i);
556 void __close_on_exec_fdescs(void)
558 struct PosixCIntBase *PosixCBase =
559 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
560 int i;
561 fdesc *fd;
563 for (i = PosixCBase->fd_slots - 1; i >= 0; i--)
565 if ((fd = __getfdesc(i)) != NULL)
567 D(bug("__close_fdesc_on_exec: checking fd %d\n", i));
568 if (fd->fdflags & FD_CLOEXEC)
570 D(bug("__close_fdesc_on_exec: closing fd %d\n", i));
571 close(i);
577 #include <stdio.h>
579 void __updatestdio(void)
581 struct PosixCIntBase *PosixCBase =
582 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
583 struct Process *me;
584 fcb *fcb = NULL;
586 me = (struct Process *)FindTask(NULL);
588 fflush(((struct PosixCBase *)PosixCBase)->_stdin);
589 fflush(((struct PosixCBase *)PosixCBase)->_stdout);
590 fflush(((struct PosixCBase *)PosixCBase)->_stderr);
592 fcb = PosixCBase->fd_array[STDIN_FILENO]->fcb;
593 if (!(fcb->privflags & _FCB_DONTCLOSE_FH))
594 Close(fcb->handle);
595 else
596 fcb->privflags &= ~_FCB_DONTCLOSE_FH;
597 fcb->handle = OpenFromLock(DupLockFromFH(Input()));
599 fcb = PosixCBase->fd_array[STDOUT_FILENO]->fcb;
600 if (!(fcb->privflags & _FCB_DONTCLOSE_FH))
601 Close(fcb->handle);
602 else
603 fcb->privflags &= ~_FCB_DONTCLOSE_FH;
604 fcb->handle = OpenFromLock(DupLockFromFH(Output()));
606 fcb = PosixCBase->fd_array[STDERR_FILENO]->fcb;
607 if (!(fcb->privflags & _FCB_DONTCLOSE_FH))
608 Close(fcb->handle);
609 if (me->pr_CES != BNULL)
611 fcb->handle = OpenFromLock(DupLockFromFH(me->pr_CES));
612 fcb->privflags &= ~_FCB_DONTCLOSE_FH;
614 else
616 fcb->handle = PosixCBase->fd_array[STDOUT_FILENO]->fcb->handle;
617 fcb->privflags |= _FCB_DONTCLOSE_FH;
621 ADD2OPENLIB(__init_fd, 2);
622 ADD2CLOSELIB(__exit_fd, 2);