upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / file_io / win32 / open.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_private.h"
18 #include "apr_arch_file_io.h"
19 #include "apr_file_io.h"
20 #include "apr_general.h"
21 #include "apr_strings.h"
22 #include "apr_portable.h"
23 #include "apr_thread_mutex.h"
24 #if APR_HAVE_ERRNO_H
25 #include <errno.h>
26 #endif
27 #include <winbase.h>
28 #include <string.h>
29 #if APR_HAVE_SYS_STAT_H
30 #include <sys/stat.h>
31 #endif
32 #include "apr_arch_misc.h"
33 #include "apr_arch_inherit.h"
34 #include <io.h>
35
36 #if APR_HAS_UNICODE_FS
37 apr_status_t utf8_to_unicode_path(apr_wchar_t* retstr, apr_size_t retlen, 
38                                   const char* srcstr)
39 {
40     /* TODO: The computations could preconvert the string to determine
41      * the true size of the retstr, but that's a memory over speed
42      * tradeoff that isn't appropriate this early in development.
43      *
44      * Allocate the maximum string length based on leading 4 
45      * characters of \\?\ (allowing nearly unlimited path lengths) 
46      * plus the trailing null, then transform /'s into \\'s since
47      * the \\?\ form doesn't allow '/' path seperators.
48      *
49      * Note that the \\?\ form only works for local drive paths, and
50      * \\?\UNC\ is needed UNC paths.
51      */
52     int srcremains = strlen(srcstr) + 1;
53     apr_wchar_t *t = retstr;
54     apr_status_t rv;
55
56     /* This is correct, we don't twist the filename if it is will
57      * definately be shorter than 248 characters.  It merits some 
58      * performance testing to see if this has any effect, but there
59      * seem to be applications that get confused by the resulting
60      * Unicode \\?\ style file names, especially if they use argv[0]
61      * or call the Win32 API functions such as GetModuleName, etc.
62      * Not every application is prepared to handle such names.
63      * 
64      * Note also this is shorter than MAX_PATH, as directory paths 
65      * are actually limited to 248 characters. 
66      *
67      * Note that a utf-8 name can never result in more wide chars
68      * than the original number of utf-8 narrow chars.
69      */
70     if (srcremains > 248) {
71         if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) {
72             wcscpy (retstr, L"\\\\?\\");
73             retlen -= 4;
74             t += 4;
75         }
76         else if ((srcstr[0] == '/' || srcstr[0] == '\\')
77               && (srcstr[1] == '/' || srcstr[1] == '\\')
78               && (srcstr[2] != '?')) {
79             /* Skip the slashes */
80             srcstr += 2;
81             srcremains -= 2;
82             wcscpy (retstr, L"\\\\?\\UNC\\");
83             retlen -= 8;
84             t += 8;
85         }
86     }
87
88     if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen)) {
89         return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
90     }
91     if (srcremains) {
92         return APR_ENAMETOOLONG;
93     }
94     for (; *t; ++t)
95         if (*t == L'/')
96             *t = L'\\';
97     return APR_SUCCESS;
98 }
99
100 apr_status_t unicode_to_utf8_path(char* retstr, apr_size_t retlen,
101                                   const apr_wchar_t* srcstr)
102 {
103     /* Skip the leading 4 characters if the path begins \\?\, or substitute
104      * // for the \\?\UNC\ path prefix, allocating the maximum string
105      * length based on the remaining string, plus the trailing null.
106      * then transform \\'s back into /'s since the \\?\ form never
107      * allows '/' path seperators, and APR always uses '/'s.
108      */
109     int srcremains = wcslen(srcstr) + 1;
110     apr_status_t rv;
111     char *t = retstr;
112     if (srcstr[0] == L'\\' && srcstr[1] == L'\\' && 
113         srcstr[2] == L'?'  && srcstr[3] == L'\\') {
114         if (srcstr[4] == L'U' && srcstr[5] == L'N' && 
115             srcstr[6] == L'C' && srcstr[7] == L'\\') {
116             srcremains -= 8;
117             srcstr += 8;
118             retstr[0] = '\\';
119             retstr[1] = '\\';
120             retlen -= 2;
121             t += 2;
122         }
123         else {
124             srcremains -= 4;
125             srcstr += 4;
126         }
127     }
128         
129     if (rv = apr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen)) {
130         return rv;
131     }
132     if (srcremains) {
133         return APR_ENAMETOOLONG;
134     }
135     return APR_SUCCESS;
136 }
137 #endif
138
139 void *res_name_from_filename(const char *file, int global, apr_pool_t *pool)
140 {
141 #if APR_HAS_UNICODE_FS
142     IF_WIN_OS_IS_UNICODE
143     {
144         apr_wchar_t *wpre, *wfile, *ch;
145         apr_size_t n = strlen(file) + 1;
146         apr_size_t r, d;
147         apr_status_t rv;
148
149         if (apr_os_level >= APR_WIN_2000) {
150             if (global)
151                 wpre = L"Global\\";
152             else
153                 wpre = L"Local\\";
154         }
155         else
156             wpre = L"";
157         r = wcslen(wpre);
158
159         if (n > 256 - r) {
160             file += n - 256 - r;
161             n = 256;
162             /* skip utf8 continuation bytes */
163             while ((*file & 0xC0) == 0x80) {
164                 ++file;
165                 --n;
166             }
167         }
168         wfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t));
169         wcscpy(wfile, wpre);
170         d = n;
171         if (rv = apr_conv_utf8_to_ucs2(file, &n, wfile + r, &d)) {
172             return NULL;
173         }
174         for (ch = wfile + r; *ch; ++ch) {
175             if (*ch == ':' || *ch == '/' || *ch == '\\')
176                 *ch = '_';
177         }
178         return wfile;
179     }
180 #endif
181 #if APR_HAS_ANSI_FS
182     ELSE_WIN_OS_IS_ANSI
183     {
184         char *nfile, *ch;
185         apr_size_t n = strlen(file) + 1;
186
187 #if !APR_HAS_UNICODE_FS
188         apr_status_t rv;
189         apr_size_t r, d;
190         char *pre;
191
192         if (apr_os_level >= APR_WIN_2000) {
193             if (global)
194                 pre = "Global\\";
195             else
196                 pre = "Local\\";
197         }
198         else
199             pre = "";
200         r = strlen(pre);
201
202         if (n > 256 - r) {
203             file += n - 256 - r;
204             n = 256;
205         }
206         nfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t));
207         memcpy(nfile, pre, r);
208         memcpy(nfile + r, file, n);
209 #else
210         const apr_size_t r = 0;
211         if (n > 256) {
212             file += n - 256;
213             n = 256;
214         }
215         nfile = apr_pmemdup(pool, file, n);
216 #endif
217         for (ch = nfile + r; *ch; ++ch) {
218             if (*ch == ':' || *ch == '/' || *ch == '\\')
219                 *ch = '_';
220         }
221         return nfile;
222     }
223 #endif
224 }
225
226
227 apr_status_t file_cleanup(void *thefile)
228 {
229     apr_file_t *file = thefile;
230     apr_status_t flush_rv = APR_SUCCESS;
231
232     if (file->filehand != INVALID_HANDLE_VALUE) {
233
234         if (file->buffered) {
235             /* XXX: flush here is not mutex protected */
236             flush_rv = apr_file_flush((apr_file_t *)thefile);
237         }
238
239         /* In order to avoid later segfaults with handle 'reuse',
240          * we must protect against the case that a dup2'ed handle
241          * is being closed, and invalidate the corresponding StdHandle 
242          * We also tell msvcrt when stdhandles are closed.
243          */
244         if (file->flags & APR_STD_FLAGS)
245         {
246             if ((file->flags & APR_STD_FLAGS) == APR_STDERR_FLAG) {
247                 _close(2);
248                 SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
249             }
250             else if ((file->flags & APR_STD_FLAGS) == APR_STDOUT_FLAG) {
251                 _close(1);
252                 SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
253             }
254             else if ((file->flags & APR_STD_FLAGS) == APR_STDIN_FLAG) {
255                 _close(0);
256                 SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE);
257             }
258         }
259         else
260             CloseHandle(file->filehand);
261
262         file->filehand = INVALID_HANDLE_VALUE;
263     }
264     if (file->pOverlapped && file->pOverlapped->hEvent) {
265         CloseHandle(file->pOverlapped->hEvent);
266         file->pOverlapped = NULL;
267     }
268     return flush_rv;
269 }
270
271 APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, const char *fname,
272                                    apr_int32_t flag, apr_fileperms_t perm,
273                                    apr_pool_t *pool)
274 {
275     HANDLE handle = INVALID_HANDLE_VALUE;
276     DWORD oflags = 0;
277     DWORD createflags = 0;
278     DWORD attributes = 0;
279     DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE;
280     apr_status_t rv;
281
282     if (flag & APR_READ) {
283         oflags |= GENERIC_READ;
284     }
285     if (flag & APR_WRITE) {
286         oflags |= GENERIC_WRITE;
287     }
288     if (flag & APR_WRITEATTRS) {
289         oflags |= FILE_WRITE_ATTRIBUTES;
290     }
291
292     if (apr_os_level >= APR_WIN_NT) 
293         sharemode |= FILE_SHARE_DELETE;
294
295     if (flag & APR_CREATE) {
296         if (flag & APR_EXCL) {
297             /* only create new if file does not already exist */
298             createflags = CREATE_NEW;
299         } else if (flag & APR_TRUNCATE) {
300             /* truncate existing file or create new */
301             createflags = CREATE_ALWAYS;
302         } else {
303             /* open existing but create if necessary */
304             createflags = OPEN_ALWAYS;
305         }
306     } else if (flag & APR_TRUNCATE) {
307         /* only truncate if file already exists */
308         createflags = TRUNCATE_EXISTING;
309     } else {
310         /* only open if file already exists */
311         createflags = OPEN_EXISTING;
312     }
313
314     if ((flag & APR_EXCL) && !(flag & APR_CREATE)) {
315         return APR_EACCES;
316     }   
317     
318     if (flag & APR_DELONCLOSE) {
319         attributes |= FILE_FLAG_DELETE_ON_CLOSE;
320     }
321
322     if (flag & APR_OPENLINK) {
323        attributes |= FILE_FLAG_OPEN_REPARSE_POINT;
324     }
325
326     /* Without READ or WRITE, we fail unless apr called apr_file_open
327      * internally with the private APR_OPENINFO flag.
328      *
329      * With the APR_OPENINFO flag on NT, use the option flag
330      * FILE_FLAG_BACKUP_SEMANTICS to allow us to open directories.
331      * See the static resolve_ident() fn in file_io/win32/filestat.c
332      */
333     if (!(flag & (APR_READ | APR_WRITE))) {
334         if (flag & APR_OPENINFO) {
335             if (apr_os_level >= APR_WIN_NT) {
336                 attributes |= FILE_FLAG_BACKUP_SEMANTICS;
337             }
338         }
339         else {
340             return APR_EACCES;
341         }
342         if (flag & APR_READCONTROL)
343             oflags |= READ_CONTROL;
344     }
345
346     if (flag & APR_XTHREAD) {
347         /* This win32 specific feature is required 
348          * to allow multiple threads to work with the file.
349          */
350         attributes |= FILE_FLAG_OVERLAPPED;
351     }
352
353 #if APR_HAS_UNICODE_FS
354     IF_WIN_OS_IS_UNICODE
355     {
356         apr_wchar_t wfname[APR_PATH_MAX];
357
358         if (flag & APR_SENDFILE_ENABLED) {    
359             /* This feature is required to enable sendfile operations
360              * against the file on Win32. Also implies APR_XTHREAD.
361              */
362             flag |= APR_XTHREAD;
363             attributes |= FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED;
364         }
365
366         if (rv = utf8_to_unicode_path(wfname, sizeof(wfname) 
367                                                / sizeof(apr_wchar_t), fname))
368             return rv;
369         handle = CreateFileW(wfname, oflags, sharemode,
370                              NULL, createflags, attributes, 0);
371     }
372 #endif
373 #if APR_HAS_ANSI_FS
374     ELSE_WIN_OS_IS_ANSI {
375         handle = CreateFileA(fname, oflags, sharemode,
376                              NULL, createflags, attributes, 0);
377         if (flag & APR_SENDFILE_ENABLED) {    
378             /* This feature is not supported on this platform.
379              */
380             flag &= ~APR_SENDFILE_ENABLED;
381         }
382
383     }
384 #endif
385     if (handle == INVALID_HANDLE_VALUE) {
386         return apr_get_os_error();
387     }
388
389     (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t));
390     (*new)->pool = pool;
391     (*new)->filehand = handle;
392     (*new)->fname = apr_pstrdup(pool, fname);
393     (*new)->flags = flag;
394     (*new)->timeout = -1;
395     (*new)->ungetchar = -1;
396
397     if (flag & APR_APPEND) {
398         (*new)->append = 1;
399         SetFilePointer((*new)->filehand, 0, NULL, FILE_END);
400     }
401     if (flag & APR_BUFFERED) {
402         (*new)->buffered = 1;
403         (*new)->buffer = apr_palloc(pool, APR_FILE_BUFSIZE);
404     }
405     /* Need the mutex to handled buffered and O_APPEND style file i/o */
406     if ((*new)->buffered || (*new)->append) {
407         rv = apr_thread_mutex_create(&(*new)->mutex, 
408                                      APR_THREAD_MUTEX_DEFAULT, pool);
409         if (rv) {
410             if (file_cleanup(*new) == APR_SUCCESS) {
411                 apr_pool_cleanup_kill(pool, *new, file_cleanup);
412             }
413             return rv;
414         }
415     }
416
417     if (!(flag & APR_FILE_NOCLEANUP)) {
418         apr_pool_cleanup_register((*new)->pool, (void *)(*new), file_cleanup,
419                                   apr_pool_cleanup_null);
420     }
421     return APR_SUCCESS;
422 }
423
424 APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file)
425 {
426     apr_status_t stat;
427     if ((stat = file_cleanup(file)) == APR_SUCCESS) {
428         apr_pool_cleanup_kill(file->pool, file, file_cleanup);
429
430         if (file->mutex) {
431             apr_thread_mutex_destroy(file->mutex);
432         }
433
434         return APR_SUCCESS;
435     }
436     return stat;
437 }
438
439 APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool)
440 {
441 #if APR_HAS_UNICODE_FS
442     IF_WIN_OS_IS_UNICODE
443     {
444         apr_wchar_t wpath[APR_PATH_MAX];
445         apr_status_t rv;
446         if (rv = utf8_to_unicode_path(wpath, sizeof(wpath) 
447                                               / sizeof(apr_wchar_t), path)) {
448             return rv;
449         }
450         if (DeleteFileW(wpath))
451             return APR_SUCCESS;
452     }
453 #endif
454 #if APR_HAS_ANSI_FS
455     ELSE_WIN_OS_IS_ANSI
456         if (DeleteFile(path))
457             return APR_SUCCESS;
458 #endif
459     return apr_get_os_error();
460 }
461
462 APR_DECLARE(apr_status_t) apr_file_rename(const char *frompath,
463                                           const char *topath,
464                                           apr_pool_t *pool)
465 {
466     IF_WIN_OS_IS_UNICODE
467     {
468 #if APR_HAS_UNICODE_FS
469         apr_wchar_t wfrompath[APR_PATH_MAX], wtopath[APR_PATH_MAX];
470         apr_status_t rv;
471         if (rv = utf8_to_unicode_path(wfrompath, sizeof(wfrompath) 
472                                            / sizeof(apr_wchar_t), frompath)) {
473             return rv;
474         }
475         if (rv = utf8_to_unicode_path(wtopath, sizeof(wtopath) 
476                                              / sizeof(apr_wchar_t), topath)) {
477             return rv;
478         }
479 #ifndef _WIN32_WCE
480         if (MoveFileExW(wfrompath, wtopath, MOVEFILE_REPLACE_EXISTING |
481                                             MOVEFILE_COPY_ALLOWED))
482 #else
483         if (MoveFileW(wfrompath, wtopath))
484 #endif
485             return APR_SUCCESS;
486 #else
487         if (MoveFileEx(frompath, topath, MOVEFILE_REPLACE_EXISTING |
488                                          MOVEFILE_COPY_ALLOWED))
489             return APR_SUCCESS;
490 #endif
491     }
492 #if APR_HAS_ANSI_FS
493     ELSE_WIN_OS_IS_ANSI
494     {
495         /* Windows 95 and 98 do not support MoveFileEx, so we'll use
496          * the old MoveFile function.  However, MoveFile requires that
497          * the new file not already exist...so we have to delete that
498          * file if it does.  Perhaps we should back up the to-be-deleted
499          * file in case something happens?
500          */
501         HANDLE handle = INVALID_HANDLE_VALUE;
502
503         if ((handle = CreateFile(topath, GENERIC_WRITE, 0, 0,  
504             OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE )
505         {
506             CloseHandle(handle);
507             if (!DeleteFile(topath))
508                 return apr_get_os_error();
509         }
510         if (MoveFile(frompath, topath))
511             return APR_SUCCESS;
512     }        
513 #endif
514     return apr_get_os_error();
515 }
516
517 APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile,
518                                           apr_file_t *file)
519 {
520     *thefile = file->filehand;
521     return APR_SUCCESS;
522 }
523
524 APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file,
525                                           apr_os_file_t *thefile,
526                                           apr_int32_t flags,
527                                           apr_pool_t *pool)
528 {
529     (*file) = apr_pcalloc(pool, sizeof(apr_file_t));
530     (*file)->pool = pool;
531     (*file)->filehand = *thefile;
532     (*file)->ungetchar = -1; /* no char avail */
533     (*file)->timeout = -1;
534     (*file)->flags = flags;
535
536     if (flags & APR_APPEND) {
537         (*file)->append = 1;
538     }
539     if (flags & APR_BUFFERED) {
540         (*file)->buffered = 1;
541         (*file)->buffer = apr_palloc(pool, APR_FILE_BUFSIZE);
542     }
543
544     if ((*file)->append || (*file)->buffered) {
545         apr_status_t rv;
546         rv = apr_thread_mutex_create(&(*file)->mutex, 
547                                      APR_THREAD_MUTEX_DEFAULT, pool);
548         if (rv) {
549             if (file_cleanup(*file) == APR_SUCCESS) {
550                 apr_pool_cleanup_kill(pool, *file, file_cleanup);
551             }
552             return rv;
553         }
554     }
555
556     /* XXX... we pcalloc above so all others are zeroed.
557      * Should we be testing if thefile is a handle to 
558      * a PIPE and set up the mechanics appropriately?
559      *
560      *  (*file)->pipe;
561      */
562     return APR_SUCCESS;
563 }    
564
565 APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr)
566 {
567     if (fptr->eof_hit == 1) {
568         return APR_EOF;
569     }
570     return APR_SUCCESS;
571 }   
572
573 APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, apr_pool_t *pool)
574 {
575 #ifdef _WIN32_WCE
576     return APR_ENOTIMPL;
577 #else
578     apr_os_file_t file_handle;
579
580     apr_set_os_error(APR_SUCCESS);
581     file_handle = GetStdHandle(STD_ERROR_HANDLE);
582     if (!file_handle)
583         file_handle = INVALID_HANDLE_VALUE;
584
585     return apr_os_file_put(thefile, &file_handle,
586                            APR_WRITE | APR_STDERR_FLAG, pool);
587 #endif
588 }
589
590 APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, apr_pool_t *pool)
591 {
592 #ifdef _WIN32_WCE
593     return APR_ENOTIMPL;
594 #else
595     apr_os_file_t file_handle;
596
597     apr_set_os_error(APR_SUCCESS);
598     file_handle = GetStdHandle(STD_OUTPUT_HANDLE);
599     if (!file_handle)
600         file_handle = INVALID_HANDLE_VALUE;
601
602     return apr_os_file_put(thefile, &file_handle,
603                            APR_WRITE | APR_STDOUT_FLAG, pool);
604 #endif
605 }
606
607 APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, apr_pool_t *pool)
608 {
609 #ifdef _WIN32_WCE
610     return APR_ENOTIMPL;
611 #else
612     apr_os_file_t file_handle;
613
614     apr_set_os_error(APR_SUCCESS);
615     file_handle = GetStdHandle(STD_INPUT_HANDLE);
616     if (!file_handle)
617         file_handle = INVALID_HANDLE_VALUE;
618
619     return apr_os_file_put(thefile, &file_handle,
620                            APR_READ | APR_STDIN_FLAG, pool);
621 #endif
622 }
623
624 APR_POOL_IMPLEMENT_ACCESSOR(file);
625
626 APR_IMPLEMENT_INHERIT_SET(file, flags, pool, file_cleanup)
627  
628 APR_IMPLEMENT_INHERIT_UNSET(file, flags, pool, file_cleanup)