Use intern GENMF function.
[AROS.git] / compiler / posixc / __fdesc.c
blobe807483afec76ea84be543eca763bc4d22b551ed
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
5 File descriptors 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) openmode = MODE_NEWFILE;
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;
299 if (!(fh = Open ((char *)pathname, openmode)) )
301 ULONG ioerr = IoErr();
302 D(bug("__open: Open ioerr=%d\n", ioerr));
303 errno = __stdc_ioerr2errno(ioerr);
304 goto err;
307 /* Handle O_TRUNC */
308 if((flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)))
310 if(SetFileSize(fh, 0, OFFSET_BEGINNING) != 0)
312 ULONG ioerr = IoErr();
313 /* Ignore error if ACTION_SET_FILE_SIZE is not implemented */
314 if(ioerr != ERROR_NOT_IMPLEMENTED &&
315 ioerr != ERROR_ACTION_NOT_KNOWN)
317 D(bug("__open: SetFileSize ioerr=%d\n", ioerr));
318 errno = __stdc_ioerr2errno(ioerr);
319 goto err;
324 /* Handle O_APPEND */
325 if((flags & O_APPEND) && (flags & (O_RDWR | O_WRONLY)))
327 if(Seek(fh, 0, OFFSET_END) != 0) {
328 errno = __stdc_ioerr2errno(IoErr());
329 goto err;
334 success:
335 currdesc->fcb->handle = fh;
336 currdesc->fcb->flags = flags;
337 currdesc->fcb->opencount = 1;
339 __setfdesc(wanted_fd, currdesc);
341 D(bug("__open: exiting fd=%d\n", wanted_fd));
343 return wanted_fd;
345 err:
346 if (fib) FreeDosObject(DOS_FIB, fib);
347 FreeVec(cblock);
348 if (currdesc) __free_fdesc(currdesc);
349 if (fh && fh != lock) Close(fh);
350 if (lock) UnLock(lock);
352 D(bug("__open: exiting with error %d\n", errno ));
354 return -1;
357 fdesc *__alloc_fdesc(void)
359 struct PosixCIntBase *PosixCBase =
360 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
361 fdesc * desc;
363 desc = AllocPooled(PosixCBase->internalpool, sizeof(fdesc));
365 D(bug("Allocated fdesc %x from %x pool\n", desc, PosixCBase->internalpool));
367 return desc;
370 void __free_fdesc(fdesc *desc)
372 struct PosixCIntBase *PosixCBase =
373 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
375 D(bug("Freeing fdesc %x from %x pool\n", desc, PosixCBase->internalpool));
376 FreePooled(PosixCBase->internalpool, desc, sizeof(fdesc));
380 /* FIXME: perhaps this has to be handled in a different way... */
381 int __init_stdfiles(struct PosixCIntBase *PosixCBase)
383 struct Process *me;
384 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
385 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
386 BPTR infh, outfh;
387 int res = __getfdslot(2);
391 res == -1 ||
392 !(infcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
393 !(indesc = __alloc_fdesc()) ||
394 !(outfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
395 !(outdesc = __alloc_fdesc()) ||
396 !(errfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
397 !(errdesc = __alloc_fdesc())
400 FreeVec(infcb);
401 if(indesc)
402 __free_fdesc(indesc);
403 FreeVec(outfcb);
404 if(outdesc)
405 __free_fdesc(outdesc);
406 FreeVec(errfcb);
407 if(errdesc)
408 __free_fdesc(errdesc);
409 SetIoErr(ERROR_NO_FREE_STORE);
410 return 0;
413 me = (struct Process *)FindTask (NULL);
415 infh = Input();
416 infcb->handle = OpenFromLock(DupLockFromFH(infh));
417 infcb->flags = O_RDONLY;
418 infcb->opencount = 1;
419 /* Remove (remaining) command line args on first read */
420 infcb->privflags = _FCB_FLUSHONREAD;
421 /* Use original fh if it can't be duplicated */
422 if (infcb->handle == BNULL)
424 infcb->handle = infh;
425 infcb->privflags |= _FCB_DONTCLOSE_FH;
427 indesc->fcb = infcb;
428 indesc->fdflags = 0;
429 D(bug("[__init_stdfiles]Input(): %p, infcb->handle: %p\n",
430 BADDR(Input()), BADDR(infcb->handle)
433 outfh = Output();
434 outfcb->handle = OpenFromLock(DupLockFromFH(outfh));
435 outfcb->flags = O_WRONLY | O_APPEND;
436 outfcb->opencount = 1;
437 /* Use original fh if it can't be duplicated */
438 if (outfcb->handle == BNULL)
440 outfcb->handle = outfh;
441 outfcb->privflags |= _FCB_DONTCLOSE_FH;
443 outdesc->fcb = outfcb;
444 outdesc->fdflags = 0;
445 D(bug("[__init_stdfiles]Output(): %p, outfcb->handle: %p\n",
446 BADDR(Output()), BADDR(outfcb->handle)
449 /* Normally stderr is expected to be unbuffered for POSIX.
450 We only do this if we can duplicate the handle otherwise
451 we obey the buffering of the error stream as originally set.
453 if (me->pr_CES != BNULL)
455 errfcb->handle = OpenFromLock(DupLockFromFH(me->pr_CES));
456 if (errfcb->handle != BNULL)
457 SetVBuf(errfcb->handle, NULL, BUF_NONE, -1);
458 else /* File handle could not be duplicated; use original */
460 errfcb->handle = me->pr_CES;
461 errfcb->privflags |= _FCB_DONTCLOSE_FH;
464 else
466 errfcb->handle = OpenFromLock(DupLockFromFH(Output()));
467 if (errfcb->handle != BNULL)
468 SetVBuf((BPTR) errfcb->handle, NULL, BUF_NONE, -1);
469 else /* File handle could not be duplicated; use original */
471 errfcb->handle = outfcb->handle;
472 errfcb->privflags = _FCB_DONTCLOSE_FH;
475 errfcb->flags = O_WRONLY | O_APPEND;
476 errfcb->opencount = 1;
477 errdesc->fcb = errfcb;
478 errdesc->fdflags = 0;
479 D(bug("[__init_stdfiles]me->pr_CES: %p, errfcb->handle: %p\n",
480 BADDR(me->pr_CES), BADDR(errfcb->handle)
483 PosixCBase->fd_array[STDIN_FILENO] = indesc;
484 PosixCBase->fd_array[STDOUT_FILENO] = outdesc;
485 PosixCBase->fd_array[STDERR_FILENO] = errdesc;
487 return 1;
490 static int __copy_fdarray(fdesc **__src_fd_array, int fd_slots)
492 struct PosixCIntBase *PosixCBase =
493 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
494 int i;
496 for(i = fd_slots - 1; i >= 0; i--)
498 if(__src_fd_array[i])
500 if(__getfdslot(i) != i)
501 return 0;
503 if((PosixCBase->fd_array[i] = __alloc_fdesc()) == NULL)
504 return 0;
506 PosixCBase->fd_array[i]->fdflags = __src_fd_array[i]->fdflags;
507 PosixCBase->fd_array[i]->fcb = __src_fd_array[i]->fcb;
508 PosixCBase->fd_array[i]->fcb->opencount++;
512 return 1;
515 int __init_fd(struct PosixCIntBase *PosixCBase)
517 struct PosixCIntBase *pPosixCBase =
518 (struct PosixCIntBase *)__GM_GetBaseParent(PosixCBase);
520 D(bug("Found parent PosixCBase %p with flags 0x%x\n",
521 pPosixCBase, pPosixCBase ? pPosixCBase->flags : 0
524 if (pPosixCBase && (pPosixCBase->flags & (VFORK_PARENT | EXEC_PARENT)))
525 return __copy_fdarray(pPosixCBase->fd_array, pPosixCBase->fd_slots);
526 else
527 return __init_stdfiles(PosixCBase);
530 void __exit_fd(struct PosixCIntBase *PosixCBase)
532 int i = PosixCBase->fd_slots;
533 while (i)
535 if (PosixCBase->fd_array[--i])
536 close(i);
540 void __close_on_exec_fdescs(void)
542 struct PosixCIntBase *PosixCBase =
543 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
544 int i;
545 fdesc *fd;
547 for (i = PosixCBase->fd_slots - 1; i >= 0; i--)
549 if ((fd = __getfdesc(i)) != NULL)
551 D(bug("__close_fdesc_on_exec: checking fd %d\n", i));
552 if (fd->fdflags & FD_CLOEXEC)
554 D(bug("__close_fdesc_on_exec: closing fd %d\n", i));
555 close(i);
561 #include <stdio.h>
563 void __updatestdio(void)
565 struct PosixCIntBase *PosixCBase =
566 (struct PosixCIntBase *)__aros_getbase_PosixCBase();
567 struct Process *me;
568 fcb *fcb = NULL;
570 me = (struct Process *)FindTask(NULL);
572 fflush(((struct PosixCBase *)PosixCBase)->_stdin);
573 fflush(((struct PosixCBase *)PosixCBase)->_stdout);
574 fflush(((struct PosixCBase *)PosixCBase)->_stderr);
576 fcb = PosixCBase->fd_array[STDIN_FILENO]->fcb;
577 if (!(fcb->privflags & _FCB_DONTCLOSE_FH))
578 Close(fcb->handle);
579 else
580 fcb->privflags &= ~_FCB_DONTCLOSE_FH;
581 fcb->handle = OpenFromLock(DupLockFromFH(Input()));
583 fcb = PosixCBase->fd_array[STDOUT_FILENO]->fcb;
584 if (!(fcb->privflags & _FCB_DONTCLOSE_FH))
585 Close(fcb->handle);
586 else
587 fcb->privflags &= ~_FCB_DONTCLOSE_FH;
588 fcb->handle = OpenFromLock(DupLockFromFH(Output()));
590 fcb = PosixCBase->fd_array[STDERR_FILENO]->fcb;
591 if (!(fcb->privflags & _FCB_DONTCLOSE_FH))
592 Close(fcb->handle);
593 if (me->pr_CES != BNULL)
595 fcb->handle = OpenFromLock(DupLockFromFH(me->pr_CES));
596 fcb->privflags &= ~_FCB_DONTCLOSE_FH;
598 else
600 fcb->handle = PosixCBase->fd_array[STDOUT_FILENO]->fcb->handle;
601 fcb->privflags |= _FCB_DONTCLOSE_FH;
605 ADD2OPENLIB(__init_fd, 2);
606 ADD2CLOSELIB(__exit_fd, 2);