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