]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libc/misc/dirent/opendir.c
b43f60814795c293e6a6620d64c3c333eb14a433
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libc / misc / dirent / opendir.c
1 /*
2  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
3  *
4  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
5  */
6
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <sys/dir.h>
14 #include <sys/stat.h>
15 #include <dirent.h>
16 #include "dirstream.h"
17
18 static DIR *fd_to_DIR(int fd, __blksize_t size)
19 {
20         DIR *ptr;
21
22         ptr = malloc(sizeof(*ptr));
23         if (!ptr)
24                 return NULL;
25
26         ptr->dd_fd = fd;
27         ptr->dd_nextloc = ptr->dd_size = ptr->dd_nextoff = 0;
28         ptr->dd_max = size;
29         if (ptr->dd_max < 512)
30                 ptr->dd_max = 512;
31
32         ptr->dd_buf = calloc(1, ptr->dd_max);
33         if (!ptr->dd_buf) {
34                 free(ptr);
35                 return NULL;
36         }
37         __pthread_mutex_init(&ptr->dd_lock, NULL);
38
39         return ptr;
40 }
41
42 DIR *fdopendir(int fd)
43 {
44         int flags;
45         struct stat st;
46
47         if (fstat(fd, &st))
48                 return NULL;
49         if (!S_ISDIR(st.st_mode)) {
50                 __set_errno(ENOTDIR);
51                 return NULL;
52         }
53
54         flags = fcntl(fd, F_GETFL);
55         if (flags == -1)
56                 return NULL;
57         if ((flags & O_ACCMODE) == O_WRONLY) {
58                 __set_errno(EINVAL);
59                 return NULL;
60         }
61
62         return fd_to_DIR(fd, st.st_blksize);
63 }
64
65 /* opendir just makes an open() call - it return NULL if it fails
66  * (open sets errno), otherwise it returns a DIR * pointer.
67  */
68 DIR *opendir(const char *name)
69 {
70         int fd;
71         struct stat statbuf;
72         DIR *ptr;
73
74 #ifndef O_DIRECTORY
75         /* O_DIRECTORY is linux specific and has been around since like 2.1.x */
76         if (stat(name, &statbuf))
77                 return NULL;
78         if (!S_ISDIR(statbuf.st_mode)) {
79                 __set_errno(ENOTDIR);
80                 return NULL;
81         }
82 # define O_DIRECTORY 0
83 #endif
84         fd = open(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_CLOEXEC);
85         if (fd < 0)
86                 return NULL;
87         /* Note: we should check to make sure that between the stat() and open()
88          * call, 'name' didnt change on us, but that's only if O_DIRECTORY isnt
89          * defined and since Linux has supported it for like ever, i'm not going
90          * to worry about it right now (if ever). */
91
92         if (fstat(fd, &statbuf) < 0) {
93                 /* this close() never fails
94                  *int saved_errno;
95                  *saved_errno = errno; */
96                 close(fd);
97                 /*__set_errno(saved_errno);*/
98                 return NULL;
99         }
100
101         /* According to POSIX, directory streams should be closed when
102          * exec. From "Anna Pluzhnikov" <besp@midway.uchicago.edu>.
103          */
104 #ifndef __ASSUME_O_CLOEXEC
105         fcntl(fd, F_SETFD, FD_CLOEXEC);
106 #endif
107
108         ptr = fd_to_DIR(fd, statbuf.st_blksize);
109         if (!ptr) {
110                 close(fd);
111                 __set_errno(ENOMEM);
112         }
113         return ptr;
114 }
115 libc_hidden_def(opendir)