Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

file.c
Go to the documentation of this file.
1 #include "ruby/ruby.h"
2 #include "ruby/encoding.h"
3 #include "internal.h"
4 #include <winbase.h>
5 #include <wchar.h>
6 #include <shlwapi.h>
7
8 #ifndef INVALID_FILE_ATTRIBUTES
9 # define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
10 #endif
11
12 /* cache 'encoding name' => 'code page' into a hash */
13 static struct code_page_table {
14 USHORT *table;
15 unsigned int count;
16 } rb_code_page;
17
18 #define IS_DIR_SEPARATOR_P(c) (c == L'\\' || c == L'/')
19 #define IS_DIR_UNC_P(c) (IS_DIR_SEPARATOR_P(c[0]) && IS_DIR_SEPARATOR_P(c[1]))
20
21 /* MultiByteToWideChar() doesn't work with code page 51932 */
22 #define INVALID_CODE_PAGE 51932
23 #define PATH_BUFFER_SIZE MAX_PATH * 2
24
25 #define insecure_obj_p(obj, level) ((level) >= 4 || ((level) > 0 && OBJ_TAINTED(obj)))
26
27 static inline void
28 replace_wchar(wchar_t *s, int find, int replace)
29 {
30 while (*s != 0) {
31 if (*s == find)
32 *s = replace;
33 s++;
34 }
35 }
36
37 /* Convert str from multibyte char to wchar with specified code page */
38 static inline void
39 convert_mb_to_wchar(const char *str, wchar_t **wstr, size_t *wstr_len, UINT code_page)
40 {
41 size_t len;
42
43 len = MultiByteToWideChar(code_page, 0, str, -1, NULL, 0) + 1;
44 *wstr = (wchar_t *)xmalloc(len * sizeof(wchar_t));
45
46 MultiByteToWideChar(code_page, 0, str, -1, *wstr, len);
47 *wstr_len = len - 2;
48 }
49
50 static inline void
51 convert_wchar_to_mb(const wchar_t *wstr, char **str, size_t *str_len, UINT code_page)
52 {
53 size_t len;
54
55 len = WideCharToMultiByte(code_page, 0, wstr, -1, NULL, 0, NULL, NULL);
56 *str = (char *)xmalloc(len * sizeof(char));
57 WideCharToMultiByte(code_page, 0, wstr, -1, *str, len, NULL, NULL);
58
59 /* do not count terminator as part of the string length */
60 *str_len = len - 1;
61 }
62
63 /*
64 Return user's home directory using environment variables combinations.
65 Memory allocated by this function should be manually freed afterwards.
66
67 Try:
68 HOME, HOMEDRIVE + HOMEPATH and USERPROFILE environment variables
69 TODO: Special Folders - Profile and Personal
70 */
71 static wchar_t *
72 home_dir(void)
73 {
74 wchar_t *buffer = NULL;
75 size_t buffer_len = 0, len = 0;
76 size_t home_env = 0;
77
78 /*
79 GetEnvironmentVariableW when used with NULL will return the required
80 buffer size and its terminating character.
81 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
82 */
83
84 if (len = GetEnvironmentVariableW(L"HOME", NULL, 0)) {
85 buffer_len = len;
86 home_env = 1;
87 }
88 else if (len = GetEnvironmentVariableW(L"HOMEDRIVE", NULL, 0)) {
89 buffer_len = len;
90 if (len = GetEnvironmentVariableW(L"HOMEPATH", NULL, 0)) {
91 buffer_len += len;
92 home_env = 2;
93 }
94 else {
95 buffer_len = 0;
96 }
97 }
98 else if (len = GetEnvironmentVariableW(L"USERPROFILE", NULL, 0)) {
99 buffer_len = len;
100 home_env = 3;
101 }
102
103 /* allocate buffer */
104 if (home_env)
105 buffer = (wchar_t *)xmalloc(buffer_len * sizeof(wchar_t));
106
107 switch (home_env) {
108 case 1:
109 /* HOME */
110 GetEnvironmentVariableW(L"HOME", buffer, buffer_len);
111 break;
112 case 2:
113 /* HOMEDRIVE + HOMEPATH */
114 len = GetEnvironmentVariableW(L"HOMEDRIVE", buffer, buffer_len);
115 GetEnvironmentVariableW(L"HOMEPATH", buffer + len, buffer_len - len);
116 break;
117 case 3:
118 /* USERPROFILE */
119 GetEnvironmentVariableW(L"USERPROFILE", buffer, buffer_len);
120 break;
121 default:
122 break;
123 }
124
125 if (home_env) {
126 /* sanitize backslashes with forwardslashes */
127 replace_wchar(buffer, L'\\', L'/');
128
129 return buffer;
130 }
131
132 return NULL;
133 }
134
135 /* Remove trailing invalid ':$DATA' of the path. */
136 static inline size_t
137 remove_invalid_alternative_data(wchar_t *wfullpath, size_t size)
138 {
139 static const wchar_t prime[] = L":$DATA";
140 enum { prime_len = (sizeof(prime) / sizeof(wchar_t)) -1 };
141
142 if (size <= prime_len || _wcsnicmp(wfullpath + size - prime_len, prime, prime_len) != 0)
143 return size;
144
145 /* alias of stream */
146 /* get rid of a bug of x64 VC++ */
147 if (wfullpath[size - (prime_len + 1)] == ':') {
148 /* remove trailing '::$DATA' */
149 size -= prime_len + 1; /* prime */
150 wfullpath[size] = L'\0';
151 }
152 else {
153 /* remove trailing ':$DATA' of paths like '/aa:a:$DATA' */
154 wchar_t *pos = wfullpath + size - (prime_len + 1);
155 while (!IS_DIR_SEPARATOR_P(*pos) && pos != wfullpath) {
156 if (*pos == L':') {
157 size -= prime_len; /* alternative */
158 wfullpath[size] = L'\0';
159 break;
160 }
161 pos--;
162 }
163 }
164 return size;
165 }
166
167 /* Return system code page. */
168 static inline UINT
169 system_code_page(void)
170 {
171 return AreFileApisANSI() ? CP_ACP : CP_OEMCP;
172 }
173
174 void rb_enc_foreach_name(int (*func)(st_data_t name, st_data_t idx, st_data_t arg), st_data_t arg);
175
176 static int
177 code_page_i(st_data_t name, st_data_t idx, st_data_t arg)
178 {
179 const char *n = (const char *)name;
180 if (strncmp("CP", n, 2) == 0) {
181 int code_page = atoi(n + 2);
182 if (code_page != 0) {
183 struct code_page_table *cp = (struct code_page_table *)arg;
184 unsigned int count = cp->count;
185 USHORT *table = cp->table;
186 if (count <= idx) {
187 unsigned int i = count;
188 cp->count = count = ((idx + 4) & ~31 | 28);
189 cp->table = table = realloc(table, count * sizeof(*table));
190 while (i < count) table[i++] = INVALID_CODE_PAGE;
191 }
192 table[idx] = (USHORT)code_page;
193 }
194 }
195 return ST_CONTINUE;
196 }
197
198 /*
199 Return code page number of the encoding.
200 Cache code page into a hash for performance since finding the code page in
201 Encoding#names is slow.
202 */
203 static UINT
204 code_page(rb_encoding *enc)
205 {
206 int enc_idx;
207
208 if (!enc)
209 return system_code_page();
210
211 enc_idx = rb_enc_to_index(enc);
212
213 /* map US-ASCII and ASCII-8bit as code page 1252 (us-ascii) */
214 if (enc_idx == rb_usascii_encindex() || enc_idx == rb_ascii8bit_encindex()) {
215 return 1252;
216 }
217
218 if (0 <= enc_idx && (unsigned int)enc_idx < rb_code_page.count)
219 return rb_code_page.table[enc_idx];
220
221 return INVALID_CODE_PAGE;
222 }
223
224 #define fix_string_encoding(str, encoding) rb_str_conv_enc((str), (encoding), rb_utf8_encoding())
225
226 /*
227 Replace the last part of the path to long name.
228 We try to avoid to call FindFirstFileW() since it takes long time.
229 */
230 static inline size_t
231 replace_to_long_name(wchar_t **wfullpath, size_t size, int heap)
232 {
233 WIN32_FIND_DATAW find_data;
234 HANDLE find_handle;
235
236 /*
237 Skip long name conversion if the path is already long name.
238 Short name is 8.3 format.
239 http://en.wikipedia.org/wiki/8.3_filename
240 This check can be skipped for directory components that have file
241 extensions longer than 3 characters, or total lengths longer than
242 12 characters.
243 http://msdn.microsoft.com/en-us/library/windows/desktop/aa364980(v=vs.85).aspx
244 */
245 size_t const max_short_name_size = 8 + 1 + 3;
246 size_t const max_extension_size = 3;
247 size_t path_len = 1, extension_len = 0;
248 wchar_t *pos = *wfullpath;
249
250 if (size == 3 && pos[1] == L':' && pos[2] == L'\\' && pos[3] == L'\0') {
251 /* root path doesn't need short name expansion */
252 return size;
253 }
254
255 /* skip long name conversion if path contains wildcard characters */
256 if (wcspbrk(pos, L"*?")) {
257 return size;
258 }
259
260 pos = *wfullpath + size - 1;
261 while (!IS_DIR_SEPARATOR_P(*pos) && pos != *wfullpath) {
262 if (!extension_len && *pos == L'.') {
263 extension_len = path_len - 1;
264 }
265 if (path_len > max_short_name_size || extension_len > max_extension_size) {
266 return size;
267 }
268 path_len++;
269 pos--;
270 }
271
272 find_handle = FindFirstFileW(*wfullpath, &find_data);
273 if (find_handle != INVALID_HANDLE_VALUE) {
274 size_t trail_pos = wcslen(*wfullpath);
275 size_t file_len = wcslen(find_data.cFileName);
276
277 FindClose(find_handle);
278 while (trail_pos > 0) {
279 if (IS_DIR_SEPARATOR_P((*wfullpath)[trail_pos]))
280 break;
281 trail_pos--;
282 }
283 size = trail_pos + 1 + file_len;
284 if ((size + 1) > sizeof(*wfullpath) / sizeof((*wfullpath)[0])) {
285 wchar_t *buf = (wchar_t *)xmalloc((size + 1) * sizeof(wchar_t));
286 wcsncpy(buf, *wfullpath, trail_pos + 1);
287 if (heap)
288 xfree(*wfullpath);
289 *wfullpath = buf;
290 }
291 wcsncpy(*wfullpath + trail_pos + 1, find_data.cFileName, file_len + 1);
292 }
293 return size;
294 }
295
296 static inline VALUE
297 get_user_from_path(wchar_t **wpath, int offset, UINT cp, UINT path_cp, rb_encoding *path_encoding)
298 {
299 VALUE result, tmp;
300 wchar_t *wuser = *wpath + offset;
301 wchar_t *pos = wuser;
302 char *user;
303 size_t size;
304
305 while (!IS_DIR_SEPARATOR_P(*pos) && *pos != '\0')
306 pos++;
307
308 *pos = '\0';
309 convert_wchar_to_mb(wuser, &user, &size, cp);
310
311 /* convert to VALUE and set the path encoding */
312 if (path_cp == INVALID_CODE_PAGE) {
313 tmp = rb_enc_str_new(user, size, rb_utf8_encoding());
314 result = rb_str_encode(tmp, rb_enc_from_encoding(path_encoding), 0, Qnil);
315 rb_str_resize(tmp, 0);
316 }
317 else {
318 result = rb_enc_str_new(user, size, path_encoding);
319 }
320
321 if (user)
322 xfree(user);
323
324 return result;
325 }
326
327 VALUE
328 rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_name, VALUE result)
329 {
330 size_t size = 0, wpath_len = 0, wdir_len = 0, whome_len = 0;
331 size_t buffer_len = 0;
332 char *fullpath = NULL;
333 wchar_t *wfullpath = NULL, *wpath = NULL, *wpath_pos = NULL;
334 wchar_t *wdir = NULL, *wdir_pos = NULL;
335 wchar_t *whome = NULL, *buffer = NULL, *buffer_pos = NULL;
336 UINT path_cp, cp;
337 VALUE path = fname, dir = dname;
338 wchar_t wfullpath_buffer[PATH_BUFFER_SIZE];
339 wchar_t path_drive = L'\0', dir_drive = L'\0';
340 int ignore_dir = 0;
341 rb_encoding *path_encoding;
342 int tainted = 0;
343
344 /* tainted if path is tainted */
345 tainted = OBJ_TAINTED(path);
346
347 /* get path encoding */
348 if (NIL_P(dir)) {
349 path_encoding = rb_enc_get(path);
350 }
351 else {
352 path_encoding = rb_enc_check(path, dir);
353 }
354
355 cp = path_cp = code_page(path_encoding);
356
357 /* workaround invalid codepage */
358 if (path_cp == INVALID_CODE_PAGE) {
359 cp = CP_UTF8;
360 if (!NIL_P(path)) {
361 path = fix_string_encoding(path, path_encoding);
362 }
363 }
364
365 /* convert char * to wchar_t */
366 if (!NIL_P(path)) {
367 convert_mb_to_wchar(RSTRING_PTR(path), &wpath, &wpath_len, cp);
368 wpath_pos = wpath;
369 }
370
371 /* determine if we need the user's home directory */
372 /* expand '~' only if NOT rb_file_absolute_path() where `abs_mode` is 1 */
373 if (abs_mode == 0 && wpath_len > 0 && wpath_pos[0] == L'~' &&
374 (wpath_len == 1 || IS_DIR_SEPARATOR_P(wpath_pos[1]))) {
375 /* tainted if expanding '~' */
376 tainted = 1;
377
378 whome = home_dir();
379 if (whome == NULL) {
380 xfree(wpath);
381 rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
382 }
383 whome_len = wcslen(whome);
384
385 if (PathIsRelativeW(whome) && !(whome_len >= 2 && IS_DIR_UNC_P(whome))) {
386 xfree(wpath);
387 xfree(whome);
388 rb_raise(rb_eArgError, "non-absolute home");
389 }
390
391 if (path_cp == INVALID_CODE_PAGE || rb_enc_str_asciionly_p(path)) {
392 /* use filesystem encoding if expanding home dir */
393 path_encoding = rb_filesystem_encoding();
394 cp = path_cp = system_code_page();
395 }
396
397 /* ignores dir since we are expanding home */
398 ignore_dir = 1;
399
400 /* exclude ~ from the result */
401 wpath_pos++;
402 wpath_len--;
403
404 /* exclude separator if present */
405 if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) {
406 wpath_pos++;
407 wpath_len--;
408 }
409 }
410 else if (wpath_len >= 2 && wpath_pos[1] == L':') {
411 if (wpath_len >= 3 && IS_DIR_SEPARATOR_P(wpath_pos[2])) {
412 /* ignore dir since path contains a drive letter and a root slash */
413 ignore_dir = 1;
414 }
415 else {
416 /* determine if we ignore dir or not later */
417 path_drive = wpath_pos[0];
418 }
419 }
420 else if (abs_mode == 0 && wpath_len >= 2 && wpath_pos[0] == L'~') {
421 result = get_user_from_path(&wpath_pos, 1, cp, path_cp, path_encoding);
422
423 if (wpath)
424 xfree(wpath);
425
426 rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result));
427 }
428
429 /* convert dir */
430 if (!ignore_dir && !NIL_P(dir)) {
431 /* fix string encoding */
432 if (path_cp == INVALID_CODE_PAGE) {
433 dir = fix_string_encoding(dir, path_encoding);
434 }
435
436 /* convert char * to wchar_t */
437 if (!NIL_P(dir)) {
438 convert_mb_to_wchar(RSTRING_PTR(dir), &wdir, &wdir_len, cp);
439 wdir_pos = wdir;
440 }
441
442 if (abs_mode == 0 && wdir_len > 0 && wdir_pos[0] == L'~' &&
443 (wdir_len == 1 || IS_DIR_SEPARATOR_P(wdir_pos[1]))) {
444 /* tainted if expanding '~' */
445 tainted = 1;
446
447 whome = home_dir();
448 if (whome == NULL) {
449 xfree(wpath);
450 xfree(wdir);
451 rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
452 }
453 whome_len = wcslen(whome);
454
455 if (PathIsRelativeW(whome) && !(whome_len >= 2 && IS_DIR_UNC_P(whome))) {
456 xfree(wpath);
457 xfree(wdir);
458 xfree(whome);
459 rb_raise(rb_eArgError, "non-absolute home");
460 }
461
462 /* exclude ~ from the result */
463 wdir_pos++;
464 wdir_len--;
465
466 /* exclude separator if present */
467 if (wdir_len && IS_DIR_SEPARATOR_P(wdir_pos[0])) {
468 wdir_pos++;
469 wdir_len--;
470 }
471 }
472 else if (wdir_len >= 2 && wdir[1] == L':') {
473 dir_drive = wdir[0];
474 if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) {
475 wdir_len = 2;
476 }
477 }
478 else if (wdir_len >= 2 && IS_DIR_UNC_P(wdir)) {
479 /* UNC path */
480 if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) {
481 /* cut the UNC path tail to '//host/share' */
482 size_t separators = 0;
483 size_t pos = 2;
484 while (pos < wdir_len && separators < 2) {
485 if (IS_DIR_SEPARATOR_P(wdir[pos])) {
486 separators++;
487 }
488 pos++;
489 }
490 if (separators == 2)
491 wdir_len = pos - 1;
492 }
493 }
494 else if (abs_mode == 0 && wdir_len >= 2 && wdir_pos[0] == L'~') {
495 result = get_user_from_path(&wdir_pos, 1, cp, path_cp, path_encoding);
496 if (wpath)
497 xfree(wpath);
498
499 if (wdir)
500 xfree(wdir);
501
502 rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result));
503 }
504 }
505
506 /* determine if we ignore dir or not */
507 if (!ignore_dir && path_drive && dir_drive) {
508 if (towupper(path_drive) == towupper(dir_drive)) {
509 /* exclude path drive letter to use dir */
510 wpath_pos += 2;
511 wpath_len -= 2;
512 }
513 else {
514 /* ignore dir since path drive is different from dir drive */
515 ignore_dir = 1;
516 wdir_len = 0;
517 }
518 }
519
520 if (!ignore_dir && wpath_len >= 2 && IS_DIR_UNC_P(wpath)) {
521 /* ignore dir since path has UNC root */
522 ignore_dir = 1;
523 wdir_len = 0;
524 }
525 else if (!ignore_dir && wpath_len >= 1 && IS_DIR_SEPARATOR_P(wpath[0]) &&
526 !dir_drive && !(wdir_len >= 2 && IS_DIR_UNC_P(wdir))) {
527 /* ignore dir since path has root slash and dir doesn't have drive or UNC root */
528 ignore_dir = 1;
529 wdir_len = 0;
530 }
531
532 buffer_len = wpath_len + 1 + wdir_len + 1 + whome_len + 1;
533
534 buffer = buffer_pos = (wchar_t *)xmalloc((buffer_len + 1) * sizeof(wchar_t));
535
536 /* add home */
537 if (whome_len) {
538 wcsncpy(buffer_pos, whome, whome_len);
539 buffer_pos += whome_len;
540 }
541
542 /* Add separator if required */
543 if (whome_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) {
544 buffer_pos[0] = L'\\';
545 buffer_pos++;
546 }
547
548 if (wdir_len) {
549 /* tainted if dir is used and dir is tainted */
550 if (!tainted && OBJ_TAINTED(dir))
551 tainted = 1;
552
553 wcsncpy(buffer_pos, wdir_pos, wdir_len);
554 buffer_pos += wdir_len;
555 }
556
557 /* add separator if required */
558 if (wdir_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) {
559 buffer_pos[0] = L'\\';
560 buffer_pos++;
561 }
562
563 /* now deal with path */
564 if (wpath_len) {
565 wcsncpy(buffer_pos, wpath_pos, wpath_len);
566 buffer_pos += wpath_len;
567 }
568
569 /* GetFullPathNameW requires at least "." to determine current directory */
570 if (wpath_len == 0) {
571 buffer_pos[0] = L'.';
572 buffer_pos++;
573 }
574
575 /* Ensure buffer is NULL terminated */
576 buffer_pos[0] = L'\0';
577
578 /* tainted if path is relative */
579 if (!tainted && PathIsRelativeW(buffer) && !(buffer_len >= 2 && IS_DIR_UNC_P(buffer)))
580 tainted = 1;
581
582 /* FIXME: Make this more robust */
583 /* Determine require buffer size */
584 size = GetFullPathNameW(buffer, PATH_BUFFER_SIZE, wfullpath_buffer, NULL);
585 if (size > PATH_BUFFER_SIZE) {
586 /* allocate more memory than alloted originally by PATH_BUFFER_SIZE */
587 wfullpath = (wchar_t *)xmalloc(size * sizeof(wchar_t));
588 size = GetFullPathNameW(buffer, size, wfullpath, NULL);
589 }
590 else {
591 wfullpath = wfullpath_buffer;
592 }
593
594 /* Remove any trailing slashes */
595 if (IS_DIR_SEPARATOR_P(wfullpath[size - 1]) &&
596 wfullpath[size - 2] != L':' &&
597 !(size == 2 && IS_DIR_UNC_P(wfullpath))) {
598 size -= 1;
599 wfullpath[size] = L'\0';
600 }
601
602 /* Remove any trailing dot */
603 if (wfullpath[size - 1] == L'.') {
604 size -= 1;
605 wfullpath[size] = L'\0';
606 }
607
608 /* removes trailing invalid ':$DATA' */
609 size = remove_invalid_alternative_data(wfullpath, size);
610
611 /* Replace the trailing path to long name */
612 if (long_name)
613 size = replace_to_long_name(&wfullpath, size, (wfullpath != wfullpath_buffer));
614
615 /* sanitize backslashes with forwardslashes */
616 replace_wchar(wfullpath, L'\\', L'/');
617
618 /* convert to char * */
619 size = WideCharToMultiByte(cp, 0, wfullpath, size, NULL, 0, NULL, NULL);
620 if (size > (size_t)RSTRING_LEN(result)) {
621 rb_str_modify(result);
622 rb_str_resize(result, size);
623 }
624
625 WideCharToMultiByte(cp, 0, wfullpath, size, RSTRING_PTR(result), size, NULL, NULL);
626 rb_str_set_len(result, size);
627
628 /* convert to VALUE and set the path encoding */
629 if (path_cp == INVALID_CODE_PAGE) {
630 VALUE tmp;
631 size_t len;
632
633 rb_enc_associate(result, rb_utf8_encoding());
634 ENC_CODERANGE_CLEAR(result);
635 tmp = rb_str_encode(result, rb_enc_from_encoding(path_encoding), 0, Qnil);
636 len = RSTRING_LEN(tmp);
637 rb_str_modify(result);
638 rb_str_resize(result, len);
639 memcpy(RSTRING_PTR(result), RSTRING_PTR(tmp), len);
640 rb_str_resize(tmp, 0);
641 }
642 rb_enc_associate(result, path_encoding);
643 ENC_CODERANGE_CLEAR(result);
644
645 /* makes the result object tainted if expanding tainted strings or returning modified path */
646 if (tainted)
647 OBJ_TAINT(result);
648
649 /* TODO: better cleanup */
650 if (buffer)
651 xfree(buffer);
652
653 if (wpath)
654 xfree(wpath);
655
656 if (wdir)
657 xfree(wdir);
658
659 if (whome)
660 xfree(whome);
661
662 if (wfullpath && wfullpath != wfullpath_buffer)
663 xfree(wfullpath);
664
665 if (fullpath)
666 xfree(fullpath);
667
668 return result;
669 }
670
671 int
672 rb_file_load_ok(const char *path)
673 {
674 DWORD attr;
675 int ret = 1;
676 size_t len;
677 wchar_t* wpath;
678
679 convert_mb_to_wchar(path, &wpath, &len, CP_UTF8);
680
681 attr = GetFileAttributesW(wpath);
682 if (attr == INVALID_FILE_ATTRIBUTES ||
683 (attr & FILE_ATTRIBUTE_DIRECTORY)) {
684 ret = 0;
685 }
686 else {
687 HANDLE h = CreateFileW(wpath, GENERIC_READ,
688 FILE_SHARE_READ | FILE_SHARE_WRITE,
689 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
690 if (h != INVALID_HANDLE_VALUE) {
691 CloseHandle(h);
692 }
693 else {
694 ret = 0;
695 }
696 }
697 xfree(wpath);
698 return ret;
699 }
700
701 void
702 Init_w32_codepage(void)
703 {
704 if (rb_code_page.count) return;
705 rb_enc_foreach_name(code_page_i, (st_data_t)&rb_code_page);
706 }
code_page_i
static int code_page_i(st_data_t name, st_data_t idx, st_data_t arg)
Definition: file.c:177
rb_enc_check
rb_encoding * rb_enc_check(VALUE str1, VALUE str2)
Definition: encoding.c:838
system_code_page
static UINT system_code_page(void)
Definition: file.c:169
count
int count
Definition: encoding.c:48
ruby.h
code_page_table::count
unsigned int count
Definition: file.c:15
ST_CONTINUE
Definition: st.h:100
ENC_CODERANGE_CLEAR
#define ENC_CODERANGE_CLEAR(obj)
Definition: encoding.h:56
rb_enc_from_encoding
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:102
rb_str_set_len
void rb_str_set_len(VALUE, long)
Definition: string.c:2008
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
PATH_BUFFER_SIZE
#define PATH_BUFFER_SIZE
Definition: file.c:23
rb_enc_associate
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Definition: encoding.c:826
IS_DIR_SEPARATOR_P
#define IS_DIR_SEPARATOR_P(c)
Definition: file.c:18
Init_w32_codepage
void Init_w32_codepage(void)
Definition: file.c:702
rb_utf8_encoding
rb_encoding * rb_utf8_encoding(void)
Definition: encoding.c:1242
OBJ_TAINTED
#define OBJ_TAINTED(x)
Definition: ruby.h:1176
st_data_t
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
Definition: st.h:20
convert_wchar_to_mb
static void convert_wchar_to_mb(const wchar_t *wstr, char **str, size_t *str_len, UINT code_page)
Definition: file.c:51
code_page
static UINT code_page(rb_encoding *enc)
Definition: file.c:204
DWORD
IUnknown DWORD
Definition: win32ole.c:149
remove_invalid_alternative_data
static size_t remove_invalid_alternative_data(wchar_t *wfullpath, size_t size)
Definition: file.c:137
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
rb_enc_foreach_name
void rb_enc_foreach_name(int(*func)(st_data_t name, st_data_t idx, st_data_t arg), st_data_t arg)
Definition: encoding.c:1947
realloc
#define realloc
Definition: ripper.c:97
encoding.h
rb_str_resize
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2025
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:841
func
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
fix_string_encoding
#define fix_string_encoding(str, encoding)
Definition: file.c:224
home_dir
static wchar_t * home_dir(void)
Definition: file.c:72
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
internal.h
Qnil
#define Qnil
Definition: ruby.h:427
OBJ_TAINT
#define OBJ_TAINT(x)
Definition: ruby.h:1177
VALUE
unsigned long VALUE
Definition: ruby.h:88
result
static VALUE result
Definition: nkf.c:40
rb_usascii_encindex
#define rb_usascii_encindex()
Definition: internal.h:404
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:845
rb_str_modify
void rb_str_modify(VALUE)
Definition: string.c:1484
rb_enc_get
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:832
size
int size
Definition: encoding.c:49
replace_to_long_name
static size_t replace_to_long_name(wchar_t **wfullpath, size_t size, int heap)
Definition: file.c:231
xmalloc
#define xmalloc
Definition: defines.h:108
rb_code_page
static struct code_page_table rb_code_page
get_user_from_path
static VALUE get_user_from_path(wchar_t **wpath, int offset, UINT cp, UINT path_cp, rb_encoding *path_encoding)
Definition: file.c:297
rb_filesystem_encoding
rb_encoding * rb_filesystem_encoding(void)
Definition: encoding.c:1309
code_page_table::table
USHORT * table
Definition: file.c:14
rb_enc_str_new
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:548
convert_mb_to_wchar
static void convert_mb_to_wchar(const char *str, wchar_t **wstr, size_t *wstr_len, UINT code_page)
Definition: file.c:39
name
const char * name
Definition: nkf.c:208
rb_file_load_ok
int rb_file_load_ok(const char *path)
Definition: file.c:5391
StringValuePtr
#define StringValuePtr(v)
Definition: ruby.h:540
rb_enc_to_index
#define rb_enc_to_index(enc)
Definition: encoding.h:77
INVALID_CODE_PAGE
#define INVALID_CODE_PAGE
Definition: file.c:22
rb_str_encode
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Definition: transcode.c:2885
xfree
void void xfree(void *)
code_page_table
Definition: file.c:13
rb_enc_str_asciionly_p
int rb_enc_str_asciionly_p(VALUE)
Definition: string.c:448
NULL
#define NULL
Definition: _sdbm.c:103
INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES
Definition: file.c:9
rb_ascii8bit_encindex
#define rb_ascii8bit_encindex()
Definition: internal.h:402
rb_eArgError
VALUE rb_eArgError
Definition: error.c:549
IS_DIR_UNC_P
#define IS_DIR_UNC_P(c)
Definition: file.c:19
replace_wchar
static void replace_wchar(wchar_t *s, int find, int replace)
Definition: file.c:28
rb_file_expand_path_internal
VALUE rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_name, VALUE result)
Definition: file.c:3054
OnigEncodingTypeST
Definition: oniguruma.h:158