define __KERNEL_STRICT_NAMES to avoid inclusion of kernel types on systems that carry...
[cake.git] / compiler / clib / __open.c
blob96ce0e3994805b471ec4474a1c36829ebd8d8f95
1 /*
2 Copyright © 1995-2009, 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 "__open.h"
28 #include "__upath.h"
31 fdesc *__getfdesc(register int fd)
33 return ((__numslots>fd) && (fd>=0))?__fd_array[fd]:NULL;
36 void __setfdesc(register int fd, fdesc *desc)
38 /* FIXME: Check if fd is in valid range... */
39 __fd_array[fd] = desc;
42 int __getfirstfd(register int startfd)
44 /* FIXME: Check if fd is in valid range... */
45 for (
47 startfd < __numslots && __fd_array[startfd];
48 startfd++
51 return startfd;
54 int __getfdslot(int wanted_fd)
56 if (wanted_fd>=__numslots)
58 void *tmp;
60 tmp = malloc((wanted_fd+1)*sizeof(fdesc *));
62 if (!tmp) return -1;
64 if (__fd_array)
66 CopyMem(__fd_array, tmp, __numslots*sizeof(fdesc *));
67 free(__fd_array);
70 __fd_array = tmp;
72 bzero(__fd_array + __numslots, (wanted_fd - __numslots + 1) * sizeof(fdesc *));
73 __numslots = wanted_fd+1;
75 else if (wanted_fd < 0)
77 errno = EINVAL;
78 return -1;
80 else if (__fd_array[wanted_fd])
82 close(wanted_fd);
85 return wanted_fd;
88 LONG __oflags2amode(int flags)
90 LONG openmode = 0;
92 /* filter out invalid modes */
93 switch (flags & (O_CREAT|O_TRUNC|O_EXCL))
95 case O_EXCL:
96 case O_EXCL|O_TRUNC:
97 return -1;
100 if (flags & O_WRITE) openmode |= FMF_WRITE;
101 if (flags & O_READ) openmode |= FMF_READ;
102 if (flags & O_EXEC) openmode |= FMF_EXECUTE;
103 if (flags & O_CREAT) openmode |= FMF_CREATE;
104 if (flags & O_NONBLOCK) openmode |= FMF_NONBLOCK;
105 if (flags & O_APPEND) openmode |= FMF_APPEND;
107 return openmode;
110 int __open(int wanted_fd, const char *pathname, int flags, int mode)
112 BPTR fh = NULL, lock = NULL;
113 fdesc *currdesc = NULL;
114 fcb *cblock = NULL;
115 struct FileInfoBlock *fib = NULL;
116 LONG openmode = __oflags2amode(flags);
118 if (__doupath && pathname[0] == '\0')
120 /* On *nix "" is not really a valid file name. */
121 errno = ENOENT;
122 return -1;
125 pathname = __path_u2a(pathname);
126 if (!pathname) return -1;
128 D(bug("__open: entering, wanted fd = %d, path = %s, flags = %d, mode = %d\n", wanted_fd, pathname, flags, mode));
130 if (openmode == -1)
132 errno = EINVAL;
133 D(bug( "__open: exiting with error EINVAL\n"));
134 return -1;
137 cblock = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR);
138 if (!cblock) { D(bug("__open: no memory [1]\n")); goto err; }
139 currdesc = __alloc_fdesc();
140 if (!currdesc) { D(bug("__open: no memory [2]\n")); goto err; }
141 currdesc->fdflags = 0;
142 currdesc->fcb = cblock;
144 wanted_fd = __getfdslot(wanted_fd);
145 if (wanted_fd == -1) { D(bug("__open: no free fd\n")); goto err; }
147 lock = Lock((char *)pathname, SHARED_LOCK);
148 if (!lock)
150 if (IoErr() == ERROR_OBJECT_WRONG_TYPE)
153 Needed for sfs file system which reports this error number on a
154 Lock aaa/bbb/ccc with bbb being a file instead of a directory.
156 errno = ENOTDIR;
157 goto err;
162 (IoErr() != ERROR_OBJECT_NOT_FOUND) ||
163 /* If the file doesn't exist and the flag O_CREAT is not set return an error */
164 (IoErr() == ERROR_OBJECT_NOT_FOUND && !(flags & O_CREAT))
167 errno = IoErr2errno(IoErr());
168 goto err;
171 else
173 /* If the file exists, but O_EXCL is set, then return an error */
174 if (flags & O_EXCL)
176 errno = EEXIST;
177 goto err;
180 fib = AllocDosObject(DOS_FIB, NULL);
181 if (!fib)
183 errno = IoErr2errno(IoErr());
184 goto err;
187 if (!Examine(lock, fib))
190 The filesystem in which the file resides doesn't support
191 the EXAMINE action. It might be broken or might also not
192 be a filesystem at all. So let's assume the file is not a
193 diretory.
195 fib->fib_DirEntryType = 0;
198 # warning implement softlink handling
200 /* Check if it's a directory or a softlink.
201 Softlinks are not handled yet, though */
202 if (fib->fib_DirEntryType > 0)
204 /* A directory cannot be opened for writing */
205 if (openmode & FMF_WRITE)
207 errno = EISDIR;
208 goto err;
211 fh = lock;
212 FreeDosObject(DOS_FIB, fib);
213 currdesc->fcb->isdir = 1;
215 goto success;
217 FreeDosObject(DOS_FIB, fib);
218 fib = NULL;
221 /* the file exists and it's not a directory or the file doesn't exist */
223 if (lock)
225 UnLock(lock);
226 lock = NULL;
229 if (openmode & (FMF_APPEND | FMF_WRITE))
230 openmode |= FMF_READ; /* force filesystem ACTION_FINDUPDATE */
232 if (!(fh = Open ((char *)pathname, openmode)) )
234 ULONG ioerr = IoErr();
235 D(bug("[clib] Open ioerr=%d\n", ioerr));
236 errno = IoErr2errno(ioerr);
237 goto err;
240 if((flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)))
242 if(SetFileSize(fh, 0, OFFSET_BEGINNING) != 0)
244 /* Ignore error if FSA_SET_FILE_SIZE is not implemented */
245 if(IoErr() != ERROR_NOT_IMPLEMENTED)
247 errno = IoErr2errno(IoErr());
248 goto err;
253 success:
254 currdesc->fcb->fh = fh;
255 currdesc->fcb->flags = flags;
256 currdesc->fcb->opencount = 1;
258 __setfdesc(wanted_fd, currdesc);
260 D(bug("__open: exiting fd=%d\n", wanted_fd));
262 return wanted_fd;
264 err:
265 if (fib) FreeDosObject(DOS_FIB, fib);
266 if (cblock) FreeVec(cblock);
267 if (currdesc) __free_fdesc(currdesc);
268 if (fh && fh != lock) Close(fh);
269 if (lock) UnLock(lock);
271 D(bug("__open: exiting with error %d\n", errno ));
273 return -1;
276 fdesc *__alloc_fdesc(void)
278 fdesc * desc;
280 desc = AllocPooled(__fd_mempool, sizeof(fdesc));
282 D(bug("Allocated fdesc %x from %x pool\n", desc, __fd_mempool));
284 return desc;
287 void __free_fdesc(fdesc *desc)
289 D(bug("Freeing fdesc %x from %x pool\n", desc, __fd_mempool));
290 FreePooled(__fd_mempool, desc, sizeof(fdesc));
294 struct __reg_fdarray {
295 struct MinNode node;
296 struct Task *task;
297 fdesc **fdarray;
298 int numslots;
301 /* Some local variables for register_init_fdarray */
302 static int __fdinit = 0;
303 static struct SignalSemaphore __fdsem;
304 static struct MinList __fdreglist;
306 int __init_vars(void)
308 InitSemaphore(&__fdsem);
309 NEWLIST(&__fdreglist);
311 return TRUE;
314 int __register_init_fdarray(fdesc **__fdarray, int numslots)
316 /* arosc privdata should not be used inside this function,
317 * this function is called before aroscbase is initialized
319 struct __reg_fdarray *regnode = AllocVec(sizeof(struct __reg_fdarray), MEMF_ANY|MEMF_CLEAR);
321 if (regnode == NULL)
322 return 0;
324 regnode->task = FindTask(NULL);
325 regnode->fdarray = __fdarray;
326 regnode->numslots = numslots;
328 D(bug("Allocated regnode: %p, fdarray: %p, numslots: %d\n",
329 regnode, regnode->fdarray, regnode->numslots
332 ObtainSemaphore(&__fdsem);
333 AddHead((struct List *)&__fdreglist, (struct Node *)regnode);
334 ReleaseSemaphore(&__fdsem);
336 return 1;
340 #warning perhaps this has to be handled in a different way...
341 int __init_stdfiles(void)
343 struct Process *me;
344 fcb *infcb = NULL, *outfcb = NULL, *errfcb = NULL;
345 fdesc *indesc=NULL, *outdesc=NULL, *errdesc=NULL;
346 int res = __getfdslot(2);
350 res == -1 ||
351 !(infcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
352 !(indesc = __alloc_fdesc()) ||
353 !(outfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
354 !(outdesc = __alloc_fdesc()) ||
355 !(errfcb = AllocVec(sizeof(fcb), MEMF_ANY | MEMF_CLEAR)) ||
356 !(errdesc = __alloc_fdesc())
359 if(infcb)
360 FreeVec(infcb);
361 if(indesc)
362 __free_fdesc(indesc);
363 if(outfcb)
364 FreeVec(outfcb);
365 if(outdesc)
366 __free_fdesc(outdesc);
367 if(errfcb)
368 FreeVec(errfcb);
369 if(errdesc)
370 __free_fdesc(errdesc);
371 SetIoErr(ERROR_NO_FREE_STORE);
372 return 0;
375 indesc->fdflags = 0;
376 outdesc->fdflags = 0;
377 errdesc->fdflags = 0;
379 indesc->fcb = infcb;
380 outdesc->fcb = outfcb;
381 errdesc->fcb = errfcb;
383 me = (struct Process *)FindTask (NULL);
384 indesc->fcb->fh = Input();
385 outdesc->fcb->fh = Output();
386 errdesc->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
388 indesc->fcb->flags = O_RDONLY;
389 outdesc->fcb->flags = O_WRONLY | O_APPEND;
390 errdesc->fcb->flags = O_WRONLY | O_APPEND;
392 indesc->fcb->opencount = outdesc->fcb->opencount = errdesc->fcb->opencount = 1;
393 indesc->fcb->privflags = outdesc->fcb->privflags = errdesc->fcb->privflags = _FCB_DONTCLOSE_FH;
395 __fd_array[STDIN_FILENO] = indesc;
396 __fd_array[STDOUT_FILENO] = outdesc;
397 __fd_array[STDERR_FILENO] = errdesc;
399 return 1;
402 static int __copy_fdarray(fdesc **__src_fd_array, int numslots)
404 int i;
406 for(i = numslots - 1; i >= 0; i--)
408 if(__src_fd_array[i])
410 if(__getfdslot(i) != i)
411 return 0;
413 if((__fd_array[i] = __alloc_fdesc()) == NULL)
414 return 0;
416 __fd_array[i]->fdflags = 0;
417 __fd_array[i]->fcb = __src_fd_array[i]->fcb;
418 __fd_array[i]->fcb->opencount++;
422 return 1;
425 int __init_fd(void)
427 struct __reg_fdarray *regnodeit, *regnode = NULL;
428 struct Task *self = FindTask(NULL);
430 if (!__fdinit)
432 __init_vars();
433 __fdinit = 1;
436 __fd_mempool = CreatePool(MEMF_PUBLIC, 16*sizeof(fdesc), 16*sizeof(fdesc));
438 ObtainSemaphore(&__fdsem);
439 ForeachNode(&__fdreglist, regnodeit)
441 if (regnodeit->task == self)
443 regnode = regnodeit;
445 D(bug("Found regnode: %p, fdarray: %p, numslots: %d\n",
446 regnode, regnode->fdarray, regnode->numslots
448 Remove((struct Node *)regnode);
449 break;
452 ReleaseSemaphore(&__fdsem);
454 if (regnode == NULL)
455 return __init_stdfiles();
456 else
458 int ok = __copy_fdarray(regnode->fdarray, regnode->numslots);
460 FreeVec(regnode);
462 return ok;
466 void __exit_fd(void)
468 int i = __numslots;
469 while (i)
471 if (__fd_array[--i])
472 close(i);
474 DeletePool(__fd_mempool);
477 #include <stdio.h>
479 void __updatestdio(void)
481 struct Process *me;
483 me = (struct Process *)FindTask(NULL);
485 fflush(stdin);
486 fflush(stdout);
487 fflush(stderr);
489 __fd_array[STDIN_FILENO]->fcb->fh = Input();
490 __fd_array[STDOUT_FILENO]->fcb->fh = Output();
491 __fd_array[STDERR_FILENO]->fcb->fh = me->pr_CES ? me->pr_CES : me->pr_COS;
493 __fd_array[STDIN_FILENO]->fcb->privflags =
494 __fd_array[STDOUT_FILENO]->fcb->privflags =
495 __fd_array[STDERR_FILENO]->fcb->privflags = _FCB_DONTCLOSE_FH;
498 ADD2INIT(__init_fd, 2);
499 ADD2EXIT(__exit_fd, 2);