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 int __getfdslots(void)
33 struct aroscbase
*aroscbase
= __GM_GetBase();
34 return aroscbase
->acb_numslots
;
37 fdesc
*__getfdesc(register int fd
)
39 struct aroscbase
*aroscbase
= __GM_GetBase();
40 return ((aroscbase
->acb_numslots
>fd
) && (fd
>=0))?aroscbase
->acb_fd_array
[fd
]:NULL
;
43 void __setfdesc(register int fd
, fdesc
*desc
)
45 struct aroscbase
*aroscbase
= __GM_GetBase();
46 /* FIXME: Check if fd is in valid range... */
47 aroscbase
->acb_fd_array
[fd
] = desc
;
50 int __getfirstfd(register int startfd
)
52 struct aroscbase
*aroscbase
= __GM_GetBase();
53 /* FIXME: Check if fd is in valid range... */
56 startfd
< aroscbase
->acb_numslots
&& aroscbase
->acb_fd_array
[startfd
];
63 int __getfdslot(int wanted_fd
)
65 struct aroscbase
*aroscbase
= __GM_GetBase();
66 if (wanted_fd
>=aroscbase
->acb_numslots
)
70 tmp
= AllocPooled(aroscbase
->acb_fd_mempool
, (wanted_fd
+1)*sizeof(fdesc
*));
74 if (aroscbase
->acb_fd_array
)
76 size_t size
= aroscbase
->acb_numslots
*sizeof(fdesc
*);
77 CopyMem(aroscbase
->acb_fd_array
, tmp
, size
);
78 FreePooled(aroscbase
->acb_fd_mempool
, aroscbase
->acb_fd_array
, size
);
81 aroscbase
->acb_fd_array
= tmp
;
83 bzero(aroscbase
->acb_fd_array
+ aroscbase
->acb_numslots
, (wanted_fd
- aroscbase
->acb_numslots
+ 1) * sizeof(fdesc
*));
84 aroscbase
->acb_numslots
= wanted_fd
+1;
86 else if (wanted_fd
< 0)
91 else if (aroscbase
->acb_fd_array
[wanted_fd
])
99 LONG
__oflags2amode(int flags
)
103 /* filter out invalid modes */
104 switch (flags
& (O_CREAT
|O_TRUNC
|O_EXCL
))
111 /* Sorted in 'trumping' order. Ie if
112 * O_WRITE is on, that overrides O_READ.
113 * Similarly, O_CREAT overrides O_WRITE.
115 if (flags
& O_RDONLY
) openmode
= MODE_OLDFILE
;
116 if (flags
& O_WRONLY
) openmode
= MODE_OLDFILE
;
117 if (flags
& O_RDWR
) openmode
= MODE_OLDFILE
;
118 if (flags
& O_READ
) openmode
= MODE_OLDFILE
;
119 if (flags
& O_WRITE
) openmode
= MODE_READWRITE
;
120 if (flags
& O_CREAT
) openmode
= MODE_NEWFILE
;
121 if (flags
& O_APPEND
) /* Handled later */;
122 if (flags
& O_TRUNC
) /* Handled later */;
123 if (flags
& O_EXEC
) /* Ignored */;
124 if (flags
& O_NONBLOCK
) /* Ignored */;
129 int __open(int wanted_fd
, const char *pathname
, int flags
, int mode
)
131 struct aroscbase
*aroscbase
= __GM_GetBase();
132 BPTR fh
= BNULL
, lock
= BNULL
;
133 fdesc
*currdesc
= NULL
;
135 struct FileInfoBlock
*fib
= NULL
;
136 LONG openmode
= __oflags2amode(flags
);
138 if (aroscbase
->acb_doupath
&& pathname
[0] == '\0')
140 /* On *nix "" is not really a valid file name. */
145 pathname
= __path_u2a(pathname
);
146 if (!pathname
) return -1;
148 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd
, pathname
, flags
, mode
));
153 D(bug( "__open: exiting with error EINVAL\n"));
157 cblock
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
);
158 if (!cblock
) { D(bug("__open: no memory [1]\n")); goto err
; }
159 currdesc
= __alloc_fdesc();
160 if (!currdesc
) { D(bug("__open: no memory [2]\n")); goto err
; }
161 currdesc
->fdflags
= 0;
162 currdesc
->fcb
= cblock
;
164 wanted_fd
= __getfdslot(wanted_fd
);
165 if (wanted_fd
== -1) { D(bug("__open: no free fd\n")); goto err
; }
167 lock
= Lock((char *)pathname
, SHARED_LOCK
);
170 if (IoErr() == ERROR_OBJECT_WRONG_TYPE
)
173 Needed for sfs file system which reports this error number on a
174 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
182 (IoErr() != ERROR_OBJECT_NOT_FOUND
) ||
183 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
184 (IoErr() == ERROR_OBJECT_NOT_FOUND
&& !(flags
& O_CREAT
))
187 errno
= __arosc_ioerr2errno(IoErr());
193 /* If the file exists, but O_EXCL is set, then return an error */
200 fib
= AllocDosObject(DOS_FIB
, NULL
);
203 errno
= __arosc_ioerr2errno(IoErr());
207 if (!Examine(lock
, fib
))
210 The filesystem in which the file resides doesn't support
211 the EXAMINE action. It might be broken or might also not
212 be a filesystem at all. So let's assume the file is not a
215 fib
->fib_DirEntryType
= 0;
218 /* FIXME: implement softlink handling */
220 /* Check if it's a directory or a softlink.
221 Softlinks are not handled yet, though */
222 if (fib
->fib_DirEntryType
> 0)
224 /* A directory cannot be opened for writing */
225 if (openmode
!= MODE_OLDFILE
)
232 FreeDosObject(DOS_FIB
, fib
);
233 currdesc
->fcb
->isdir
= 1;
237 FreeDosObject(DOS_FIB
, fib
);
241 /* the file exists and it's not a directory or the file doesn't exist */
249 if (!(fh
= Open ((char *)pathname
, openmode
)) )
251 ULONG ioerr
= IoErr();
252 D(bug("__open: Open ioerr=%d\n", ioerr
));
253 errno
= __arosc_ioerr2errno(ioerr
);
258 if((flags
& O_TRUNC
) && (flags
& (O_RDWR
| O_WRONLY
)))
260 if(SetFileSize(fh
, 0, OFFSET_BEGINNING
) != 0)
262 ULONG ioerr
= IoErr();
263 /* Ignore error if ACTION_SET_FILE_SIZE is not implemented */
264 if(ioerr
!= ERROR_NOT_IMPLEMENTED
)
266 D(bug("__open: SetFileSize ioerr=%d\n", ioerr
));
267 errno
= __arosc_ioerr2errno(ioerr
);
273 /* Handle O_APPEND */
274 if((flags
& O_APPEND
) && (flags
& (O_RDWR
| O_WRONLY
)))
276 if(Seek(fh
, 0, OFFSET_END
) != 0) {
277 errno
= __arosc_ioerr2errno(IoErr());
284 currdesc
->fcb
->fh
= fh
;
285 currdesc
->fcb
->flags
= flags
;
286 currdesc
->fcb
->opencount
= 1;
288 __setfdesc(wanted_fd
, currdesc
);
290 D(bug("__open: exiting fd=%d\n", wanted_fd
));
295 if (fib
) FreeDosObject(DOS_FIB
, fib
);
296 if (cblock
) FreeVec(cblock
);
297 if (currdesc
) __free_fdesc(currdesc
);
298 if (fh
&& fh
!= lock
) Close(fh
);
299 if (lock
) UnLock(lock
);
301 D(bug("__open: exiting with error %d\n", errno
));
306 fdesc
*__alloc_fdesc(void)
308 struct aroscbase
*aroscbase
= __GM_GetBase();
311 desc
= AllocPooled(aroscbase
->acb_fd_mempool
, sizeof(fdesc
));
313 D(bug("Allocated fdesc %x from %x pool\n", desc
, aroscbase
->acb_fd_mempool
));
318 void __free_fdesc(fdesc
*desc
)
320 struct aroscbase
*aroscbase
= __GM_GetBase();
321 D(bug("Freeing fdesc %x from %x pool\n", desc
, aroscbase
->acb_fd_mempool
));
322 FreePooled(aroscbase
->acb_fd_mempool
, desc
, sizeof(fdesc
));
326 struct __reg_fdarray
{
333 /* Some local variables for register_init_fdarray */
334 static struct SignalSemaphore __fdsem
;
335 static struct MinList __fdreglist
;
337 int __init_vars(void)
339 InitSemaphore(&__fdsem
);
340 NEWLIST(&__fdreglist
);
345 int __register_init_fdarray(struct aroscbase
*base
)
347 /* arosc privdata should not be used inside this function,
348 * this function is called before aroscbase is initialized
350 struct __reg_fdarray
*regnode
= AllocVec(sizeof(struct __reg_fdarray
), MEMF_ANY
|MEMF_CLEAR
);
355 regnode
->task
= FindTask(NULL
);
356 regnode
->fdarray
= base
->acb_fd_array
;
357 regnode
->numslots
= base
->acb_numslots
;
359 D(bug("Allocated regnode: %p, fdarray: %p, numslots: %d\n",
360 regnode
, regnode
->fdarray
, regnode
->numslots
363 ObtainSemaphore(&__fdsem
);
364 AddHead((struct List
*)&__fdreglist
, (struct Node
*)regnode
);
365 ReleaseSemaphore(&__fdsem
);
370 /* FIXME: perhaps this has to be handled in a different way... */
371 int __init_stdfiles(struct aroscbase
*aroscbase
)
374 fcb
*infcb
= NULL
, *outfcb
= NULL
, *errfcb
= NULL
;
375 fdesc
*indesc
=NULL
, *outdesc
=NULL
, *errdesc
=NULL
;
376 int res
= __getfdslot(2);
381 !(infcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
382 !(indesc
= __alloc_fdesc()) ||
383 !(outfcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
384 !(outdesc
= __alloc_fdesc()) ||
385 !(errfcb
= AllocVec(sizeof(fcb
), MEMF_ANY
| MEMF_CLEAR
)) ||
386 !(errdesc
= __alloc_fdesc())
392 __free_fdesc(indesc
);
396 __free_fdesc(outdesc
);
400 __free_fdesc(errdesc
);
401 SetIoErr(ERROR_NO_FREE_STORE
);
406 outdesc
->fdflags
= 0;
407 errdesc
->fdflags
= 0;
410 outdesc
->fcb
= outfcb
;
411 errdesc
->fcb
= errfcb
;
413 me
= (struct Process
*)FindTask (NULL
);
414 indesc
->fcb
->fh
= Input();
415 outdesc
->fcb
->fh
= Output();
416 errdesc
->fcb
->fh
= me
->pr_CES
? me
->pr_CES
: me
->pr_COS
;
418 indesc
->fcb
->flags
= O_RDONLY
;
419 outdesc
->fcb
->flags
= O_WRONLY
| O_APPEND
;
420 errdesc
->fcb
->flags
= O_WRONLY
| O_APPEND
;
422 indesc
->fcb
->opencount
= outdesc
->fcb
->opencount
= errdesc
->fcb
->opencount
= 1;
423 indesc
->fcb
->privflags
= outdesc
->fcb
->privflags
= errdesc
->fcb
->privflags
= _FCB_DONTCLOSE_FH
;
425 aroscbase
->acb_fd_array
[STDIN_FILENO
] = indesc
;
426 aroscbase
->acb_fd_array
[STDOUT_FILENO
] = outdesc
;
427 aroscbase
->acb_fd_array
[STDERR_FILENO
] = errdesc
;
432 static int __copy_fdarray(fdesc
**__src_fd_array
, int numslots
)
434 struct aroscbase
*aroscbase
= __GM_GetBase();
437 for(i
= numslots
- 1; i
>= 0; i
--)
439 if(__src_fd_array
[i
])
441 if(__getfdslot(i
) != i
)
444 if((aroscbase
->acb_fd_array
[i
] = __alloc_fdesc()) == NULL
)
447 aroscbase
->acb_fd_array
[i
]->fdflags
= __src_fd_array
[i
]->fdflags
;
448 aroscbase
->acb_fd_array
[i
]->fcb
= __src_fd_array
[i
]->fcb
;
449 aroscbase
->acb_fd_array
[i
]->fcb
->opencount
++;
456 int __init_fd(struct aroscbase
*aroscbase
)
458 struct __reg_fdarray
*regnodeit
, *regnode
= NULL
;
459 struct Task
*self
= FindTask(NULL
);
461 aroscbase
->acb_fd_mempool
= CreatePool(MEMF_PUBLIC
, 16*sizeof(fdesc
), 16*sizeof(fdesc
));
463 ObtainSemaphore(&__fdsem
);
464 ForeachNode(&__fdreglist
, regnodeit
)
466 if (regnodeit
->task
== self
)
470 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
471 regnode
, regnode
->fdarray
, regnode
->numslots
473 Remove((struct Node
*)regnode
);
477 ReleaseSemaphore(&__fdsem
);
480 return __init_stdfiles(aroscbase
);
483 int ok
= __copy_fdarray(regnode
->fdarray
, regnode
->numslots
);
491 void __exit_fd(struct aroscbase
*aroscbase
)
493 int i
= aroscbase
->acb_numslots
;
496 if (aroscbase
->acb_fd_array
[--i
])
499 DeletePool(aroscbase
->acb_fd_mempool
);
504 void __updatestdio(void)
506 struct aroscbase
*aroscbase
= __GM_GetBase();
509 me
= (struct Process
*)FindTask(NULL
);
515 aroscbase
->acb_fd_array
[STDIN_FILENO
]->fcb
->fh
= Input();
516 aroscbase
->acb_fd_array
[STDOUT_FILENO
]->fcb
->fh
= Output();
517 aroscbase
->acb_fd_array
[STDERR_FILENO
]->fcb
->fh
= me
->pr_CES
? me
->pr_CES
: me
->pr_COS
;
519 aroscbase
->acb_fd_array
[STDIN_FILENO
]->fcb
->privflags
=
520 aroscbase
->acb_fd_array
[STDOUT_FILENO
]->fcb
->privflags
=
521 aroscbase
->acb_fd_array
[STDERR_FILENO
]->fcb
->privflags
= _FCB_DONTCLOSE_FH
;
524 ADD2INIT(__init_vars
, 0);
525 ADD2OPENLIB(__init_fd
, 2);
526 ADD2CLOSELIB(__exit_fd
, 2);