2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
5 File descriptor handling internals.
8 #include LC_LIBDEFS_FILE
18 #include <proto/exec.h>
19 #include <proto/dos.h>
20 #include <exec/memory.h>
21 #include <exec/semaphores.h>
23 #include <dos/stdio.h>
24 #include <aros/symbolsets.h>
25 #include <aros/debug.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
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... */
97 startfd
< PosixCBase
->fd_slots
&& PosixCBase
->fd_array
[startfd
];
104 int __getfdslot(int wanted_fd
)
106 struct PosixCIntBase
*PosixCBase
=
107 (struct PosixCIntBase
*)__aros_getbase_PosixCBase();
109 if (wanted_fd
>=PosixCBase
->fd_slots
)
113 tmp
= AllocPooled(PosixCBase
->internalpool
, (wanted_fd
+1)*sizeof(fdesc
*));
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)
132 else if (PosixCBase
->fd_array
[wanted_fd
])
140 LONG
__oflags2amode(int flags
)
144 /* filter out invalid modes */
145 switch (flags
& (O_CREAT
|O_TRUNC
|O_EXCL
))
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 */;
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
;
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. */
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
));
196 D(bug( "__open: bad mode, exiting with error EINVAL\n"));
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
);
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.
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());
242 /* If the file exists, but O_EXCL is set, then return an error */
249 fib
= AllocDosObject(DOS_FIB
, NULL
);
252 errno
= __stdc_ioerr2errno(IoErr());
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
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
)
281 FreeDosObject(DOS_FIB
, fib
);
282 currdesc
->fcb
->privflags
|= _FCB_ISDIR
;
286 FreeDosObject(DOS_FIB
, fib
);
291 /* the file exists and it's not a directory or the file doesn't exist */
300 /* Handle O_CREAT (creates the file only if it does not exist) */
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
);
319 /* Allow opening NIL: (/dev/null) regardless of additional flags/modes */
320 if (!strcasecmp(pathname
, "NIL:"))
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
);
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());
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
));
362 if (fib
) FreeDosObject(DOS_FIB
, fib
);
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
));
373 fdesc
*__alloc_fdesc(void)
375 struct PosixCIntBase
*PosixCBase
=
376 (struct PosixCIntBase
*)__aros_getbase_PosixCBase();
379 desc
= AllocPooled(PosixCBase
->internalpool
, sizeof(fdesc
));
381 D(bug("Allocated fdesc %x from %x pool\n", desc
, PosixCBase
->internalpool
));
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
));
395 static void stderrlogic(struct Process
*me
, fcb
*fcb
)
397 if ((fcb
->handle
!= BNULL
) && !(fcb
->privflags
& _FCB_DONTCLOSE_FH
))
399 if (me
->pr_CES
!= BNULL
)
401 fcb
->handle
= me
->pr_CES
;
402 fcb
->privflags
|= _FCB_DONTCLOSE_FH
;
406 fcb
->handle
= Open("NIL:", MODE_OLDFILE
);
407 fcb
->privflags
&= ~_FCB_DONTCLOSE_FH
;
409 /* stderr is expected to be unbuffered for POSIX. */
410 SetVBuf(fcb
->handle
, NULL
, BUF_NONE
, -1);
413 /* FIXME: perhaps this has to be handled in a different way... */
414 int __init_stdfiles(struct PosixCIntBase
*PosixCBase
)
417 fcb
*infcb
= NULL
, *outfcb
= NULL
, *errfcb
= NULL
;
418 fdesc
*indesc
=NULL
, *outdesc
=NULL
, *errdesc
=NULL
;
419 int res
= __getfdslot(2);
424 !(infcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
425 !(indesc
= __alloc_fdesc()) ||
426 !(outfcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
427 !(outdesc
= __alloc_fdesc()) ||
428 !(errfcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
429 !(errdesc
= __alloc_fdesc())
434 __free_fdesc(indesc
);
437 __free_fdesc(outdesc
);
440 __free_fdesc(errdesc
);
441 SetIoErr(ERROR_NO_FREE_STORE
);
445 me
= (struct Process
*)FindTask (NULL
);
447 infcb
->handle
= Input();
448 infcb
->flags
= O_RDONLY
;
449 infcb
->opencount
= 1;
450 /* Remove (remaining) command line args on first read */
451 infcb
->privflags
= _FCB_FLUSHONREAD
;
452 infcb
->privflags
|= _FCB_DONTCLOSE_FH
;
455 D(bug("[__init_stdfiles]Input(): %p, infcb->handle: %p\n",
456 BADDR(Input()), BADDR(infcb
->handle
)
459 outfcb
->handle
= Output();
460 outfcb
->flags
= O_WRONLY
| O_APPEND
;
461 outfcb
->opencount
= 1;
462 outfcb
->privflags
|= _FCB_DONTCLOSE_FH
;
463 outdesc
->fcb
= outfcb
;
464 outdesc
->fdflags
= 0;
465 D(bug("[__init_stdfiles]Output(): %p, outfcb->handle: %p\n",
466 BADDR(Output()), BADDR(outfcb
->handle
)
469 errfcb
->privflags
= 0;
470 stderrlogic(me
, errfcb
);
471 errfcb
->flags
= O_WRONLY
| O_APPEND
;
472 errfcb
->opencount
= 1;
473 errdesc
->fcb
= errfcb
;
474 errdesc
->fdflags
= 0;
475 D(bug("[__init_stdfiles]me->pr_CES: %p, errfcb->handle: %p\n",
476 BADDR(me
->pr_CES
), BADDR(errfcb
->handle
)
479 PosixCBase
->fd_array
[STDIN_FILENO
] = indesc
;
480 PosixCBase
->fd_array
[STDOUT_FILENO
] = outdesc
;
481 PosixCBase
->fd_array
[STDERR_FILENO
] = errdesc
;
486 static int __copy_fdarray(fdesc
**__src_fd_array
, int fd_slots
)
488 struct PosixCIntBase
*PosixCBase
=
489 (struct PosixCIntBase
*)__aros_getbase_PosixCBase();
492 for(i
= fd_slots
- 1; i
>= 0; i
--)
494 if(__src_fd_array
[i
])
496 if(__getfdslot(i
) != i
)
499 if((PosixCBase
->fd_array
[i
] = __alloc_fdesc()) == NULL
)
502 PosixCBase
->fd_array
[i
]->fdflags
= __src_fd_array
[i
]->fdflags
;
503 PosixCBase
->fd_array
[i
]->fcb
= __src_fd_array
[i
]->fcb
;
504 PosixCBase
->fd_array
[i
]->fcb
->opencount
++;
511 int __init_fd(struct PosixCIntBase
*PosixCBase
)
513 struct PosixCIntBase
*pPosixCBase
=
514 (struct PosixCIntBase
*)__GM_GetBaseParent(PosixCBase
);
516 D(bug("Found parent PosixCBase %p with flags 0x%x\n",
517 pPosixCBase
, pPosixCBase
? pPosixCBase
->flags
: 0
520 if (pPosixCBase
&& (pPosixCBase
->flags
& (VFORK_PARENT
| EXEC_PARENT
)))
522 /* VFORK_PARENT use case - child manipulates file descriptors prior to calling exec* */
523 int res
= __copy_fdarray(pPosixCBase
->fd_array
, pPosixCBase
->fd_slots
);
525 if (pPosixCBase
->flags
& EXEC_PARENT
)
526 /* EXEC_PARENT called through RunCommand which injected parameters to Input() */
527 PosixCBase
->fd_array
[STDIN_FILENO
]->fcb
->privflags
|= _FCB_FLUSHONREAD
;
532 return __init_stdfiles(PosixCBase
);
535 void __exit_fd(struct PosixCIntBase
*PosixCBase
)
537 int i
= PosixCBase
->fd_slots
;
540 if (PosixCBase
->fd_array
[--i
])
545 void __close_on_exec_fdescs(void)
547 struct PosixCIntBase
*PosixCBase
=
548 (struct PosixCIntBase
*)__aros_getbase_PosixCBase();
552 for (i
= PosixCBase
->fd_slots
- 1; i
>= 0; i
--)
554 if ((fd
= __getfdesc(i
)) != NULL
)
556 D(bug("__close_fdesc_on_exec: checking fd %d\n", i
));
557 if (fd
->fdflags
& FD_CLOEXEC
)
559 D(bug("__close_fdesc_on_exec: closing fd %d\n", i
));
568 void __updatestdio(void)
570 struct PosixCIntBase
*PosixCBase
=
571 (struct PosixCIntBase
*)__aros_getbase_PosixCBase();
575 me
= (struct Process
*)FindTask(NULL
);
577 fflush(((struct PosixCBase
*)PosixCBase
)->_stdin
);
578 fflush(((struct PosixCBase
*)PosixCBase
)->_stdout
);
579 fflush(((struct PosixCBase
*)PosixCBase
)->_stderr
);
581 fcb
= PosixCBase
->fd_array
[STDIN_FILENO
]->fcb
;
582 fcb
->handle
= Input();
584 fcb
= PosixCBase
->fd_array
[STDOUT_FILENO
]->fcb
;
585 fcb
->handle
= Output();
587 fcb
= PosixCBase
->fd_array
[STDERR_FILENO
]->fcb
;
588 stderrlogic(me
, fcb
);
591 ADD2OPENLIB(__init_fd
, 2);
592 ADD2CLOSELIB(__exit_fd
, 2);