2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
5 File descriptors handling internals.
8 #include "__arosc_privdata.h"
18 #include <proto/exec.h>
19 #include <proto/dos.h>
20 #include <exec/memory.h>
21 #include <exec/semaphores.h>
23 #include <aros/symbolsets.h>
24 #include <aros/debug.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... */
79 startfd
< aroscbase
->acb_numslots
&& aroscbase
->acb_fd_array
[startfd
];
86 int __getfdslot(int wanted_fd
)
88 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
89 if (wanted_fd
>=aroscbase
->acb_numslots
)
93 tmp
= AllocPooled(aroscbase
->acb_internalpool
, (wanted_fd
+1)*sizeof(fdesc
*));
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
;
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)
118 else if (aroscbase
->acb_fd_array
[wanted_fd
])
126 LONG
__oflags2amode(int flags
)
130 /* filter out invalid modes */
131 switch (flags
& (O_CREAT
|O_TRUNC
|O_EXCL
))
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 */;
156 static int nolocktest(const char *pathname
)
158 /* Allow fopen("CON:...") */
159 if (strcasestr(pathname
, "CON:") == pathname
)
165 int __open(int wanted_fd
, const char *pathname
, int flags
, int mode
)
167 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
168 BPTR fh
= BNULL
, lock
= BNULL
;
169 fdesc
*currdesc
= NULL
;
171 struct FileInfoBlock
*fib
= NULL
;
172 LONG openmode
= __oflags2amode(flags
);
174 if (aroscbase
->acb_doupath
&& pathname
[0] == '\0')
176 /* On *nix "" is not really a valid file name. */
181 pathname
= __path_u2a(pathname
);
182 if (!pathname
) return -1;
184 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd
, pathname
, flags
, mode
));
189 D(bug( "__open: exiting with error EINVAL\n"));
193 cblock
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
);
194 if (!cblock
) { D(bug("__open: no memory [1]\n")); goto err
; }
195 currdesc
= __alloc_fdesc();
196 if (!currdesc
) { D(bug("__open: no memory [2]\n")); goto err
; }
197 currdesc
->fdflags
= 0;
198 currdesc
->fcb
= cblock
;
200 wanted_fd
= __getfdslot(wanted_fd
);
201 if (wanted_fd
== -1) { D(bug("__open: no free fd\n")); goto err
; }
203 if(!nolocktest(pathname
))
205 lock
= Lock((char *)pathname
, SHARED_LOCK
);
208 if (IoErr() == ERROR_OBJECT_WRONG_TYPE
)
211 Needed for sfs file system which reports this error number on a
212 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
220 (IoErr() != ERROR_OBJECT_NOT_FOUND
) ||
221 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
222 (IoErr() == ERROR_OBJECT_NOT_FOUND
&& !(flags
& O_CREAT
))
225 errno
= __arosc_ioerr2errno(IoErr());
231 /* If the file exists, but O_EXCL is set, then return an error */
238 fib
= AllocDosObject(DOS_FIB
, NULL
);
241 errno
= __arosc_ioerr2errno(IoErr());
245 if (!Examine(lock
, fib
))
248 The filesystem in which the file resides doesn't support
249 the EXAMINE action. It might be broken or might also not
250 be a filesystem at all. So let's assume the file is not a
253 fib
->fib_DirEntryType
= 0;
256 /* FIXME: implement softlink handling */
258 /* Check if it's a directory or a softlink.
259 Softlinks are not handled yet, though */
260 if (fib
->fib_DirEntryType
> 0)
262 /* A directory cannot be opened for writing */
263 if (openmode
!= MODE_OLDFILE
)
270 FreeDosObject(DOS_FIB
, fib
);
271 currdesc
->fcb
->isdir
= 1;
275 FreeDosObject(DOS_FIB
, fib
);
280 /* the file exists and it's not a directory or the file doesn't exist */
288 if (!(fh
= Open ((char *)pathname
, openmode
)) )
290 ULONG ioerr
= IoErr();
291 D(bug("__open: Open ioerr=%d\n", ioerr
));
292 errno
= __arosc_ioerr2errno(ioerr
);
297 if((flags
& O_TRUNC
) && (flags
& (O_RDWR
| O_WRONLY
)))
299 if(SetFileSize(fh
, 0, OFFSET_BEGINNING
) != 0)
301 ULONG ioerr
= IoErr();
302 /* Ignore error if ACTION_SET_FILE_SIZE is not implemented */
303 if(ioerr
!= ERROR_NOT_IMPLEMENTED
&&
304 ioerr
!= ERROR_ACTION_NOT_KNOWN
)
306 D(bug("__open: SetFileSize ioerr=%d\n", ioerr
));
307 errno
= __arosc_ioerr2errno(ioerr
);
313 /* Handle O_APPEND */
314 if((flags
& O_APPEND
) && (flags
& (O_RDWR
| O_WRONLY
)))
316 if(Seek(fh
, 0, OFFSET_END
) != 0) {
317 errno
= __arosc_ioerr2errno(IoErr());
324 currdesc
->fcb
->fh
= fh
;
325 currdesc
->fcb
->flags
= flags
;
326 currdesc
->fcb
->opencount
= 1;
328 __setfdesc(wanted_fd
, currdesc
);
330 D(bug("__open: exiting fd=%d\n", wanted_fd
));
335 if (fib
) FreeDosObject(DOS_FIB
, fib
);
336 if (cblock
) FreeVec(cblock
);
337 if (currdesc
) __free_fdesc(currdesc
);
338 if (fh
&& fh
!= lock
) Close(fh
);
339 if (lock
) UnLock(lock
);
341 D(bug("__open: exiting with error %d\n", errno
));
346 fdesc
*__alloc_fdesc(void)
348 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
351 desc
= AllocPooled(aroscbase
->acb_internalpool
, sizeof(fdesc
));
353 D(bug("Allocated fdesc %x from %x pool\n", desc
, aroscbase
->acb_internalpool
));
358 void __free_fdesc(fdesc
*desc
)
360 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
361 D(bug("Freeing fdesc %x from %x pool\n", desc
, aroscbase
->acb_internalpool
));
362 FreePooled(aroscbase
->acb_internalpool
, desc
, sizeof(fdesc
));
366 struct __reg_fdarray
{
373 /* Some local variables for register_init_fdarray */
374 static struct SignalSemaphore __fdsem
;
375 static struct MinList __fdreglist
;
377 int __init_vars(struct ExecBase
*SysBase
)
379 InitSemaphore(&__fdsem
);
380 NEWLIST(&__fdreglist
);
385 int __register_init_fdarray(struct aroscbase
*base
)
387 /* arosc privdata should not be used inside this function,
388 * this function is called before aroscbase is initialized
390 struct __reg_fdarray
*regnode
= AllocVec(sizeof(struct __reg_fdarray
), MEMF_ANY
|MEMF_CLEAR
);
395 regnode
->task
= FindTask(NULL
);
396 regnode
->fdarray
= base
->acb_fd_array
;
397 regnode
->numslots
= base
->acb_numslots
;
399 D(bug("Allocated regnode: %p, fdarray: %p, numslots: %d\n",
400 regnode
, regnode
->fdarray
, regnode
->numslots
403 ObtainSemaphore(&__fdsem
);
404 AddHead((struct List
*)&__fdreglist
, (struct Node
*)regnode
);
405 ReleaseSemaphore(&__fdsem
);
410 /* FIXME: perhaps this has to be handled in a different way... */
411 int __init_stdfiles(struct aroscbase
*aroscbase
)
414 fcb
*infcb
= NULL
, *outfcb
= NULL
, *errfcb
= NULL
;
415 fdesc
*indesc
=NULL
, *outdesc
=NULL
, *errdesc
=NULL
;
416 int res
= __getfdslot(2);
421 !(infcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
422 !(indesc
= __alloc_fdesc()) ||
423 !(outfcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
424 !(outdesc
= __alloc_fdesc()) ||
425 !(errfcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
426 !(errdesc
= __alloc_fdesc())
432 __free_fdesc(indesc
);
436 __free_fdesc(outdesc
);
440 __free_fdesc(errdesc
);
441 SetIoErr(ERROR_NO_FREE_STORE
);
446 outdesc
->fdflags
= 0;
447 errdesc
->fdflags
= 0;
450 outdesc
->fcb
= outfcb
;
451 errdesc
->fcb
= errfcb
;
453 me
= (struct Process
*)FindTask (NULL
);
454 indesc
->fcb
->fh
= Input();
455 outdesc
->fcb
->fh
= Output();
456 errdesc
->fcb
->fh
= me
->pr_CES
? me
->pr_CES
: me
->pr_COS
;
458 indesc
->fcb
->flags
= O_RDONLY
;
459 outdesc
->fcb
->flags
= O_WRONLY
| O_APPEND
;
460 errdesc
->fcb
->flags
= O_WRONLY
| O_APPEND
;
462 indesc
->fcb
->opencount
= outdesc
->fcb
->opencount
= errdesc
->fcb
->opencount
= 1;
463 indesc
->fcb
->privflags
= outdesc
->fcb
->privflags
= errdesc
->fcb
->privflags
= _FCB_DONTCLOSE_FH
;
465 aroscbase
->acb_fd_array
[STDIN_FILENO
] = indesc
;
466 aroscbase
->acb_fd_array
[STDOUT_FILENO
] = outdesc
;
467 aroscbase
->acb_fd_array
[STDERR_FILENO
] = errdesc
;
472 static int __copy_fdarray(fdesc
**__src_fd_array
, int numslots
)
474 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
477 for(i
= numslots
- 1; i
>= 0; i
--)
479 if(__src_fd_array
[i
])
481 if(__getfdslot(i
) != i
)
484 if((aroscbase
->acb_fd_array
[i
] = __alloc_fdesc()) == NULL
)
487 aroscbase
->acb_fd_array
[i
]->fdflags
= __src_fd_array
[i
]->fdflags
;
488 aroscbase
->acb_fd_array
[i
]->fcb
= __src_fd_array
[i
]->fcb
;
489 aroscbase
->acb_fd_array
[i
]->fcb
->opencount
++;
496 int __init_fd(struct aroscbase
*aroscbase
)
498 struct __reg_fdarray
*regnodeit
, *regnode
= NULL
;
499 struct Task
*self
= FindTask(NULL
);
501 ObtainSemaphore(&__fdsem
);
502 ForeachNode(&__fdreglist
, regnodeit
)
504 if (regnodeit
->task
== self
)
508 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
509 regnode
, regnode
->fdarray
, regnode
->numslots
511 Remove((struct Node
*)regnode
);
515 ReleaseSemaphore(&__fdsem
);
518 return __init_stdfiles(aroscbase
);
521 int ok
= __copy_fdarray(regnode
->fdarray
, regnode
->numslots
);
529 void __exit_fd(struct aroscbase
*aroscbase
)
531 int i
= aroscbase
->acb_numslots
;
534 if (aroscbase
->acb_fd_array
[--i
])
539 void __close_on_exec_fdescs(void)
541 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
546 for (i
= aroscbase
->acb_numslots
- 1; i
>= 0; i
--)
548 if ((fd
= __getfdesc(i
)) != NULL
)
550 D(bug("__close_fdesc_on_exec: checking fd %d\n", i
));
551 if (fd
->fdflags
& FD_CLOEXEC
)
553 D(bug("__close_fdesc_on_exec: closing fd %d\n", i
));
562 void __updatestdio(void)
564 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
567 me
= (struct Process
*)FindTask(NULL
);
573 aroscbase
->acb_fd_array
[STDIN_FILENO
]->fcb
->fh
= Input();
574 aroscbase
->acb_fd_array
[STDOUT_FILENO
]->fcb
->fh
= Output();
575 aroscbase
->acb_fd_array
[STDERR_FILENO
]->fcb
->fh
= me
->pr_CES
? me
->pr_CES
: me
->pr_COS
;
577 aroscbase
->acb_fd_array
[STDIN_FILENO
]->fcb
->privflags
=
578 aroscbase
->acb_fd_array
[STDOUT_FILENO
]->fcb
->privflags
=
579 aroscbase
->acb_fd_array
[STDERR_FILENO
]->fcb
->privflags
= _FCB_DONTCLOSE_FH
;
582 ADD2INIT(__init_vars
, 0);
583 ADD2OPENLIB(__init_fd
, 2);
584 ADD2CLOSELIB(__exit_fd
, 2);