Also allocate fd_array from fd_mempool
[AROS.git] / compiler / clib / __fdesc.c
blobca7d995de723256ffa8a6b34e9ceb720a2d1ec48
1 /*
2 Copyright © 1995-2011, 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 <dos/filesystem.h>
24 #include <aros/symbolsets.h>
25 #include <aros/debug.h>
26 #include "__errno.h"
27 #include "__fdesc.h"
28 #include "__upath.h"
30 int __getfdslots(void)
32 return __numslots;
35 fdesc *__getfdesc(register int fd)
37 return ((__numslots>fd) && (fd>=0))?__fd_array[fd]:NULL;
40 void __setfdesc(register int fd, fdesc *desc)
42 /* FIXME: Check if fd is in valid range... */
43 __fd_array[fd] = desc;
46 int __getfirstfd(register int startfd)
48 /* FIXME: Check if fd is in valid range... */
49 for (
51 startfd < __numslots && __fd_array[startfd];
52 startfd++
55 return startfd;
58 int __getfdslot(int wanted_fd)
60 if (wanted_fd>=__numslots)
62 void *tmp;
64 tmp = AllocPooled(__fd_mempool, (wanted_fd+1)*sizeof(fdesc *));
66 if (!tmp) return -1;
68 if (__fd_array)
70 size_t size = __numslots*sizeof(fdesc *);
71 CopyMem(__fd_array, tmp, size);
72 FreePooled(__fd_mempool, __fd_array, size);
75 __fd_array = tmp;
77 bzero(__fd_array + __numslots, (wanted_fd - __numslots + 1) * sizeof(fdesc *));
78 __numslots = wanted_fd+1;
80 else if (wanted_fd < 0)
82 errno = EINVAL;
83 return -1;
85 else if (__fd_array[wanted_fd])
87 close(wanted_fd);
90 return wanted_fd;
93 LONG __oflags2amode(int flags)
95 LONG openmode = 0;
97 /* filter out invalid modes */
98 switch (flags & (O_CREAT|O_TRUNC|O_EXCL))
100 case O_EXCL:
101 case O_EXCL|O_TRUNC:
102 return -1;
105 if (flags & O_WRITE) openmode |= FMF_WRITE;
106 if (flags & O_READ) openmode |= FMF_READ;
107 if (flags & O_EXEC) openmode |= FMF_EXECUTE;
108 if (flags & O_CREAT) openmode |= FMF_CREATE;
109 if (flags & O_NONBLOCK) openmode |= FMF_NONBLOCK;
110 if (flags & O_APPEND) openmode |= FMF_APPEND;
112 return openmode;
115 int __open(int wanted_fd, const char *pathname, int flags, int mode)
117 BPTR fh = BNULL, lock = BNULL;
118 fdesc *currdesc = NULL;
119 fcb *cblock = NULL;
120 struct FileInfoBlock *fib = NULL;
121 LONG openmode = __oflags2amode(flags);
123 if (__doupath && pathname[0] == '\0')
125 /* On *nix "" is not really a valid file name. */
126 errno = ENOENT;
127 return -1;
130 pathname = __path_u2a(pathname);
131 if (!pathname) return -1;
133 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd, pathname, flags, mode));
135 if (openmode == -1)
137 errno = EINVAL;
138 D(bug( "__open: exiting with error EINVAL\n"));
139 return -1;
142 cblock = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR);
143 if (!cblock) { D(bug("__open: no memory [1]\n")); goto err; }
144 currdesc = __alloc_fdesc();
145 if (!currdesc) { D(bug("__open: no memory [2]\n")); goto err; }
146 currdesc->fdflags = 0;
147 currdesc->fcb = cblock;
149 wanted_fd = __getfdslot(wanted_fd);
150 if (wanted_fd == -1) { D(bug("__open: no free fd\n")); goto err; }
152 lock = Lock((char *)pathname, SHARED_LOCK);
153 if (!lock)
155 if (IoErr() == ERROR_OBJECT_WRONG_TYPE)
158 Needed for sfs file system which reports this error number on a
159 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
161 errno = ENOTDIR;
162 goto err;
167 (IoErr() != ERROR_OBJECT_NOT_FOUND) ||
168 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
169 (IoErr() == ERROR_OBJECT_NOT_FOUND && !(flags & O_CREAT))
172 errno = IoErr2errno(IoErr());
173 goto err;
176 else
178 /* If the file exists, but O_EXCL is set, then return an error */
179 if (flags & O_EXCL)
181 errno = EEXIST;
182 goto err;
185 fib = AllocDosObject(DOS_FIB, NULL);
186 if (!fib)
188 errno = IoErr2errno(IoErr());
189 goto err;
192 if (!Examine(lock, fib))
195 The filesystem in which the file resides doesn't support
196 the EXAMINE action. It might be broken or might also not
197 be a filesystem at all. So let's assume the file is not a
198 diretory.
200 fib->fib_DirEntryType = 0;
203 /* FIXME: implement softlink handling */
205 /* Check if it's a directory or a softlink.
206 Softlinks are not handled yet, though */
207 if (fib->fib_DirEntryType > 0)
209 /* A directory cannot be opened for writing */
210 if (openmode & FMF_WRITE)
212 errno = EISDIR;
213 goto err;
216 fh = lock;
217 FreeDosObject(DOS_FIB, fib);
218 currdesc->fcb->isdir = 1;
220 goto success;
222 FreeDosObject(DOS_FIB, fib);
223 fib = NULL;
226 /* the file exists and it's not a directory or the file doesn't exist */
228 if (lock)
230 UnLock(lock);
231 lock = BNULL;
234 if (openmode & (FMF_APPEND | FMF_WRITE))
235 openmode |= FMF_READ; /* force filesystem ACTION_FINDUPDATE */
237 if (!(fh = Open ((char *)pathname, openmode)) )
239 ULONG ioerr = IoErr();
240 D(bug("[clib] Open ioerr=%d\n", ioerr));
241 errno = IoErr2errno(ioerr);
242 goto err;
245 if((flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)))
247 if(SetFileSize(fh, 0, OFFSET_BEGINNING) != 0)
249 /* Ignore error if FSA_SET_FILE_SIZE is not implemented */
250 if(IoErr() != ERROR_NOT_IMPLEMENTED)
252 errno = IoErr2errno(IoErr());
253 goto err;
258 success:
259 currdesc->fcb->fh = fh;
260 currdesc->fcb->flags = flags;
261 currdesc->fcb->opencount = 1;
263 __setfdesc(wanted_fd, currdesc);
265 D(bug("__open: exiting fd=%d\n", wanted_fd));
267 return wanted_fd;
269 err:
270 if (fib) FreeDosObject(DOS_FIB, fib);
271 if (cblock) FreeVec(cblock);
272 if (currdesc) __free_fdesc(currdesc);
273 if (fh && fh != lock) Close(fh);
274 if (lock) UnLock(lock);
276 D(bug("__open: exiting with error %d\n", errno ));
278 return -1;
281 fdesc *__alloc_fdesc(void)
283 fdesc * desc;
285 desc = AllocPooled(__fd_mempool, sizeof(fdesc));
287 D(bug("Allocated fdesc %x from %x pool\n", desc, __fd_mempool));
289 return desc;
292 void __free_fdesc(fdesc *desc)
294 D(bug("Freeing fdesc %x from %x pool\n", desc, __fd_mempool));
295 FreePooled(__fd_mempool, desc, sizeof(fdesc));
299 struct __reg_fdarray {
300 struct MinNode node;
301 struct Task *task;
302 fdesc **fdarray;
303 int numslots;
306 /* Some local variables for register_init_fdarray */
307 static int __fdinit = 0;
308 static struct SignalSemaphore __fdsem;
309 static struct MinList __fdreglist;
311 int __init_vars(void)
313 InitSemaphore(&__fdsem);
314 NEWLIST(&__fdreglist);
316 return TRUE;
319 int __register_init_fdarray(struct arosc_privdata *priv)
321 /* arosc privdata should not be used inside this function,
322 * this function is called before aroscbase is initialized
324 struct __reg_fdarray *regnode = AllocVec(sizeof(struct __reg_fdarray), MEMF_ANY|MEMF_CLEAR);
326 if (regnode == NULL)
327 return 0;
329 regnode->task = FindTask(NULL);
330 regnode->fdarray = priv->acpd_fd_array;
331 regnode->numslots = priv->acpd_numslots;
333 D(bug("Allocated regnode: %p, fdarray: %p, numslots: %d\n",
334 regnode, regnode->fdarray, regnode->numslots
337 ObtainSemaphore(&__fdsem);
338 AddHead((struct List *)&__fdreglist, (struct Node *)regnode);
339 ReleaseSemaphore(&__fdsem);
341 return 1;
344 /* FIXME: perhaps this has to be handled in a different way... */
345 int __init_stdfiles(void)
347 struct Process *me;
348 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
349 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
350 int res = __getfdslot(2);
354 res == -1 ||
355 !(infcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
356 !(indesc = __alloc_fdesc()) ||
357 !(outfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
358 !(outdesc = __alloc_fdesc()) ||
359 !(errfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
360 !(errdesc = __alloc_fdesc())
363 if(infcb)
364 FreeVec(infcb);
365 if(indesc)
366 __free_fdesc(indesc);
367 if(outfcb)
368 FreeVec(outfcb);
369 if(outdesc)
370 __free_fdesc(outdesc);
371 if(errfcb)
372 FreeVec(errfcb);
373 if(errdesc)
374 __free_fdesc(errdesc);
375 SetIoErr(ERROR_NO_FREE_STORE);
376 return 0;
379 indesc->fdflags = 0;
380 outdesc->fdflags = 0;
381 errdesc->fdflags = 0;
383 indesc->fcb = infcb;
384 outdesc->fcb = outfcb;
385 errdesc->fcb = errfcb;
387 me = (struct Process *)FindTask (NULL);
388 indesc->fcb->fh = Input();
389 outdesc->fcb->fh = Output();
390 errdesc->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
392 indesc->fcb->flags = O_RDONLY;
393 outdesc->fcb->flags = O_WRONLY | O_APPEND;
394 errdesc->fcb->flags = O_WRONLY | O_APPEND;
396 indesc->fcb->opencount = outdesc->fcb->opencount = errdesc->fcb->opencount = 1;
397 indesc->fcb->privflags = outdesc->fcb->privflags = errdesc->fcb->privflags = _FCB_DONTCLOSE_FH;
399 __fd_array[STDIN_FILENO] = indesc;
400 __fd_array[STDOUT_FILENO] = outdesc;
401 __fd_array[STDERR_FILENO] = errdesc;
403 return 1;
406 static int __copy_fdarray(fdesc **__src_fd_array, int numslots)
408 int i;
410 for(i = numslots - 1; i >= 0; i--)
412 if(__src_fd_array[i])
414 if(__getfdslot(i) != i)
415 return 0;
417 if((__fd_array[i] = __alloc_fdesc()) == NULL)
418 return 0;
420 __fd_array[i]->fdflags = __src_fd_array[i]->fdflags;
421 __fd_array[i]->fcb = __src_fd_array[i]->fcb;
422 __fd_array[i]->fcb->opencount++;
426 return 1;
429 int __init_fd(void)
431 struct __reg_fdarray *regnodeit, *regnode = NULL;
432 struct Task *self = FindTask(NULL);
434 if (!__fdinit)
436 __init_vars();
437 __fdinit = 1;
440 __fd_mempool = CreatePool(MEMF_PUBLIC, 16*sizeof(fdesc), 16*sizeof(fdesc));
442 ObtainSemaphore(&__fdsem);
443 ForeachNode(&__fdreglist, regnodeit)
445 if (regnodeit->task == self)
447 regnode = regnodeit;
449 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
450 regnode, regnode->fdarray, regnode->numslots
452 Remove((struct Node *)regnode);
453 break;
456 ReleaseSemaphore(&__fdsem);
458 if (regnode == NULL)
459 return __init_stdfiles();
460 else
462 int ok = __copy_fdarray(regnode->fdarray, regnode->numslots);
464 FreeVec(regnode);
466 return ok;
470 void __exit_fd(void)
472 int i = __numslots;
473 while (i)
475 if (__fd_array[--i])
476 close(i);
478 DeletePool(__fd_mempool);
481 #include <stdio.h>
483 void __updatestdio(void)
485 struct Process *me;
487 me = (struct Process *)FindTask(NULL);
489 fflush(stdin);
490 fflush(stdout);
491 fflush(stderr);
493 __fd_array[STDIN_FILENO]->fcb->fh = Input();
494 __fd_array[STDOUT_FILENO]->fcb->fh = Output();
495 __fd_array[STDERR_FILENO]->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
497 __fd_array[STDIN_FILENO]->fcb->privflags =
498 __fd_array[STDOUT_FILENO]->fcb->privflags =
499 __fd_array[STDERR_FILENO]->fcb->privflags = _FCB_DONTCLOSE_FH;
502 ADD2INIT(__init_fd, 2);
503 ADD2EXIT(__exit_fd, 2);