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