bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / file_io / netware / filestat.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 "fsio.h"
19 #include "nks/dirio.h"
20 #include "apr_file_io.h"
21 #include "apr_general.h"
22 #include "apr_strings.h"
23 #include "apr_errno.h"
24 #include "apr_hash.h"
25 #include "apr_thread_rwlock.h"
26
27 #ifdef HAVE_UTIME_H
28 #include <utime.h>
29 #endif
30
31 #define APR_HAS_PSA
32
33 static apr_filetype_e filetype_from_mode(mode_t mode)
34 {
35     apr_filetype_e type = APR_NOFILE;
36
37     if (S_ISREG(mode))
38         type = APR_REG;
39     else if (S_ISDIR(mode))
40         type = APR_DIR;
41     else if (S_ISCHR(mode))
42         type = APR_CHR;
43     else if (S_ISBLK(mode))
44         type = APR_BLK;
45     else if (S_ISFIFO(mode))
46         type = APR_PIPE;
47     else if (S_ISLNK(mode))
48         type = APR_LNK;
49     else if (S_ISSOCK(mode))
50         type = APR_SOCK;
51     else
52         type = APR_UNKFILE;
53     return type;
54 }
55
56 static void fill_out_finfo(apr_finfo_t *finfo, struct stat *info,
57                            apr_int32_t wanted)
58
59     finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK 
60                     | APR_FINFO_OWNER | APR_FINFO_PROT;
61     finfo->protection = apr_unix_mode2perms(info->st_mode);
62     finfo->filetype = filetype_from_mode(info->st_mode);
63     finfo->user = info->st_uid;
64     finfo->group = info->st_gid;
65     finfo->size = info->st_size;
66     finfo->inode = info->st_ino;
67     finfo->device = info->st_dev;
68     finfo->nlink = info->st_nlink;
69     apr_time_ansi_put(&finfo->atime, info->st_atime.tv_sec);
70     apr_time_ansi_put(&finfo->mtime, info->st_mtime.tv_sec);
71     apr_time_ansi_put(&finfo->ctime, info->st_ctime.tv_sec);
72     /* ### needs to be revisited  
73      * if (wanted & APR_FINFO_CSIZE) {
74      *   finfo->csize = info->st_blocks * 512;
75      *   finfo->valid |= APR_FINFO_CSIZE;
76      * }
77      */
78 }
79
80 apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, 
81                                       apr_int32_t wanted,
82                                       apr_file_t *thefile)
83 {
84     struct stat info;
85
86     if (thefile->buffered) {
87         apr_status_t rv = apr_file_flush_locked(thefile);
88         if (rv != APR_SUCCESS)
89             return rv;
90     }
91
92     if (fstat(thefile->filedes, &info) == 0) {
93         finfo->pool = thefile->pool;
94         finfo->fname = thefile->fname;
95         fill_out_finfo(finfo, &info, wanted);
96         return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
97     }
98     else {
99         return errno;
100     }
101 }
102
103 APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, 
104                                             apr_int32_t wanted,
105                                             apr_file_t *thefile)
106 {
107     struct stat info;
108
109     if (thefile->buffered) {
110         apr_status_t rv = apr_file_flush(thefile);
111         if (rv != APR_SUCCESS)
112             return rv;
113     }
114
115     if (fstat(thefile->filedes, &info) == 0) {
116         finfo->pool = thefile->pool;
117         finfo->fname = thefile->fname;
118         fill_out_finfo(finfo, &info, wanted);
119         return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
120     }
121     else {
122         return errno;
123     }
124 }
125
126 APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, 
127                                              apr_fileperms_t perms)
128 {
129     mode_t mode = apr_unix_perms2mode(perms);
130
131     if (chmod(fname, mode) == -1)
132         return errno;
133     return APR_SUCCESS;
134 }
135
136 APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname,
137                                              apr_fileattrs_t attributes,
138                                              apr_fileattrs_t attr_mask,
139                                              apr_pool_t *pool)
140 {
141     apr_status_t status;
142     apr_finfo_t finfo;
143
144     /* Don't do anything if we can't handle the requested attributes */
145     if (!(attr_mask & (APR_FILE_ATTR_READONLY
146                        | APR_FILE_ATTR_EXECUTABLE)))
147         return APR_SUCCESS;
148
149     status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool);
150     if (!APR_STATUS_IS_SUCCESS(status))
151         return status;
152
153     /* ### TODO: should added bits be umask'd? */
154     if (attr_mask & APR_FILE_ATTR_READONLY)
155     {
156         if (attributes & APR_FILE_ATTR_READONLY)
157         {
158             finfo.protection &= ~APR_UWRITE;
159             finfo.protection &= ~APR_GWRITE;
160             finfo.protection &= ~APR_WWRITE;
161         }
162         else
163         {
164             /* ### umask this! */
165             finfo.protection |= APR_UWRITE;
166             finfo.protection |= APR_GWRITE;
167             finfo.protection |= APR_WWRITE;
168         }
169     }
170
171     if (attr_mask & APR_FILE_ATTR_EXECUTABLE)
172     {
173         if (attributes & APR_FILE_ATTR_EXECUTABLE)
174         {
175             /* ### umask this! */
176             finfo.protection |= APR_UEXECUTE;
177             finfo.protection |= APR_GEXECUTE;
178             finfo.protection |= APR_WEXECUTE;
179         }
180         else
181         {
182             finfo.protection &= ~APR_UEXECUTE;
183             finfo.protection &= ~APR_GEXECUTE;
184             finfo.protection &= ~APR_WEXECUTE;
185         }
186     }
187
188     return apr_file_perms_set(fname, finfo.protection);
189 }
190
191 #ifndef APR_HAS_PSA
192 static apr_status_t stat_cache_cleanup(void *data)
193 {
194     apr_pool_t *p = (apr_pool_t *)getGlobalPool();
195     apr_hash_index_t *hi;
196     apr_hash_t *statCache = (apr_hash_t*)data;
197         char *key;
198     apr_ssize_t keylen;
199     NXPathCtx_t pathctx;
200
201     for (hi = apr_hash_first(p, statCache); hi; hi = apr_hash_next(hi)) {
202         apr_hash_this(hi, (const void**)&key, &keylen, (void**)&pathctx);
203
204         if (pathctx) {
205             NXFreePathContext(pathctx);
206         }
207     }
208
209     return APR_SUCCESS;
210 }
211
212 int cstat (NXPathCtx_t ctx, char *path, struct stat *buf, unsigned long requestmap, apr_pool_t *p)
213 {
214     apr_pool_t *gPool = (apr_pool_t *)getGlobalPool();
215     apr_hash_t *statCache = NULL;
216     apr_thread_rwlock_t *rwlock = NULL;
217
218     NXPathCtx_t pathctx = 0;
219     char *ptr = NULL, *tr;
220     int len = 0, x;
221     char *ppath;
222     char *pinfo;
223
224     if (ctx == 1) {
225
226         /* If there isn't a global pool then just stat the file
227            and return */
228         if (!gPool) {
229             char poolname[50];
230     
231             if (apr_pool_create(&gPool, NULL) != APR_SUCCESS) {
232                 return getstat(ctx, path, buf, requestmap);
233             }
234     
235             setGlobalPool(gPool);
236             apr_pool_tag(gPool, apr_pstrdup(gPool, "cstat_mem_pool"));
237     
238             statCache = apr_hash_make(gPool);
239             apr_pool_userdata_set ((void*)statCache, "STAT_CACHE", stat_cache_cleanup, gPool);
240
241             apr_thread_rwlock_create(&rwlock, gPool);
242             apr_pool_userdata_set ((void*)rwlock, "STAT_CACHE_LOCK", apr_pool_cleanup_null, gPool);
243         }
244         else {
245             apr_pool_userdata_get((void**)&statCache, "STAT_CACHE", gPool);
246             apr_pool_userdata_get((void**)&rwlock, "STAT_CACHE_LOCK", gPool);
247         }
248
249         if (!gPool || !statCache || !rwlock) {
250             return getstat(ctx, path, buf, requestmap);
251         }
252     
253         for (x = 0,tr = path;*tr != '\0';tr++,x++) {
254             if (*tr == '\\' || *tr == '/') {
255                 ptr = tr;
256                 len = x;
257             }
258             if (*tr == ':') {
259                 ptr = "\\";
260                 len = x;
261             }
262         }
263     
264         if (ptr) {
265             ppath = apr_pstrndup (p, path, len);
266             strlwr(ppath);
267             if (ptr[1] != '\0') {
268                 ptr++;
269             }
270             /* If the path ended in a trailing slash then our result path
271                will be a single slash. To avoid stat'ing the root with a
272                slash, we need to make sure we stat the current directory
273                with a dot */
274             if (((*ptr == '/') || (*ptr == '\\')) && (*(ptr+1) == '\0')) {
275                 pinfo = apr_pstrdup (p, ".");
276             }
277             else {
278                 pinfo = apr_pstrdup (p, ptr);
279             }
280         }
281     
282         /* If we have a statCache then try to pull the information
283            from the cache.  Otherwise just stat the file and return.*/
284         if (statCache) {
285             apr_thread_rwlock_rdlock(rwlock);
286             pathctx = (NXPathCtx_t) apr_hash_get(statCache, ppath, APR_HASH_KEY_STRING);
287             apr_thread_rwlock_unlock(rwlock);
288             if (pathctx) {
289                 return getstat(pathctx, pinfo, buf, requestmap);
290             }
291             else {
292                 int err;
293
294                 err = NXCreatePathContext(0, ppath, 0, NULL, &pathctx);
295                 if (!err) {
296                     apr_thread_rwlock_wrlock(rwlock);
297                     apr_hash_set(statCache, apr_pstrdup(gPool,ppath) , APR_HASH_KEY_STRING, (void*)pathctx);
298                     apr_thread_rwlock_unlock(rwlock);
299                     return getstat(pathctx, pinfo, buf, requestmap);
300                 }
301             }
302         }
303     }
304     return getstat(ctx, path, buf, requestmap);
305 }
306 #endif
307
308 APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, 
309                                    const char *fname, 
310                                    apr_int32_t wanted, apr_pool_t *pool)
311 {
312     struct stat info;
313     int srv;
314     NXPathCtx_t pathCtx = 0;
315
316     getcwdpath(NULL, &pathCtx, CTX_ACTUAL_CWD);
317 #ifdef APR_HAS_PSA
318         srv = getstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT);
319 #else
320     srv = cstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT, pool);
321 #endif
322     errno = srv;
323
324     if (srv == 0) {
325         finfo->pool = pool;
326         finfo->fname = fname;
327         fill_out_finfo(finfo, &info, wanted);
328         if (wanted & APR_FINFO_LINK)
329             wanted &= ~APR_FINFO_LINK;
330         if (wanted & APR_FINFO_NAME) {
331             finfo->name = apr_pstrdup(pool, info.st_name);
332             finfo->valid |= APR_FINFO_NAME;
333         }
334         return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
335     }
336     else {
337 #if !defined(ENOENT) || !defined(ENOTDIR)
338 #error ENOENT || ENOTDIR not defined; please see the
339 #error comments at this line in the source for a workaround.
340         /*
341          * If ENOENT || ENOTDIR is not defined in one of the your OS's
342          * include files, APR cannot report a good reason why the stat()
343          * of the file failed; there are cases where it can fail even though
344          * the file exists.  This opens holes in Apache, for example, because
345          * it becomes possible for someone to get a directory listing of a 
346          * directory even though there is an index (eg. index.html) file in 
347          * it.  If you do not have a problem with this, delete the above 
348          * #error lines and start the compile again.  If you need to do this,
349          * please submit a bug report to http://www.apache.org/bug_report.html
350          * letting us know that you needed to do this.  Please be sure to 
351          * include the operating system you are using.
352          */
353         /* WARNING: All errors will be handled as not found
354          */
355 #if !defined(ENOENT) 
356         return APR_ENOENT;
357 #else
358         /* WARNING: All errors but not found will be handled as not directory
359          */
360         if (errno != ENOENT)
361             return APR_ENOENT;
362         else
363             return errno;
364 #endif
365 #else /* All was defined well, report the usual: */
366         return errno;
367 #endif
368     }
369 }
370
371 /* Perhaps this becomes nothing but a macro?
372  */
373 APR_DECLARE(apr_status_t) apr_lstat(apr_finfo_t *finfo, const char *fname,
374                       apr_int32_t wanted, apr_pool_t *pool)
375 {
376     return apr_stat(finfo, fname, wanted | APR_FINFO_LINK, pool);
377 }
378
379
380 APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
381                                               apr_time_t mtime,
382                                               apr_pool_t *pool)
383 {
384     apr_status_t status;
385     apr_finfo_t finfo;
386
387     status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
388     if (!APR_STATUS_IS_SUCCESS(status)) {
389         return status;
390     }
391
392 #ifdef HAVE_UTIMES
393     {
394       struct timeval tvp[2];
395     
396       tvp[0].tv_sec = apr_time_sec(finfo.atime);
397       tvp[0].tv_usec = apr_time_usec(finfo.atime);
398       tvp[1].tv_sec = apr_time_sec(mtime);
399       tvp[1].tv_usec = apr_time_usec(mtime);
400       
401       if (utimes(fname, tvp) == -1) {
402         return errno;
403       }
404     }
405 #elif defined(HAVE_UTIME)
406     {
407       struct utimbuf buf;
408       
409       buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC);
410       buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC);
411       
412       if (utime(fname, &buf) == -1) {
413         return errno;
414       }
415     }
416 #else
417     return APR_ENOTIMPL;
418 #endif
419
420     return APR_SUCCESS;
421 }