Added missing properties.
[AROS.git] / compiler / clib / __fdesc.c
blobfa0fff92d01c2345d86a6936a5e64290f9a1264a
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 File descriptors handling internals.
6 */
8 #include "__arosc_privdata.h"
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 <aros/symbolsets.h>
24 #include <aros/debug.h>
25 #include "__fdesc.h"
26 #include "__upath.h"
28 static struct SignalSemaphore __fdsem;
29 static struct MinList __fdreglist;
31 void __getfdarray(APTR *arrayptr, int *slotsptr)
33 struct aroscbase *aroscbase = __GM_GetBase();
35 *arrayptr = aroscbase->acb_fd_array;
36 *slotsptr = aroscbase->acb_numslots;
39 void __setfdarray(APTR array, int slots)
41 struct aroscbase *aroscbase = __GM_GetBase();
42 aroscbase->acb_fd_array = array;
43 aroscbase->acb_numslots = slots;
46 void __setfdarraybase(struct aroscbase *aroscbase2)
48 struct aroscbase *aroscbase = __GM_GetBase();
50 aroscbase->acb_fd_array = aroscbase2->acb_fd_array;
51 aroscbase->acb_numslots = aroscbase2->acb_numslots;
54 int __getfdslots(void)
56 struct aroscbase *aroscbase = __GM_GetBase();
57 return aroscbase->acb_numslots;
60 fdesc *__getfdesc(register int fd)
62 struct aroscbase *aroscbase = __GM_GetBase();
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 = __GM_GetBase();
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 = __GM_GetBase();
76 /* FIXME: Check if fd is in valid range... */
77 for (
79 startfd < aroscbase->acb_numslots && aroscbase->acb_fd_array[startfd];
80 startfd++
83 return startfd;
86 int __getfdslot(int wanted_fd)
88 struct aroscbase *aroscbase = __GM_GetBase();
89 if (wanted_fd>=aroscbase->acb_numslots)
91 void *tmp;
93 tmp = AllocPooled(aroscbase->acb_internalpool, (wanted_fd+1)*sizeof(fdesc *));
95 if (!tmp) return -1;
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;
106 bzero(aroscbase->acb_fd_array + aroscbase->acb_numslots, (wanted_fd - aroscbase->acb_numslots + 1) * sizeof(fdesc *));
107 aroscbase->acb_numslots = wanted_fd+1;
109 else if (wanted_fd < 0)
111 errno = EINVAL;
112 return -1;
114 else if (aroscbase->acb_fd_array[wanted_fd])
116 close(wanted_fd);
119 return wanted_fd;
122 LONG __oflags2amode(int flags)
124 LONG openmode = -1;
126 /* filter out invalid modes */
127 switch (flags & (O_CREAT|O_TRUNC|O_EXCL))
129 case O_EXCL:
130 case O_EXCL|O_TRUNC:
131 return -1;
134 /* Sorted in 'trumping' order. Ie if
135 * O_WRITE is on, that overrides O_READ.
136 * Similarly, O_CREAT overrides O_WRITE.
138 if (flags & O_RDONLY) openmode = MODE_OLDFILE;
139 if (flags & O_WRONLY) openmode = MODE_OLDFILE;
140 if (flags & O_RDWR) openmode = MODE_OLDFILE;
141 if (flags & O_READ) openmode = MODE_OLDFILE;
142 if (flags & O_WRITE) openmode = MODE_READWRITE;
143 if (flags & O_CREAT) openmode = MODE_NEWFILE;
144 if (flags & O_APPEND) /* Handled later */;
145 if (flags & O_TRUNC) /* Handled later */;
146 if (flags & O_EXEC) /* Ignored */;
147 if (flags & O_NONBLOCK) /* Ignored */;
149 return openmode;
152 int __open(int wanted_fd, const char *pathname, int flags, int mode)
154 struct aroscbase *aroscbase = __GM_GetBase();
155 BPTR fh = BNULL, lock = BNULL;
156 fdesc *currdesc = NULL;
157 fcb *cblock = NULL;
158 struct FileInfoBlock *fib = NULL;
159 LONG openmode = __oflags2amode(flags);
161 if (aroscbase->acb_doupath && pathname[0] == '\0')
163 /* On *nix "" is not really a valid file name. */
164 errno = ENOENT;
165 return -1;
168 pathname = __path_u2a(pathname);
169 if (!pathname) return -1;
171 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd, pathname, flags, mode));
173 if (openmode == -1)
175 errno = EINVAL;
176 D(bug( "__open: exiting with error EINVAL\n"));
177 return -1;
180 cblock = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR);
181 if (!cblock) { D(bug("__open: no memory [1]\n")); goto err; }
182 currdesc = __alloc_fdesc();
183 if (!currdesc) { D(bug("__open: no memory [2]\n")); goto err; }
184 currdesc->fdflags = 0;
185 currdesc->fcb = cblock;
187 wanted_fd = __getfdslot(wanted_fd);
188 if (wanted_fd == -1) { D(bug("__open: no free fd\n")); goto err; }
190 lock = Lock((char *)pathname, SHARED_LOCK);
191 if (!lock)
193 if (IoErr() == ERROR_OBJECT_WRONG_TYPE)
196 Needed for sfs file system which reports this error number on a
197 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
199 errno = ENOTDIR;
200 goto err;
205 (IoErr() != ERROR_OBJECT_NOT_FOUND) ||
206 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
207 (IoErr() == ERROR_OBJECT_NOT_FOUND && !(flags & O_CREAT))
210 errno = __arosc_ioerr2errno(IoErr());
211 goto err;
214 else
216 /* If the file exists, but O_EXCL is set, then return an error */
217 if (flags & O_EXCL)
219 errno = EEXIST;
220 goto err;
223 fib = AllocDosObject(DOS_FIB, NULL);
224 if (!fib)
226 errno = __arosc_ioerr2errno(IoErr());
227 goto err;
230 if (!Examine(lock, fib))
233 The filesystem in which the file resides doesn't support
234 the EXAMINE action. It might be broken or might also not
235 be a filesystem at all. So let's assume the file is not a
236 diretory.
238 fib->fib_DirEntryType = 0;
241 /* FIXME: implement softlink handling */
243 /* Check if it's a directory or a softlink.
244 Softlinks are not handled yet, though */
245 if (fib->fib_DirEntryType > 0)
247 /* A directory cannot be opened for writing */
248 if (openmode != MODE_OLDFILE)
250 errno = EISDIR;
251 goto err;
254 fh = lock;
255 FreeDosObject(DOS_FIB, fib);
256 currdesc->fcb->isdir = 1;
258 goto success;
260 FreeDosObject(DOS_FIB, fib);
261 fib = NULL;
264 /* the file exists and it's not a directory or the file doesn't exist */
266 if (lock)
268 UnLock(lock);
269 lock = BNULL;
272 if (!(fh = Open ((char *)pathname, openmode)) )
274 ULONG ioerr = IoErr();
275 D(bug("__open: Open ioerr=%d\n", ioerr));
276 errno = __arosc_ioerr2errno(ioerr);
277 goto err;
280 /* Handle O_TRUNC */
281 if((flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)))
283 if(SetFileSize(fh, 0, OFFSET_BEGINNING) != 0)
285 ULONG ioerr = IoErr();
286 /* Ignore error if ACTION_SET_FILE_SIZE is not implemented */
287 if(ioerr != ERROR_NOT_IMPLEMENTED &&
288 ioerr != ERROR_ACTION_NOT_KNOWN)
290 D(bug("__open: SetFileSize ioerr=%d\n", ioerr));
291 errno = __arosc_ioerr2errno(ioerr);
292 goto err;
297 /* Handle O_APPEND */
298 if((flags & O_APPEND) && (flags & (O_RDWR | O_WRONLY)))
300 if(Seek(fh, 0, OFFSET_END) != 0) {
301 errno = __arosc_ioerr2errno(IoErr());
302 goto err;
307 success:
308 currdesc->fcb->fh = fh;
309 currdesc->fcb->flags = flags;
310 currdesc->fcb->opencount = 1;
312 __setfdesc(wanted_fd, currdesc);
314 D(bug("__open: exiting fd=%d\n", wanted_fd));
316 return wanted_fd;
318 err:
319 if (fib) FreeDosObject(DOS_FIB, fib);
320 if (cblock) FreeVec(cblock);
321 if (currdesc) __free_fdesc(currdesc);
322 if (fh && fh != lock) Close(fh);
323 if (lock) UnLock(lock);
325 D(bug("__open: exiting with error %d\n", errno ));
327 return -1;
330 fdesc *__alloc_fdesc(void)
332 struct aroscbase *aroscbase = __GM_GetBase();
333 fdesc * desc;
335 desc = AllocPooled(aroscbase->acb_internalpool, sizeof(fdesc));
337 D(bug("Allocated fdesc %x from %x pool\n", desc, aroscbase->acb_internalpool));
339 return desc;
342 void __free_fdesc(fdesc *desc)
344 struct aroscbase *aroscbase = __GM_GetBase();
345 D(bug("Freeing fdesc %x from %x pool\n", desc, aroscbase->acb_internalpool));
346 FreePooled(aroscbase->acb_internalpool, desc, sizeof(fdesc));
350 struct __reg_fdarray {
351 struct MinNode node;
352 struct Task *task;
353 fdesc **fdarray;
354 int numslots;
357 /* Some local variables for register_init_fdarray */
358 static struct SignalSemaphore __fdsem;
359 static struct MinList __fdreglist;
361 int __init_vars(struct ExecBase *SysBase)
363 InitSemaphore(&__fdsem);
364 NEWLIST(&__fdreglist);
366 return TRUE;
369 int __register_init_fdarray(struct aroscbase *base)
371 /* arosc privdata should not be used inside this function,
372 * this function is called before aroscbase is initialized
374 struct __reg_fdarray *regnode = AllocVec(sizeof(struct __reg_fdarray), MEMF_ANY|MEMF_CLEAR);
376 if (regnode == NULL)
377 return 0;
379 regnode->task = FindTask(NULL);
380 regnode->fdarray = base->acb_fd_array;
381 regnode->numslots = base->acb_numslots;
383 D(bug("Allocated regnode: %p, fdarray: %p, numslots: %d\n",
384 regnode, regnode->fdarray, regnode->numslots
387 ObtainSemaphore(&__fdsem);
388 AddHead((struct List *)&__fdreglist, (struct Node *)regnode);
389 ReleaseSemaphore(&__fdsem);
391 return 1;
394 /* FIXME: perhaps this has to be handled in a different way... */
395 int __init_stdfiles(struct aroscbase *aroscbase)
397 struct Process *me;
398 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
399 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
400 int res = __getfdslot(2);
404 res == -1 ||
405 !(infcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
406 !(indesc = __alloc_fdesc()) ||
407 !(outfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
408 !(outdesc = __alloc_fdesc()) ||
409 !(errfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
410 !(errdesc = __alloc_fdesc())
413 if(infcb)
414 FreeVec(infcb);
415 if(indesc)
416 __free_fdesc(indesc);
417 if(outfcb)
418 FreeVec(outfcb);
419 if(outdesc)
420 __free_fdesc(outdesc);
421 if(errfcb)
422 FreeVec(errfcb);
423 if(errdesc)
424 __free_fdesc(errdesc);
425 SetIoErr(ERROR_NO_FREE_STORE);
426 return 0;
429 indesc->fdflags = 0;
430 outdesc->fdflags = 0;
431 errdesc->fdflags = 0;
433 indesc->fcb = infcb;
434 outdesc->fcb = outfcb;
435 errdesc->fcb = errfcb;
437 me = (struct Process *)FindTask (NULL);
438 indesc->fcb->fh = Input();
439 outdesc->fcb->fh = Output();
440 errdesc->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
442 indesc->fcb->flags = O_RDONLY;
443 outdesc->fcb->flags = O_WRONLY | O_APPEND;
444 errdesc->fcb->flags = O_WRONLY | O_APPEND;
446 indesc->fcb->opencount = outdesc->fcb->opencount = errdesc->fcb->opencount = 1;
447 indesc->fcb->privflags = outdesc->fcb->privflags = errdesc->fcb->privflags = _FCB_DONTCLOSE_FH;
449 aroscbase->acb_fd_array[STDIN_FILENO] = indesc;
450 aroscbase->acb_fd_array[STDOUT_FILENO] = outdesc;
451 aroscbase->acb_fd_array[STDERR_FILENO] = errdesc;
453 return 1;
456 static int __copy_fdarray(fdesc **__src_fd_array, int numslots)
458 struct aroscbase *aroscbase = __GM_GetBase();
459 int i;
461 for(i = numslots - 1; i >= 0; i--)
463 if(__src_fd_array[i])
465 if(__getfdslot(i) != i)
466 return 0;
468 if((aroscbase->acb_fd_array[i] = __alloc_fdesc()) == NULL)
469 return 0;
471 aroscbase->acb_fd_array[i]->fdflags = __src_fd_array[i]->fdflags;
472 aroscbase->acb_fd_array[i]->fcb = __src_fd_array[i]->fcb;
473 aroscbase->acb_fd_array[i]->fcb->opencount++;
477 return 1;
480 int __init_fd(struct aroscbase *aroscbase)
482 struct __reg_fdarray *regnodeit, *regnode = NULL;
483 struct Task *self = FindTask(NULL);
485 ObtainSemaphore(&__fdsem);
486 ForeachNode(&__fdreglist, regnodeit)
488 if (regnodeit->task == self)
490 regnode = regnodeit;
492 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
493 regnode, regnode->fdarray, regnode->numslots
495 Remove((struct Node *)regnode);
496 break;
499 ReleaseSemaphore(&__fdsem);
501 if (regnode == NULL)
502 return __init_stdfiles(aroscbase);
503 else
505 int ok = __copy_fdarray(regnode->fdarray, regnode->numslots);
507 FreeVec(regnode);
509 return ok;
513 void __exit_fd(struct aroscbase *aroscbase)
515 int i = aroscbase->acb_numslots;
516 while (i)
518 if (aroscbase->acb_fd_array[--i])
519 close(i);
523 void __close_on_exec_fdescs(void)
525 struct aroscbase *aroscbase = __GM_GetBase();
527 int i;
528 fdesc *fd;
530 for (i = aroscbase->acb_numslots - 1; i >= 0; i--)
532 if ((fd = __getfdesc(i)) != NULL)
534 D(bug("__close_fdesc_on_exec: checking fd %d\n", i));
535 if (fd->fdflags & FD_CLOEXEC)
537 D(bug("__close_fdesc_on_exec: closing fd %d\n", i));
538 close(i);
544 #include <stdio.h>
546 void __updatestdio(void)
548 struct aroscbase *aroscbase = __GM_GetBase();
549 struct Process *me;
551 me = (struct Process *)FindTask(NULL);
553 fflush(stdin);
554 fflush(stdout);
555 fflush(stderr);
557 aroscbase->acb_fd_array[STDIN_FILENO]->fcb->fh = Input();
558 aroscbase->acb_fd_array[STDOUT_FILENO]->fcb->fh = Output();
559 aroscbase->acb_fd_array[STDERR_FILENO]->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
561 aroscbase->acb_fd_array[STDIN_FILENO]->fcb->privflags =
562 aroscbase->acb_fd_array[STDOUT_FILENO]->fcb->privflags =
563 aroscbase->acb_fd_array[STDERR_FILENO]->fcb->privflags = _FCB_DONTCLOSE_FH;
566 ADD2INIT(__init_vars, 0);
567 ADD2OPENLIB(__init_fd, 2);
568 ADD2CLOSELIB(__exit_fd, 2);