Apache HTTPD
open.c
Go to the documentation of this file.
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#ifdef 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#include <winioctl.h>
36
37#if APR_HAS_UNICODE_FS
39 const char* srcstr)
40{
41 /* TODO: The computations could preconvert the string to determine
42 * the true size of the retstr, but that's a memory over speed
43 * tradeoff that isn't appropriate this early in development.
44 *
45 * Allocate the maximum string length based on leading 4
46 * characters of \\?\ (allowing nearly unlimited path lengths)
47 * plus the trailing null, then transform /'s into \\'s since
48 * the \\?\ form doesn't allow '/' path seperators.
49 *
50 * Note that the \\?\ form only works for local drive paths, and
51 * \\?\UNC\ is needed UNC paths.
52 */
53 apr_size_t srcremains = strlen(srcstr) + 1;
55 apr_status_t rv;
56
57 /* This is correct, we don't twist the filename if it is will
58 * definitely be shorter than 248 characters. It merits some
59 * performance testing to see if this has any effect, but there
60 * seem to be applications that get confused by the resulting
61 * Unicode \\?\ style file names, especially if they use argv[0]
62 * or call the Win32 API functions such as GetModuleName, etc.
63 * Not every application is prepared to handle such names.
64 *
65 * Note also this is shorter than MAX_PATH, as directory paths
66 * are actually limited to 248 characters.
67 *
68 * Note that a utf-8 name can never result in more wide chars
69 * than the original number of utf-8 narrow chars.
70 */
71 if (srcremains > 248) {
72 if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) {
73 wcscpy (retstr, L"\\\\?\\");
74 retlen -= 4;
75 t += 4;
76 }
77 else if ((srcstr[0] == '/' || srcstr[0] == '\\')
78 && (srcstr[1] == '/' || srcstr[1] == '\\')
79 && (srcstr[2] != '?')) {
80 /* Skip the slashes */
81 srcstr += 2;
82 srcremains -= 2;
83 wcscpy (retstr, L"\\\\?\\UNC\\");
84 retlen -= 8;
85 t += 8;
86 }
87 }
88
90 return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
91 }
92 if (srcremains) {
93 return APR_ENAMETOOLONG;
94 }
95 for (; *t; ++t)
96 if (*t == L'/')
97 *t = L'\\';
98 return APR_SUCCESS;
99}
100
102 const apr_wchar_t* srcstr)
103{
104 /* Skip the leading 4 characters if the path begins \\?\, or substitute
105 * // for the \\?\UNC\ path prefix, allocating the maximum string
106 * length based on the remaining string, plus the trailing null.
107 * then transform \\'s back into /'s since the \\?\ form never
108 * allows '/' path seperators, and APR always uses '/'s.
109 */
111 apr_status_t rv;
112 char *t = retstr;
113 if (srcstr[0] == L'\\' && srcstr[1] == L'\\' &&
114 srcstr[2] == L'?' && srcstr[3] == L'\\') {
115 if (srcstr[4] == L'U' && srcstr[5] == L'N' &&
116 srcstr[6] == L'C' && srcstr[7] == L'\\') {
117 srcremains -= 8;
118 srcstr += 8;
119 retstr[0] = '\\';
120 retstr[1] = '\\';
121 retlen -= 2;
122 t += 2;
123 }
124 else {
125 srcremains -= 4;
126 srcstr += 4;
127 }
128 }
129
131 return rv;
132 }
133 if (srcremains) {
134 return APR_ENAMETOOLONG;
135 }
136 return APR_SUCCESS;
137}
138#endif
139
140void *res_name_from_filename(const char *file, int global, apr_pool_t *pool)
141{
142#if APR_HAS_UNICODE_FS
144 {
146 apr_size_t n = strlen(file) + 1;
147 apr_size_t r, d;
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 (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
183 {
184 char *nfile, *ch;
185 apr_size_t n = strlen(file) + 1;
186
187#if !APR_HAS_UNICODE_FS
188 apr_size_t r, d;
189 char *pre;
190
191 if (apr_os_level >= APR_WIN_2000) {
192 if (global)
193 pre = "Global\\";
194 else
195 pre = "Local\\";
196 }
197 else
198 pre = "";
199 r = strlen(pre);
200
201 if (n > 256 - r) {
202 file += n - 256 - r;
203 n = 256;
204 }
205 nfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t));
206 memcpy(nfile, pre, r);
207 memcpy(nfile + r, file, n);
208#else
209 const apr_size_t r = 0;
210 if (n > 256) {
211 file += n - 256;
212 n = 256;
213 }
215#endif
216 for (ch = nfile + r; *ch; ++ch) {
217 if (*ch == ':' || *ch == '/' || *ch == '\\')
218 *ch = '_';
219 }
220 return nfile;
221 }
222#endif
223}
224
225#if APR_HAS_UNICODE_FS
227{
229 apr_status_t rv;
230 DWORD bytesread = 0;
231 DWORD res;
232
233 /* test */
234
236 && (info.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE))
237 return APR_SUCCESS;
238
239 if (file->pOverlapped) {
240 file->pOverlapped->Offset = 0;
241 file->pOverlapped->OffsetHigh = 0;
242 }
243
246 rv = APR_SUCCESS;
247 }
248 else
249 {
250 rv = apr_get_os_error();
251
253 {
254 do {
256 (file->timeout > 0)
257 ? (DWORD)(file->timeout/1000)
258 : ((file->timeout == -1)
259 ? INFINITE : 0));
260 } while (res == WAIT_ABANDONED);
261
262 if (res != WAIT_OBJECT_0) {
264 }
265
267 &bytesread, TRUE))
268 rv = APR_SUCCESS;
269 else
270 rv = apr_get_os_error();
271 }
272 }
273 return rv;
274}
275#endif
276
278{
281
283
284 if (file->buffered) {
285 /* XXX: flush here is not mutex protected */
287 }
288
289 /* In order to avoid later segfaults with handle 'reuse',
290 * we must protect against the case that a dup2'ed handle
291 * is being closed, and invalidate the corresponding StdHandle
292 * We also tell msvcrt when stdhandles are closed.
293 */
294 if (file->flags & APR_STD_FLAGS)
295 {
297 _close(2);
299 }
300 else if ((file->flags & APR_STD_FLAGS) == APR_STDOUT_FLAG) {
301 _close(1);
303 }
304 else if ((file->flags & APR_STD_FLAGS) == APR_STDIN_FLAG) {
305 _close(0);
307 }
308 }
309 else
311
313 }
314 if (file->pOverlapped && file->pOverlapped->hEvent) {
315 CloseHandle(file->pOverlapped->hEvent);
317 }
318 return flush_rv;
319}
320
324{
326 DWORD oflags = 0;
327 DWORD createflags = 0;
328 DWORD attributes = 0;
330 apr_status_t rv;
331
332 if (flag & APR_FOPEN_NONBLOCK) {
333 return APR_ENOTIMPL;
334 }
335 if (flag & APR_FOPEN_READ) {
337 }
338 if (flag & APR_FOPEN_WRITE) {
340 }
341 if (flag & APR_WRITEATTRS) {
343 }
344
345 if (apr_os_level >= APR_WIN_NT)
347
348 if (flag & APR_FOPEN_CREATE) {
349 if (flag & APR_FOPEN_EXCL) {
350 /* only create new if file does not already exist */
352 } else if (flag & APR_FOPEN_TRUNCATE) {
353 /* truncate existing file or create new */
355 } else {
356 /* open existing but create if necessary */
358 }
359 } else if (flag & APR_FOPEN_TRUNCATE) {
360 /* only truncate if file already exists */
362 } else {
363 /* only open if file already exists */
365 }
366
367 if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) {
368 return APR_EACCES;
369 }
370
373 }
374
375 if (flag & APR_OPENLINK) {
377 }
378
379 /* Without READ or WRITE, we fail unless apr called apr_file_open
380 * internally with the private APR_OPENINFO flag.
381 *
382 * With the APR_OPENINFO flag on NT, use the option flag
383 * FILE_FLAG_BACKUP_SEMANTICS to allow us to open directories.
384 * See the static resolve_ident() fn in file_io/win32/filestat.c
385 */
386 if (!(flag & (APR_FOPEN_READ | APR_FOPEN_WRITE))) {
387 if (flag & APR_OPENINFO) {
388 if (apr_os_level >= APR_WIN_NT) {
390 }
391 }
392 else {
393 return APR_EACCES;
394 }
395 if (flag & APR_READCONTROL)
397 }
398
399 if (flag & APR_FOPEN_XTHREAD) {
400 /* This win32 specific feature is required
401 * to allow multiple threads to work with the file.
402 */
404 }
405
406#if APR_HAS_UNICODE_FS
408 {
410
412 /* This feature is required to enable sendfile operations
413 * against the file on Win32. Also implies APR_FOPEN_XTHREAD.
414 */
417 }
418
419 if ((rv = utf8_to_unicode_path(wfname, sizeof(wfname)
420 / sizeof(apr_wchar_t), fname)))
421 return rv;
424 }
425#endif
426#if APR_HAS_ANSI_FS
430 /* This feature is not supported on this platform. */
432 }
433#endif
435 return apr_get_os_error();
436 }
437
438 (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t));
439 (*new)->pool = pool;
440 (*new)->filehand = handle;
441 (*new)->fname = apr_pstrdup(pool, fname);
442 (*new)->flags = flag;
443 (*new)->timeout = -1;
444 (*new)->ungetchar = -1;
445
446 if (flag & APR_FOPEN_APPEND) {
447 (*new)->append = 1;
448 SetFilePointer((*new)->filehand, 0, NULL, FILE_END);
449 }
450 if (flag & APR_FOPEN_BUFFERED) {
451 (*new)->buffered = 1;
452 (*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
453 (*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
454 }
455 /* Need the mutex to handled buffered and O_APPEND style file i/o */
456 if ((*new)->buffered || (*new)->append) {
457 rv = apr_thread_mutex_create(&(*new)->mutex,
459 if (rv) {
460 if (file_cleanup(*new) == APR_SUCCESS) {
462 }
463 return rv;
464 }
465 }
466
467#if APR_HAS_UNICODE_FS
468 if ((apr_os_level >= APR_WIN_2000) && ((*new)->flags & APR_FOPEN_SPARSE)) {
469 if ((rv = make_sparse_file(*new)) != APR_SUCCESS)
470 /* The great mystery; do we close the file and return an error?
471 * Do we add a new APR_INCOMPLETE style error saying opened, but
472 * NOTSPARSE? For now let's simply mark the file as not-sparse.
473 */
474 (*new)->flags &= ~APR_FOPEN_SPARSE;
475 }
476 else
477#endif
478 /* This feature is not supported on this platform. */
479 (*new)->flags &= ~APR_FOPEN_SPARSE;
480
481#if APR_FILES_AS_SOCKETS
482 /* Create a pollset with room for one descriptor. */
483 /* ### check return codes */
484 (void) apr_pollset_create(&(*new)->pollset, 1, pool, 0);
485#endif
486 if (!(flag & APR_FOPEN_NOCLEANUP)) {
487 apr_pool_cleanup_register((*new)->pool, (void *)(*new), file_cleanup,
489 }
490 return APR_SUCCESS;
491}
492
494{
496 if ((stat = file_cleanup(file)) == APR_SUCCESS) {
498
499 if (file->mutex) {
501 }
502
503 return APR_SUCCESS;
504 }
505 return stat;
506}
507
509{
510#if APR_HAS_UNICODE_FS
512 {
514 apr_status_t rv;
515 if ((rv = utf8_to_unicode_path(wpath, sizeof(wpath)
516 / sizeof(apr_wchar_t), path))) {
517 return rv;
518 }
519 if (DeleteFileW(wpath))
520 return APR_SUCCESS;
521 }
522#endif
523#if APR_HAS_ANSI_FS
525 if (DeleteFile(path))
526 return APR_SUCCESS;
527#endif
528 return apr_get_os_error();
529}
530
532 const char *topath,
534{
536 {
537#if APR_HAS_UNICODE_FS
539 apr_status_t rv;
541 sizeof(wfrompath) / sizeof(apr_wchar_t),
542 frompath))) {
543 return rv;
544 }
546 sizeof(wtopath) / sizeof(apr_wchar_t),
547 topath))) {
548 return rv;
549 }
550#ifndef _WIN32_WCE
553#else
555#endif
556 return APR_SUCCESS;
557#else
560 return APR_SUCCESS;
561#endif
562 }
563#if APR_HAS_ANSI_FS
565 {
566 /* Windows 95 and 98 do not support MoveFileEx, so we'll use
567 * the old MoveFile function. However, MoveFile requires that
568 * the new file not already exist...so we have to delete that
569 * file if it does. Perhaps we should back up the to-be-deleted
570 * file in case something happens?
571 */
573
574 if ((handle = CreateFile(topath, GENERIC_WRITE, 0, 0,
576 {
578 if (!DeleteFile(topath))
579 return apr_get_os_error();
580 }
582 return APR_SUCCESS;
583 }
584#endif
585 return apr_get_os_error();
586}
587
589 const char *to_path)
590{
592
593#if APR_HAS_UNICODE_FS
595 {
598
600 sizeof(wfrom_path) / sizeof(apr_wchar_t),
601 from_path)))
602 return rv;
604 sizeof(wto_path) / sizeof(apr_wchar_t),
605 to_path)))
606 return rv;
607
609 return apr_get_os_error();
610 }
611#endif
612#if APR_HAS_ANSI_FS
615 return apr_get_os_error();
616 }
617#endif
618 return rv;
619}
620
623{
625 return APR_SUCCESS;
626}
627
632{
633 (*file) = apr_pcalloc(pool, sizeof(apr_file_t));
634 (*file)->pool = pool;
635 (*file)->filehand = *thefile;
636 (*file)->ungetchar = -1; /* no char avail */
637 (*file)->timeout = -1;
638 (*file)->flags = flags;
639
640 if (flags & APR_FOPEN_APPEND) {
641 (*file)->append = 1;
642 }
644 (*file)->buffered = 1;
645 (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
646 (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
647 }
648
649 if ((*file)->append || (*file)->buffered) {
650 apr_status_t rv;
651 rv = apr_thread_mutex_create(&(*file)->mutex,
653 if (rv) {
654 return rv;
655 }
656 }
657
658#if APR_FILES_AS_SOCKETS
659 /* Create a pollset with room for one descriptor. */
660 /* ### check return codes */
661 (void) apr_pollset_create(&(*file)->pollset, 1, pool, 0);
662#endif
663 /* Should we be testing if thefile is a handle to
664 * a PIPE and set up the mechanics appropriately?
665 *
666 * (*file)->pipe;
667 */
668 return APR_SUCCESS;
669}
670
672{
673 if (fptr->eof_hit == 1) {
674 return APR_EOF;
675 }
676 return APR_SUCCESS;
677}
678
682{
683#ifdef _WIN32_WCE
684 return APR_ENOTIMPL;
685#else
687
690 if (!file_handle)
692
695#endif
696}
697
701{
702#ifdef _WIN32_WCE
703 return APR_ENOTIMPL;
704#else
706
709 if (!file_handle)
711
714#endif
715}
716
720{
721#ifdef _WIN32_WCE
722 return APR_ENOTIMPL;
723#else
725
728 if (!file_handle)
730
733#endif
734}
735
737{
739}
740
742{
744}
745
747{
749}
750
752
754
int n
Definition ap_regex.h:278
#define TRUE
Definition abts.h:38
apr_uint16_t apr_wchar_t
#define GetStdHandle(d)
#define CreateFileW(nm, d1, d2, sd, d3, d4, h)
#define SetStdHandle(d, h)
#define CreateFileA(nm, d1, d2, sd, d3, d4, h)
#define CloseHandle(h)
#define WaitForSingleObject(h, d)
APR File I/O Handling.
APR Miscellaneous library routines.
APR Portability Routines.
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
APR Thread Mutex Routines.
request_rec int int apr_table_t const char * path
request_rec * r
#define APR_EOF
Definition apr_errno.h:461
#define APR_ENAMETOOLONG
Definition apr_errno.h:655
#define APR_EACCES
Definition apr_errno.h:641
#define APR_INCOMPLETE
Definition apr_errno.h:452
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_EINVAL
Definition apr_errno.h:711
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
apr_pool_t const char apr_dbd_t ** handle
Definition apr_dbd.h:142
const char apr_ssize_t int flags
Definition apr_encode.h:168
const void apr_status_t(*) apr_status_t(* APR_DECLARE)(void) apr_pool_pre_cleanup_register(apr_pool_t *p
Definition apr_pools.h:646
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_FROM_OS_ERROR(e)
Definition apr_errno.h:1214
#define apr_set_os_error(e)
Definition apr_errno.h:1218
#define APR_SUCCESS
Definition apr_errno.h:225
#define apr_get_os_error()
Definition apr_errno.h:1217
int apr_status_t
Definition apr_errno.h:44
apr_int32_t apr_fileperms_t
apr_file_t * thefile
const char apr_int32_t flag
apr_fileattrs_t attributes
const char apr_file_t * file
const char * to_path
const char apr_int32_t apr_fileperms_t perm
#define APR_FOPEN_TRUNCATE
Definition apr_file_io.h:58
#define APR_FOPEN_SPARSE
Definition apr_file_io.h:85
#define APR_FOPEN_NONBLOCK
Definition apr_file_io.h:88
#define APR_FOPEN_NOCLEANUP
Definition apr_file_io.h:74
#define APR_FOPEN_XTHREAD
Definition apr_file_io.h:67
#define APR_FOPEN_APPEND
Definition apr_file_io.h:57
#define APR_FOPEN_DELONCLOSE
Definition apr_file_io.h:66
#define APR_FOPEN_SENDFILE_ENABLED
Definition apr_file_io.h:79
#define APR_FOPEN_EXCL
Definition apr_file_io.h:63
#define APR_FOPEN_BUFFERED
Definition apr_file_io.h:65
#define APR_FOPEN_WRITE
Definition apr_file_io.h:55
#define APR_FOPEN_READ
Definition apr_file_io.h:54
#define APR_FOPEN_CREATE
Definition apr_file_io.h:56
const char * fname
apr_interval_time_t t
#define APR_POOL_IMPLEMENT_ACCESSOR(type)
Definition apr_pools.h:91
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
int apr_os_file_t
return NULL
Definition mod_so.c:359
#define APR_FILE_DEFAULT_BUFSIZE
#define APR_IMPLEMENT_INHERIT_UNSET(name, flag, pool, cleanup)
#define APR_IMPLEMENT_INHERIT_SET(name, flag, pool, cleanup)
apr_int32_t flags
apr_interval_time_t timeout
apr_thread_mutex_t * mutex
apr_pool_t * pool
OVERLAPPED * pOverlapped
static apr_status_t file_cleanup(apr_file_t *file, int is_child)
Definition open.c:29
#define FILE_FLAG_OPEN_REPARSE_POINT
#define APR_STDIN_FLAG
#define APR_OPENLINK
#define APR_STD_FLAGS
#define APR_OPENINFO
#define APR_STDOUT_FLAG
#define APR_READCONTROL
#define APR_WRITEATTRS
#define APR_STDERR_FLAG
IN ULONG IN INT timeout
#define ELSE_WIN_OS_IS_ANSI
typedef HANDLE(WINAPI *apr_winapi_fpt_CreateToolhelp32Snapshot)(DWORD dwFlags
APR_DECLARE_DATA apr_oslevel_e apr_os_level
Definition misc.c:24
@ APR_WIN_NT
@ APR_WIN_2000
#define IF_WIN_OS_IS_UNICODE
#define CancelIo
typedef DWORD(WINAPI *apr_winapi_fpt_GetCompressedFileSizeA)(IN LPCSTR lpFileName
INT info
void * res_name_from_filename(const char *file, int global, apr_pool_t *pool)
Definition open.c:140