upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / file_io / unix / dir.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_arch_file_io.h"
18 #include "apr_strings.h"
19 #include "apr_portable.h"
20 #if APR_HAVE_SYS_SYSLIMITS_H
21 #include <sys/syslimits.h>
22 #endif
23 #if APR_HAVE_LIMITS_H
24 #include <limits.h>
25 #endif
26
27 static apr_status_t dir_cleanup(void *thedir)
28 {
29     apr_dir_t *dir = thedir;
30     if (closedir(dir->dirstruct) == 0) {
31         return APR_SUCCESS;
32     }
33     else {
34         return errno;
35     }
36
37
38 #define PATH_SEPARATOR '/'
39
40 /* Remove trailing separators that don't affect the meaning of PATH. */
41 static const char *path_canonicalize (const char *path, apr_pool_t *pool)
42 {
43     /* At some point this could eliminate redundant components.  For
44      * now, it just makes sure there is no trailing slash. */
45     apr_size_t len = strlen (path);
46     apr_size_t orig_len = len;
47     
48     while ((len > 0) && (path[len - 1] == PATH_SEPARATOR))
49         len--;
50     
51     if (len != orig_len)
52         return apr_pstrndup (pool, path, len);
53     else
54         return path;
55 }
56
57 /* Remove one component off the end of PATH. */
58 static char *path_remove_last_component (const char *path, apr_pool_t *pool)
59 {
60     const char *newpath = path_canonicalize (path, pool);
61     int i;
62     
63     for (i = (strlen(newpath) - 1); i >= 0; i--) {
64         if (path[i] == PATH_SEPARATOR)
65             break;
66     }
67
68     return apr_pstrndup (pool, path, (i < 0) ? 0 : i);
69 }
70
71 apr_status_t apr_dir_open(apr_dir_t **new, const char *dirname, 
72                           apr_pool_t *pool)
73 {
74     /* On some platforms (e.g., Linux+GNU libc), d_name[] in struct 
75      * dirent is declared with enough storage for the name.  On other
76      * platforms (e.g., Solaris 8 for Intel), d_name is declared as a
77      * one-byte array.  Note: gcc evaluates this at compile time.
78      */
79     apr_size_t dirent_size = 
80         (sizeof((*new)->entry->d_name) > 1 ? 
81          sizeof(struct dirent) : sizeof (struct dirent) + 255);
82
83     (*new) = (apr_dir_t *)apr_palloc(pool, sizeof(apr_dir_t));
84
85     (*new)->pool = pool;
86     (*new)->dirname = apr_pstrdup(pool, dirname);
87     (*new)->dirstruct = opendir(dirname);
88     (*new)->entry = apr_pcalloc(pool, dirent_size);
89
90     if ((*new)->dirstruct == NULL) {
91         return errno;
92     }    
93     else {
94         apr_pool_cleanup_register((*new)->pool, (void *)(*new), dir_cleanup,
95                                   apr_pool_cleanup_null);
96         return APR_SUCCESS;
97     }
98 }
99
100 apr_status_t apr_dir_close(apr_dir_t *thedir)
101 {
102     return apr_pool_cleanup_run(thedir->pool, thedir, dir_cleanup);
103 }
104
105 #ifdef DIRENT_TYPE
106 static apr_filetype_e filetype_from_dirent_type(int type)
107 {
108     switch (type) {
109     case DT_REG:
110         return APR_REG;
111     case DT_DIR:
112         return APR_DIR;
113     case DT_LNK:
114         return APR_LNK;
115     case DT_CHR:
116         return APR_CHR;
117     case DT_BLK:
118         return APR_BLK;
119 #if defined(DT_FIFO)
120     case DT_FIFO:
121         return APR_PIPE;
122 #endif
123 #if !defined(BEOS) && defined(DT_SOCK)
124     case DT_SOCK:
125         return APR_SOCK;
126 #endif
127     default:
128         return APR_UNKFILE;
129     }
130 }
131 #endif
132
133 apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
134                           apr_dir_t *thedir)
135 {
136     apr_status_t ret = 0;
137 #ifdef DIRENT_TYPE
138     apr_filetype_e type;
139 #endif
140 #if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \
141                     && !defined(READDIR_IS_THREAD_SAFE)
142     struct dirent *retent;
143
144     ret = readdir_r(thedir->dirstruct, thedir->entry, &retent);
145
146     /* Avoid the Linux problem where at end-of-directory thedir->entry
147      * is set to NULL, but ret = APR_SUCCESS.
148      */
149     if(!ret && thedir->entry != retent)
150         ret = APR_ENOENT;
151
152     /* Solaris is a bit strange, if there are no more entries in the
153      * directory, it returns EINVAL.  Since this is against POSIX, we
154      * hack around the problem here.  EINVAL is possible from other
155      * readdir implementations, but only if the result buffer is too small.
156      * since we control the size of that buffer, we should never have
157      * that problem.
158      */
159     if (ret == EINVAL) {
160         ret = ENOENT;
161     }
162 #else
163     /* We're about to call a non-thread-safe readdir() that may
164        possibly set `errno', and the logic below actually cares about
165        errno after the call.  Therefore we need to clear errno first. */
166     errno = 0;
167     thedir->entry = readdir(thedir->dirstruct);
168     if (thedir->entry == NULL) {
169         /* If NULL was returned, this can NEVER be a success. Can it?! */
170         if (errno == APR_SUCCESS) {
171             ret = APR_ENOENT;
172         }
173         else
174             ret = errno;
175     }
176 #endif
177
178     /* No valid bit flag to test here - do we want one? */
179     finfo->fname = NULL;
180
181     if (ret) {
182         finfo->valid = 0;
183         return ret;
184     }
185
186 #ifdef DIRENT_TYPE
187     type = filetype_from_dirent_type(thedir->entry->DIRENT_TYPE);
188     if (type != APR_UNKFILE) {
189         wanted &= ~APR_FINFO_TYPE;
190     }
191 #endif
192 #ifdef DIRENT_INODE
193     if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) {
194         wanted &= ~APR_FINFO_INODE;
195     }
196 #endif
197
198     wanted &= ~APR_FINFO_NAME;
199
200     if (wanted)
201     {
202         char fspec[APR_PATH_MAX];
203         int off;
204         apr_cpystrn(fspec, thedir->dirname, sizeof(fspec));
205         off = strlen(fspec);
206         if ((fspec[off - 1] != '/') && (off + 1 < sizeof(fspec)))
207             fspec[off++] = '/';
208         apr_cpystrn(fspec + off, thedir->entry->d_name, sizeof(fspec) - off);
209         ret = apr_lstat(finfo, fspec, wanted, thedir->pool);
210         /* We passed a stack name that will disappear */
211         finfo->fname = NULL;
212     }
213
214     if (wanted && (ret == APR_SUCCESS || ret == APR_INCOMPLETE)) {
215         wanted &= ~finfo->valid;
216     }
217     else {
218         /* We don't bail because we fail to stat, when we are only -required-
219          * to readdir... but the result will be APR_INCOMPLETE
220          */
221         finfo->pool = thedir->pool;
222         finfo->valid = 0;
223 #ifdef DIRENT_TYPE
224         if (type != APR_UNKFILE) {
225             finfo->filetype = type;
226             finfo->valid |= APR_FINFO_TYPE;
227         }
228 #endif
229 #ifdef DIRENT_INODE
230         if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) {
231             finfo->inode = thedir->entry->DIRENT_INODE;
232             finfo->valid |= APR_FINFO_INODE;
233         }
234 #endif
235     }
236
237     finfo->name = apr_pstrdup(thedir->pool, thedir->entry->d_name);
238     finfo->valid |= APR_FINFO_NAME;
239
240     if (wanted)
241         return APR_INCOMPLETE;
242
243     return APR_SUCCESS;
244 }
245
246 apr_status_t apr_dir_rewind(apr_dir_t *thedir)
247 {
248     rewinddir(thedir->dirstruct);
249     return APR_SUCCESS;
250 }
251
252 apr_status_t apr_dir_make(const char *path, apr_fileperms_t perm, 
253                           apr_pool_t *pool)
254 {
255     mode_t mode = apr_unix_perms2mode(perm);
256
257     if (mkdir(path, mode) == 0) {
258         return APR_SUCCESS;
259     }
260     else {
261         return errno;
262     }
263 }
264
265 apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm,
266                                            apr_pool_t *pool) 
267 {
268     apr_status_t apr_err = 0;
269     
270     apr_err = apr_dir_make (path, perm, pool); /* Try to make PATH right out */
271     
272     if (apr_err == EEXIST) /* It's OK if PATH exists */
273         return APR_SUCCESS;
274     
275     if (apr_err == ENOENT) { /* Missing an intermediate dir */
276         char *dir;
277         
278         dir = path_remove_last_component(path, pool);
279         /* If there is no path left, give up. */
280         if (dir[0] == '\0') {
281             return apr_err;
282         }
283
284         apr_err = apr_dir_make_recursive(dir, perm, pool);
285         
286         if (!apr_err) 
287             apr_err = apr_dir_make (path, perm, pool);
288     }
289
290     return apr_err;
291 }
292
293 apr_status_t apr_dir_remove(const char *path, apr_pool_t *pool)
294 {
295     if (rmdir(path) == 0) {
296         return APR_SUCCESS;
297     }
298     else {
299         return errno;
300     }
301 }
302
303 apr_status_t apr_os_dir_get(apr_os_dir_t **thedir, apr_dir_t *dir)
304 {
305     if (dir == NULL) {
306         return APR_ENODIR;
307     }
308     *thedir = dir->dirstruct;
309     return APR_SUCCESS;
310 }
311
312 apr_status_t apr_os_dir_put(apr_dir_t **dir, apr_os_dir_t *thedir,
313                           apr_pool_t *pool)
314 {
315     if ((*dir) == NULL) {
316         (*dir) = (apr_dir_t *)apr_pcalloc(pool, sizeof(apr_dir_t));
317         (*dir)->pool = pool;
318     }
319     (*dir)->dirstruct = thedir;
320     return APR_SUCCESS;
321 }
322
323