~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr/file_io/netware/filestat.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
 
2
 * applicable.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * 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_DECLARE(apr_status_t) apr_file_info_get(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(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_perms_set(const char *fname, 
 
104
                                             apr_fileperms_t perms)
 
105
{
 
106
    mode_t mode = apr_unix_perms2mode(perms);
 
107
 
 
108
    if (chmod(fname, mode) == -1)
 
109
        return errno;
 
110
    return APR_SUCCESS;
 
111
}
 
112
 
 
113
APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname,
 
114
                                             apr_fileattrs_t attributes,
 
115
                                             apr_fileattrs_t attr_mask,
 
116
                                             apr_pool_t *pool)
 
117
{
 
118
    apr_status_t status;
 
119
    apr_finfo_t finfo;
 
120
 
 
121
    /* Don't do anything if we can't handle the requested attributes */
 
122
    if (!(attr_mask & (APR_FILE_ATTR_READONLY
 
123
                       | APR_FILE_ATTR_EXECUTABLE)))
 
124
        return APR_SUCCESS;
 
125
 
 
126
    status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool);
 
127
    if (status)
 
128
        return status;
 
129
 
 
130
    /* ### TODO: should added bits be umask'd? */
 
131
    if (attr_mask & APR_FILE_ATTR_READONLY)
 
132
    {
 
133
        if (attributes & APR_FILE_ATTR_READONLY)
 
134
        {
 
135
            finfo.protection &= ~APR_UWRITE;
 
136
            finfo.protection &= ~APR_GWRITE;
 
137
            finfo.protection &= ~APR_WWRITE;
 
138
        }
 
139
        else
 
140
        {
 
141
            /* ### umask this! */
 
142
            finfo.protection |= APR_UWRITE;
 
143
            finfo.protection |= APR_GWRITE;
 
144
            finfo.protection |= APR_WWRITE;
 
145
        }
 
146
    }
 
147
 
 
148
    if (attr_mask & APR_FILE_ATTR_EXECUTABLE)
 
149
    {
 
150
        if (attributes & APR_FILE_ATTR_EXECUTABLE)
 
151
        {
 
152
            /* ### umask this! */
 
153
            finfo.protection |= APR_UEXECUTE;
 
154
            finfo.protection |= APR_GEXECUTE;
 
155
            finfo.protection |= APR_WEXECUTE;
 
156
        }
 
157
        else
 
158
        {
 
159
            finfo.protection &= ~APR_UEXECUTE;
 
160
            finfo.protection &= ~APR_GEXECUTE;
 
161
            finfo.protection &= ~APR_WEXECUTE;
 
162
        }
 
163
    }
 
164
 
 
165
    return apr_file_perms_set(fname, finfo.protection);
 
166
}
 
167
 
 
168
#ifndef APR_HAS_PSA
 
169
static apr_status_t stat_cache_cleanup(void *data)
 
170
{
 
171
    apr_pool_t *p = (apr_pool_t *)getGlobalPool();
 
172
    apr_hash_index_t *hi;
 
173
    apr_hash_t *statCache = (apr_hash_t*)data;
 
174
        char *key;
 
175
    apr_ssize_t keylen;
 
176
    NXPathCtx_t pathctx;
 
177
 
 
178
    for (hi = apr_hash_first(p, statCache); hi; hi = apr_hash_next(hi)) {
 
179
        apr_hash_this(hi, (const void**)&key, &keylen, (void**)&pathctx);
 
180
 
 
181
        if (pathctx) {
 
182
            NXFreePathContext(pathctx);
 
183
        }
 
184
    }
 
185
 
 
186
    return APR_SUCCESS;
 
187
}
 
188
 
 
189
int cstat (NXPathCtx_t ctx, char *path, struct stat *buf, unsigned long requestmap, apr_pool_t *p)
 
190
{
 
191
    apr_pool_t *gPool = (apr_pool_t *)getGlobalPool();
 
192
    apr_hash_t *statCache = NULL;
 
193
    apr_thread_rwlock_t *rwlock = NULL;
 
194
 
 
195
    NXPathCtx_t pathctx = 0;
 
196
    char *ptr = NULL, *tr;
 
197
    int len = 0, x;
 
198
    char *ppath;
 
199
    char *pinfo;
 
200
 
 
201
    if (ctx == 1) {
 
202
 
 
203
        /* If there isn't a global pool then just stat the file
 
204
           and return */
 
205
        if (!gPool) {
 
206
            char poolname[50];
 
207
    
 
208
            if (apr_pool_create(&gPool, NULL) != APR_SUCCESS) {
 
209
                return getstat(ctx, path, buf, requestmap);
 
210
            }
 
211
    
 
212
            setGlobalPool(gPool);
 
213
            apr_pool_tag(gPool, apr_pstrdup(gPool, "cstat_mem_pool"));
 
214
    
 
215
            statCache = apr_hash_make(gPool);
 
216
            apr_pool_userdata_set ((void*)statCache, "STAT_CACHE", stat_cache_cleanup, gPool);
 
217
 
 
218
            apr_thread_rwlock_create(&rwlock, gPool);
 
219
            apr_pool_userdata_set ((void*)rwlock, "STAT_CACHE_LOCK", apr_pool_cleanup_null, gPool);
 
220
        }
 
221
        else {
 
222
            apr_pool_userdata_get((void**)&statCache, "STAT_CACHE", gPool);
 
223
            apr_pool_userdata_get((void**)&rwlock, "STAT_CACHE_LOCK", gPool);
 
224
        }
 
225
 
 
226
        if (!gPool || !statCache || !rwlock) {
 
227
            return getstat(ctx, path, buf, requestmap);
 
228
        }
 
229
    
 
230
        for (x = 0,tr = path;*tr != '\0';tr++,x++) {
 
231
            if (*tr == '\\' || *tr == '/') {
 
232
                ptr = tr;
 
233
                len = x;
 
234
            }
 
235
            if (*tr == ':') {
 
236
                ptr = "\\";
 
237
                len = x;
 
238
            }
 
239
        }
 
240
    
 
241
        if (ptr) {
 
242
            ppath = apr_pstrndup (p, path, len);
 
243
            strlwr(ppath);
 
244
            if (ptr[1] != '\0') {
 
245
                ptr++;
 
246
            }
 
247
            /* If the path ended in a trailing slash then our result path
 
248
               will be a single slash. To avoid stat'ing the root with a
 
249
               slash, we need to make sure we stat the current directory
 
250
               with a dot */
 
251
            if (((*ptr == '/') || (*ptr == '\\')) && (*(ptr+1) == '\0')) {
 
252
                pinfo = apr_pstrdup (p, ".");
 
253
            }
 
254
            else {
 
255
                pinfo = apr_pstrdup (p, ptr);
 
256
            }
 
257
        }
 
258
    
 
259
        /* If we have a statCache then try to pull the information
 
260
           from the cache.  Otherwise just stat the file and return.*/
 
261
        if (statCache) {
 
262
            apr_thread_rwlock_rdlock(rwlock);
 
263
            pathctx = (NXPathCtx_t) apr_hash_get(statCache, ppath, APR_HASH_KEY_STRING);
 
264
            apr_thread_rwlock_unlock(rwlock);
 
265
            if (pathctx) {
 
266
                return getstat(pathctx, pinfo, buf, requestmap);
 
267
            }
 
268
            else {
 
269
                int err;
 
270
 
 
271
                err = NXCreatePathContext(0, ppath, 0, NULL, &pathctx);
 
272
                if (!err) {
 
273
                    apr_thread_rwlock_wrlock(rwlock);
 
274
                    apr_hash_set(statCache, apr_pstrdup(gPool,ppath) , APR_HASH_KEY_STRING, (void*)pathctx);
 
275
                    apr_thread_rwlock_unlock(rwlock);
 
276
                    return getstat(pathctx, pinfo, buf, requestmap);
 
277
                }
 
278
            }
 
279
        }
 
280
    }
 
281
    return getstat(ctx, path, buf, requestmap);
 
282
}
 
283
#endif
 
284
 
 
285
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, 
 
286
                                   const char *fname, 
 
287
                                   apr_int32_t wanted, apr_pool_t *pool)
 
288
{
 
289
    struct stat info;
 
290
    int srv;
 
291
    NXPathCtx_t pathCtx = 0;
 
292
 
 
293
    getcwdpath(NULL, &pathCtx, CTX_ACTUAL_CWD);
 
294
#ifdef APR_HAS_PSA
 
295
        srv = getstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT);
 
296
#else
 
297
    srv = cstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT, pool);
 
298
#endif
 
299
    errno = srv;
 
300
 
 
301
    if (srv == 0) {
 
302
        finfo->pool = pool;
 
303
        finfo->fname = fname;
 
304
        fill_out_finfo(finfo, &info, wanted);
 
305
        if (wanted & APR_FINFO_LINK)
 
306
            wanted &= ~APR_FINFO_LINK;
 
307
        if (wanted & APR_FINFO_NAME) {
 
308
            finfo->name = apr_pstrdup(pool, info.st_name);
 
309
            finfo->valid |= APR_FINFO_NAME;
 
310
        }
 
311
        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
 
312
    }
 
313
    else {
 
314
#if !defined(ENOENT) || !defined(ENOTDIR)
 
315
#error ENOENT || ENOTDIR not defined; please see the
 
316
#error comments at this line in the source for a workaround.
 
317
        /*
 
318
         * If ENOENT || ENOTDIR is not defined in one of the your OS's
 
319
         * include files, APR cannot report a good reason why the stat()
 
320
         * of the file failed; there are cases where it can fail even though
 
321
         * the file exists.  This opens holes in Apache, for example, because
 
322
         * it becomes possible for someone to get a directory listing of a 
 
323
         * directory even though there is an index (eg. index.html) file in 
 
324
         * it.  If you do not have a problem with this, delete the above 
 
325
         * #error lines and start the compile again.  If you need to do this,
 
326
         * please submit a bug report to http://www.apache.org/bug_report.html
 
327
         * letting us know that you needed to do this.  Please be sure to 
 
328
         * include the operating system you are using.
 
329
         */
 
330
        /* WARNING: All errors will be handled as not found
 
331
         */
 
332
#if !defined(ENOENT) 
 
333
        return APR_ENOENT;
 
334
#else
 
335
        /* WARNING: All errors but not found will be handled as not directory
 
336
         */
 
337
        if (errno != ENOENT)
 
338
            return APR_ENOENT;
 
339
        else
 
340
            return errno;
 
341
#endif
 
342
#else /* All was defined well, report the usual: */
 
343
        return errno;
 
344
#endif
 
345
    }
 
346
}
 
347
 
 
348
APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
 
349
                                              apr_time_t mtime,
 
350
                                              apr_pool_t *pool)
 
351
{
 
352
    apr_status_t status;
 
353
    apr_finfo_t finfo;
 
354
 
 
355
    status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
 
356
    if (status) {
 
357
        return status;
 
358
    }
 
359
 
 
360
#ifdef HAVE_UTIMES
 
361
    {
 
362
      struct timeval tvp[2];
 
363
    
 
364
      tvp[0].tv_sec = apr_time_sec(finfo.atime);
 
365
      tvp[0].tv_usec = apr_time_usec(finfo.atime);
 
366
      tvp[1].tv_sec = apr_time_sec(mtime);
 
367
      tvp[1].tv_usec = apr_time_usec(mtime);
 
368
      
 
369
      if (utimes(fname, tvp) == -1) {
 
370
        return errno;
 
371
      }
 
372
    }
 
373
#elif defined(HAVE_UTIME)
 
374
    {
 
375
      struct utimbuf buf;
 
376
      
 
377
      buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC);
 
378
      buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC);
 
379
      
 
380
      if (utime(fname, &buf) == -1) {
 
381
        return errno;
 
382
      }
 
383
    }
 
384
#else
 
385
    return APR_ENOTIMPL;
 
386
#endif
 
387
 
 
388
    return APR_SUCCESS;
 
389
}