Mercurial > hg > nginx
comparison src/os/win32/ngx_files.c @ 3435:d65ba5392f59 stable-0.7
merge r3138, r3139, r3157, r3158, r3159, r3164, r3165,
r3202, r3203, r3383, r3388, r3417, r3418:
Win32 (mostly) and some Unix file related fixes:
*) preserve errno while ngx_free()
*) win32 ngx_file_info() utf8 support
*) delete Win95 code
*) log file name for read/write errors
*) test incomplete WriteFile()
*) handle short pwrite() to log an error cause: ENOSPC, EDQUOT, or EFBIG
*) uniform ngx_directio_on/off() interface with other file functions
*) do not create Win32 drive letter in ngx_create_full_path()
*) ignore EACCES errors for top level directories in ngx_create_full_path()
*) fix Win32 error messages when an temporary file replaces an existent file:
*) do not rename an already renamed file
*) now ngx_win32_rename_file() returns error code
*) do not log failure inside ngx_win32_rename_file()
*) fix Win32 error message when an temporary file replaces an existent file:
return at once if ngx_win32_rename_file() was not failed
and do not try to delete already the renamed temporary file
*) skip URI trailing spaces under Win32
*) disable Win32 short file names
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 01 Feb 2010 15:06:25 +0000 |
parents | 6b8284fc958d |
children | 771d28b86077 |
comparison
equal
deleted
inserted
replaced
3434:8d310fbeaa38 | 3435:d65ba5392f59 |
---|---|
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 | 9 |
10 | 10 |
11 #define NGX_UTF16_BUFLEN 256 | 11 #define NGX_UTF16_BUFLEN 256 |
12 | 12 |
13 static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t len); | 13 static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len); |
14 | 14 |
15 | 15 |
16 /* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */ | 16 /* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */ |
17 | 17 |
18 ngx_fd_t | 18 ngx_fd_t |
19 ngx_open_file(u_char *name, u_long mode, u_long create, u_long access) | 19 ngx_open_file(u_char *name, u_long mode, u_long create, u_long access) |
20 { | 20 { |
21 u_short *u; | 21 size_t len; |
22 ngx_fd_t fd; | 22 u_long n; |
23 u_short utf16[NGX_UTF16_BUFLEN]; | 23 u_short *u, *lu; |
24 | 24 ngx_fd_t fd; |
25 u = ngx_utf8_to_utf16(utf16, name, NGX_UTF16_BUFLEN); | 25 ngx_err_t err; |
26 u_short utf16[NGX_UTF16_BUFLEN]; | |
27 | |
28 len = NGX_UTF16_BUFLEN; | |
29 u = ngx_utf8_to_utf16(utf16, name, &len); | |
26 | 30 |
27 if (u == NULL) { | 31 if (u == NULL) { |
28 return INVALID_HANDLE_VALUE; | 32 return INVALID_HANDLE_VALUE; |
33 } | |
34 | |
35 fd = INVALID_HANDLE_VALUE; | |
36 lu = NULL; | |
37 | |
38 if (create == NGX_FILE_OPEN) { | |
39 | |
40 lu = malloc(len * 2); | |
41 if (lu == NULL) { | |
42 goto failed; | |
43 } | |
44 | |
45 n = GetLongPathNameW(u, lu, len); | |
46 | |
47 if (n == 0) { | |
48 goto failed; | |
49 } | |
50 | |
51 if (n != len - 1 || ngx_memcmp(u, lu, n) != 0) { | |
52 ngx_set_errno(NGX_ENOENT); | |
53 goto failed; | |
54 } | |
29 } | 55 } |
30 | 56 |
31 fd = CreateFileW(u, mode, | 57 fd = CreateFileW(u, mode, |
32 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, | 58 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, |
33 NULL, create, FILE_FLAG_BACKUP_SEMANTICS, NULL); | 59 NULL, create, FILE_FLAG_BACKUP_SEMANTICS, NULL); |
34 | 60 |
61 failed: | |
62 | |
63 err = ngx_errno; | |
64 | |
65 if (lu) { | |
66 ngx_free(lu); | |
67 } | |
68 | |
35 if (u != utf16) { | 69 if (u != utf16) { |
36 ngx_free(u); | 70 ngx_free(u); |
37 } | 71 } |
38 | 72 |
73 ngx_set_errno(err); | |
74 | |
39 return fd; | 75 return fd; |
40 } | 76 } |
41 | 77 |
42 | 78 |
43 ssize_t | 79 ssize_t |
44 ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) | 80 ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) |
45 { | 81 { |
46 long high_offset; | |
47 u_long n; | 82 u_long n; |
48 ngx_err_t err; | 83 ngx_err_t err; |
49 OVERLAPPED ovlp, *povlp; | 84 OVERLAPPED ovlp, *povlp; |
50 | 85 |
51 if (ngx_win32_version < NGX_WIN_NT) { | 86 ovlp.Internal = 0; |
52 | 87 ovlp.InternalHigh = 0; |
53 /* | 88 ovlp.Offset = (u_long) offset; |
54 * under Win9X the overlapped pointer must be NULL | 89 ovlp.OffsetHigh = (u_long) (offset >> 32); |
55 * so we have to use SetFilePointer() to set the offset | 90 ovlp.hEvent = NULL; |
56 */ | 91 |
57 | 92 povlp = &ovlp; |
58 if (file->offset != offset) { | |
59 | |
60 /* | |
61 * the maximum file size on the FAT16 is 2G, but on the FAT32 | |
62 * the size is 4G so we have to use the high_offset | |
63 * because a single offset is signed value | |
64 */ | |
65 | |
66 high_offset = (long) (offset >> 32); | |
67 | |
68 if (SetFilePointer(file->fd, (long) offset, &high_offset, | |
69 FILE_BEGIN) == INVALID_SET_FILE_POINTER) | |
70 { | |
71 /* | |
72 * INVALID_SET_FILE_POINTER is 0xffffffff and it can be valid | |
73 * value for large file so we need also to check GetLastError() | |
74 */ | |
75 | |
76 err = ngx_errno; | |
77 if (err != NO_ERROR) { | |
78 ngx_log_error(NGX_LOG_ERR, file->log, err, | |
79 "SeekFilePointer() failed"); | |
80 return NGX_ERROR; | |
81 } | |
82 } | |
83 } | |
84 | |
85 povlp = NULL; | |
86 | |
87 } else { | |
88 ovlp.Internal = 0; | |
89 ovlp.InternalHigh = 0; | |
90 ovlp.Offset = (u_long) offset; | |
91 ovlp.OffsetHigh = (u_long) (offset >> 32); | |
92 ovlp.hEvent = NULL; | |
93 | |
94 povlp = &ovlp; | |
95 } | |
96 | 93 |
97 if (ReadFile(file->fd, buf, size, &n, povlp) == 0) { | 94 if (ReadFile(file->fd, buf, size, &n, povlp) == 0) { |
98 err = ngx_errno; | 95 err = ngx_errno; |
99 | 96 |
100 if (err == ERROR_HANDLE_EOF) { | 97 if (err == ERROR_HANDLE_EOF) { |
101 return 0; | 98 return 0; |
102 } | 99 } |
103 | 100 |
104 ngx_log_error(NGX_LOG_ERR, file->log, err, "ReadFile() failed"); | 101 ngx_log_error(NGX_LOG_ERR, file->log, err, |
102 "ReadFile() \"%s\" failed", file->name.data); | |
105 return NGX_ERROR; | 103 return NGX_ERROR; |
106 } | 104 } |
107 | 105 |
108 file->offset += n; | 106 file->offset += n; |
109 | 107 |
112 | 110 |
113 | 111 |
114 ssize_t | 112 ssize_t |
115 ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) | 113 ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) |
116 { | 114 { |
117 long high_offset; | |
118 u_long n; | 115 u_long n; |
119 ngx_err_t err; | |
120 OVERLAPPED ovlp, *povlp; | 116 OVERLAPPED ovlp, *povlp; |
121 | 117 |
122 if (ngx_win32_version < NGX_WIN_NT) { | 118 ovlp.Internal = 0; |
123 | 119 ovlp.InternalHigh = 0; |
124 /* | 120 ovlp.Offset = (u_long) offset; |
125 * under Win9X the overlapped pointer must be NULL | 121 ovlp.OffsetHigh = (u_long) (offset >> 32); |
126 * so we have to use SetFilePointer() to set the offset | 122 ovlp.hEvent = NULL; |
127 */ | 123 |
128 | 124 povlp = &ovlp; |
129 if (file->offset != offset) { | |
130 | |
131 /* | |
132 * the maximum file size on the FAT16 is 2G, but on the FAT32 | |
133 * the size is 4G so we have to use high_offset | |
134 * because a single offset is signed value | |
135 */ | |
136 | |
137 high_offset = (long) (offset >> 32); | |
138 if (SetFilePointer(file->fd, (long) offset, &high_offset, | |
139 FILE_BEGIN) == INVALID_SET_FILE_POINTER) | |
140 { | |
141 /* | |
142 * INVALID_SET_FILE_POINTER is 0xffffffff and it can be valid | |
143 * value for large file so we need also to check GetLastError() | |
144 */ | |
145 | |
146 err = ngx_errno; | |
147 if (err != NO_ERROR) { | |
148 ngx_log_error(NGX_LOG_ERR, file->log, err, | |
149 "SeekFilePointer() failed"); | |
150 return NGX_ERROR; | |
151 } | |
152 } | |
153 } | |
154 | |
155 povlp = NULL; | |
156 | |
157 } else { | |
158 ovlp.Internal = 0; | |
159 ovlp.InternalHigh = 0; | |
160 ovlp.Offset = (u_long) offset; | |
161 ovlp.OffsetHigh = (u_long) (offset >> 32); | |
162 ovlp.hEvent = NULL; | |
163 | |
164 povlp = &ovlp; | |
165 } | |
166 | 125 |
167 if (WriteFile(file->fd, buf, size, &n, povlp) == 0) { | 126 if (WriteFile(file->fd, buf, size, &n, povlp) == 0) { |
168 ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "WriteFile() failed"); | 127 ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, |
128 "WriteFile() \"%s\" failed", file->name.data); | |
129 return NGX_ERROR; | |
130 } | |
131 | |
132 if (n != size) { | |
133 ngx_log_error(NGX_LOG_CRIT, file->log, 0, | |
134 "WriteFile() \"%s\" has written only %ul of %uz", | |
135 file->name.data, n, size); | |
169 return NGX_ERROR; | 136 return NGX_ERROR; |
170 } | 137 } |
171 | 138 |
172 file->offset += n; | 139 file->offset += n; |
173 | 140 |
251 | 218 |
252 return -1; | 219 return -1; |
253 } | 220 } |
254 | 221 |
255 | 222 |
256 ngx_int_t | 223 ngx_err_t |
257 ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) | 224 ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) |
258 { | 225 { |
259 u_char *name; | 226 u_char *name; |
260 ngx_int_t rc; | 227 ngx_err_t err; |
261 ngx_uint_t collision; | 228 ngx_uint_t collision; |
262 ngx_atomic_uint_t num; | 229 ngx_atomic_uint_t num; |
263 | 230 |
264 name = ngx_alloc(to->len + 1 + 10 + 1 + sizeof("DELETE"), log); | 231 name = ngx_alloc(to->len + 1 + 10 + 1 + sizeof("DELETE"), log); |
265 if (name == NULL) { | 232 if (name == NULL) { |
266 return NGX_ERROR; | 233 return NGX_ENOMEM; |
267 } | 234 } |
268 | 235 |
269 ngx_memcpy(name, to->data, to->len); | 236 ngx_memcpy(name, to->data, to->len); |
270 | 237 |
271 collision = 0; | 238 collision = 0; |
286 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, | 253 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, |
287 "MoveFile() \"%s\" to \"%s\" failed", to->data, name); | 254 "MoveFile() \"%s\" to \"%s\" failed", to->data, name); |
288 } | 255 } |
289 | 256 |
290 if (MoveFile((const char *) from->data, (const char *) to->data) == 0) { | 257 if (MoveFile((const char *) from->data, (const char *) to->data) == 0) { |
291 rc = NGX_ERROR; | 258 err = ngx_errno; |
292 | 259 |
293 } else { | 260 } else { |
294 rc = NGX_OK; | 261 err = 0; |
295 } | 262 } |
296 | 263 |
297 if (DeleteFile((const char *) name) == 0) { | 264 if (DeleteFile((const char *) name) == 0) { |
298 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, | 265 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, |
299 "DeleteFile() \"%s\" failed", name); | 266 "DeleteFile() \"%s\" failed", name); |
300 } | 267 } |
301 | 268 |
302 if (rc == NGX_ERROR) { | |
303 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, | |
304 "MoveFile() \"%s\" to \"%s\" failed", | |
305 from->data, to->data); | |
306 } | |
307 | |
308 /* mutex_unlock() */ | 269 /* mutex_unlock() */ |
309 | 270 |
310 ngx_free(name); | 271 ngx_free(name); |
311 | 272 |
312 return rc; | 273 return err; |
313 } | 274 } |
314 | 275 |
315 | 276 |
316 ngx_int_t | 277 ngx_int_t |
317 ngx_file_info(u_char *file, ngx_file_info_t *sb) | 278 ngx_file_info(u_char *file, ngx_file_info_t *sb) |
318 { | 279 { |
319 WIN32_FILE_ATTRIBUTE_DATA fa; | 280 size_t len; |
320 | 281 long rc; |
321 /* NT4 and Win98 */ | 282 u_short *u; |
322 | 283 ngx_err_t err; |
323 if (GetFileAttributesEx((char *) file, GetFileExInfoStandard, &fa) == 0) { | 284 WIN32_FILE_ATTRIBUTE_DATA fa; |
285 u_short utf16[NGX_UTF16_BUFLEN]; | |
286 | |
287 len = NGX_UTF16_BUFLEN; | |
288 | |
289 u = ngx_utf8_to_utf16(utf16, file, &len); | |
290 | |
291 if (u == NULL) { | |
324 return NGX_FILE_ERROR; | 292 return NGX_FILE_ERROR; |
293 } | |
294 | |
295 rc = GetFileAttributesExW(u, GetFileExInfoStandard, &fa); | |
296 | |
297 if (u != utf16) { | |
298 err = ngx_errno; | |
299 ngx_free(u); | |
300 ngx_set_errno(err); | |
325 } | 301 } |
326 | 302 |
327 sb->dwFileAttributes = fa.dwFileAttributes; | 303 sb->dwFileAttributes = fa.dwFileAttributes; |
328 sb->ftCreationTime = fa.ftCreationTime; | 304 sb->ftCreationTime = fa.ftCreationTime; |
329 sb->ftLastAccessTime = fa.ftLastAccessTime; | 305 sb->ftLastAccessTime = fa.ftLastAccessTime; |
330 sb->ftLastWriteTime = fa.ftLastWriteTime; | 306 sb->ftLastWriteTime = fa.ftLastWriteTime; |
331 sb->nFileSizeHigh = fa.nFileSizeHigh; | 307 sb->nFileSizeHigh = fa.nFileSizeHigh; |
332 sb->nFileSizeLow = fa.nFileSizeLow; | 308 sb->nFileSizeLow = fa.nFileSizeLow; |
333 | 309 |
334 return ~NGX_FILE_ERROR; | 310 return rc; |
335 } | 311 } |
336 | 312 |
337 | 313 |
338 ngx_int_t | 314 ngx_int_t |
339 ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s) | 315 ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s) |
531 | 507 |
532 | 508 |
533 ngx_int_t | 509 ngx_int_t |
534 ngx_directio_on(ngx_fd_t fd) | 510 ngx_directio_on(ngx_fd_t fd) |
535 { | 511 { |
536 return 0; | 512 return ~NGX_FILE_ERROR; |
537 } | 513 } |
538 | 514 |
539 | 515 |
540 ngx_int_t | 516 ngx_int_t |
541 ngx_directio_off(ngx_fd_t fd) | 517 ngx_directio_off(ngx_fd_t fd) |
542 { | 518 { |
543 return 0; | 519 return ~NGX_FILE_ERROR; |
544 } | 520 } |
545 | 521 |
546 | 522 |
547 size_t | 523 size_t |
548 ngx_fs_bsize(u_char *name) | 524 ngx_fs_bsize(u_char *name) |
562 return sc * bs; | 538 return sc * bs; |
563 } | 539 } |
564 | 540 |
565 | 541 |
566 static u_short * | 542 static u_short * |
567 ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t len) | 543 ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len) |
568 { | 544 { |
569 u_char *p; | 545 u_char *p; |
570 u_short *u, *last; | 546 u_short *u, *last; |
571 uint32_t n; | 547 uint32_t n; |
572 | 548 |
573 p = utf8; | 549 p = utf8; |
574 u = utf16; | 550 u = utf16; |
575 last = utf16 + len; | 551 last = utf16 + *len; |
576 | 552 |
577 while (u < last) { | 553 while (u < last) { |
578 | 554 |
579 if (*p < 0x80) { | 555 if (*p < 0x80) { |
580 *u = (u_short) *p; | 556 *u++ = (u_short) *p; |
581 | 557 |
582 if (*p == 0) { | 558 if (*p == 0) { |
559 *len = u - utf16; | |
583 return utf16; | 560 return utf16; |
584 } | 561 } |
585 | 562 |
586 u++; | |
587 p++; | 563 p++; |
588 | 564 |
589 continue; | 565 continue; |
590 } | 566 } |
591 | 567 |
605 u = malloc(((p - utf8) + ngx_strlen(p) + 1) * sizeof(u_short)); | 581 u = malloc(((p - utf8) + ngx_strlen(p) + 1) * sizeof(u_short)); |
606 if (u == NULL) { | 582 if (u == NULL) { |
607 return NULL; | 583 return NULL; |
608 } | 584 } |
609 | 585 |
610 ngx_memcpy(u, utf16, len * 2); | 586 ngx_memcpy(u, utf16, *len * 2); |
611 | 587 |
612 utf16 = u; | 588 utf16 = u; |
613 u += len; | 589 u += *len; |
614 | 590 |
615 for ( ;; ) { | 591 for ( ;; ) { |
616 | 592 |
617 if (*p < 0x80) { | 593 if (*p < 0x80) { |
618 *u = (u_short) *p; | 594 *u++ = (u_short) *p; |
619 | 595 |
620 if (*p == 0) { | 596 if (*p == 0) { |
597 *len = u - utf16; | |
621 return utf16; | 598 return utf16; |
622 } | 599 } |
623 | 600 |
624 u++; | |
625 p++; | 601 p++; |
626 | 602 |
627 continue; | 603 continue; |
628 } | 604 } |
629 | 605 |