arosc.library: bring back functionality to fopen/freopen("con:...")
[AROS.git] / compiler / clib / __fdesc.c
blobc787abf942f345f95e5d6b64f4c0e7c5e0ad13dc
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 = __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... */
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 = __aros_getbase_aroscbase();
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 memset(
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)
115 errno = EINVAL;
116 return -1;
118 else if (aroscbase->acb_fd_array[wanted_fd])
120 close(wanted_fd);
123 return wanted_fd;
126 LONG __oflags2amode(int flags)
128 LONG openmode = -1;
130 /* filter out invalid modes */
131 switch (flags & (O_CREAT|O_TRUNC|O_EXCL))
133 case O_EXCL:
134 case O_EXCL|O_TRUNC:
135 return -1;
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 */;
153 return openmode;
156 static int nolocktest(const char *pathname)
158 /* Allow fopen("CON:...") */
159 if (strcasestr(pathname, "CON:") == pathname)
160 return 1;
162 return 0;
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;
170 fcb *cblock = 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. */
177 errno = ENOENT;
178 return -1;
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));
186 if (openmode == -1)
188 errno = EINVAL;
189 D(bug( "__open: exiting with error EINVAL\n"));
190 return -1;
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);
206 if (!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.
214 errno = ENOTDIR;
215 goto err;
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());
226 goto err;
229 else
231 /* If the file exists, but O_EXCL is set, then return an error */
232 if (flags & O_EXCL)
234 errno = EEXIST;
235 goto err;
238 fib = AllocDosObject(DOS_FIB, NULL);
239 if (!fib)
241 errno = __arosc_ioerr2errno(IoErr());
242 goto err;
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
251 diretory.
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)
265 errno = EISDIR;
266 goto err;
269 fh = lock;
270 FreeDosObject(DOS_FIB, fib);
271 currdesc->fcb->isdir = 1;
273 goto success;
275 FreeDosObject(DOS_FIB, fib);
276 fib = NULL;
280 /* the file exists and it's not a directory or the file doesn't exist */
282 if (lock)
284 UnLock(lock);
285 lock = BNULL;
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);
293 goto err;
296 /* Handle O_TRUNC */
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);
308 goto err;
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());
318 goto err;
323 success:
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));
332 return wanted_fd;
334 err:
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 ));
343 return -1;
346 fdesc *__alloc_fdesc(void)
348 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
349 fdesc * desc;
351 desc = AllocPooled(aroscbase->acb_internalpool, sizeof(fdesc));
353 D(bug("Allocated fdesc %x from %x pool\n", desc, aroscbase->acb_internalpool));
355 return desc;
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 {
367 struct MinNode node;
368 struct Task *task;
369 fdesc **fdarray;
370 int numslots;
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);
382 return TRUE;
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);
392 if (regnode == NULL)
393 return 0;
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);
407 return 1;
410 /* FIXME: perhaps this has to be handled in a different way... */
411 int __init_stdfiles(struct aroscbase *aroscbase)
413 struct Process *me;
414 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
415 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
416 int res = __getfdslot(2);
420 res == -1 ||
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())
429 if(infcb)
430 FreeVec(infcb);
431 if(indesc)
432 __free_fdesc(indesc);
433 if(outfcb)
434 FreeVec(outfcb);
435 if(outdesc)
436 __free_fdesc(outdesc);
437 if(errfcb)
438 FreeVec(errfcb);
439 if(errdesc)
440 __free_fdesc(errdesc);
441 SetIoErr(ERROR_NO_FREE_STORE);
442 return 0;
445 indesc->fdflags = 0;
446 outdesc->fdflags = 0;
447 errdesc->fdflags = 0;
449 indesc->fcb = infcb;
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;
469 return 1;
472 static int __copy_fdarray(fdesc **__src_fd_array, int numslots)
474 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
475 int i;
477 for(i = numslots - 1; i >= 0; i--)
479 if(__src_fd_array[i])
481 if(__getfdslot(i) != i)
482 return 0;
484 if((aroscbase->acb_fd_array[i] = __alloc_fdesc()) == NULL)
485 return 0;
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++;
493 return 1;
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)
506 regnode = regnodeit;
508 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
509 regnode, regnode->fdarray, regnode->numslots
511 Remove((struct Node *)regnode);
512 break;
515 ReleaseSemaphore(&__fdsem);
517 if (regnode == NULL)
518 return __init_stdfiles(aroscbase);
519 else
521 int ok = __copy_fdarray(regnode->fdarray, regnode->numslots);
523 FreeVec(regnode);
525 return ok;
529 void __exit_fd(struct aroscbase *aroscbase)
531 int i = aroscbase->acb_numslots;
532 while (i)
534 if (aroscbase->acb_fd_array[--i])
535 close(i);
539 void __close_on_exec_fdescs(void)
541 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
543 int i;
544 fdesc *fd;
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));
554 close(i);
560 #include <stdio.h>
562 void __updatestdio(void)
564 struct aroscbase *aroscbase = __aros_getbase_aroscbase();
565 struct Process *me;
567 me = (struct Process *)FindTask(NULL);
569 fflush(stdin);
570 fflush(stdout);
571 fflush(stderr);
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);