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