Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 #include "ruby/ruby.h" 00002 #include "ruby/encoding.h" 00003 #include <winbase.h> 00004 #include <wchar.h> 00005 #include <shlwapi.h> 00006 00007 #ifndef INVALID_FILE_ATTRIBUTES 00008 # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) 00009 #endif 00010 00011 /* cache 'encoding name' => 'code page' into a hash */ 00012 static VALUE rb_code_page; 00013 00014 #define IS_DIR_SEPARATOR_P(c) (c == L'\\' || c == L'/') 00015 #define IS_DIR_UNC_P(c) (IS_DIR_SEPARATOR_P(c[0]) && IS_DIR_SEPARATOR_P(c[1])) 00016 00017 /* MultiByteToWideChar() doesn't work with code page 51932 */ 00018 #define INVALID_CODE_PAGE 51932 00019 #define PATH_BUFFER_SIZE MAX_PATH * 2 00020 00021 #define insecure_obj_p(obj, level) ((level) >= 4 || ((level) > 0 && OBJ_TAINTED(obj))) 00022 00023 static inline void 00024 replace_wchar(wchar_t *s, int find, int replace) 00025 { 00026 while (*s != 0) { 00027 if (*s == find) 00028 *s = replace; 00029 s++; 00030 } 00031 } 00032 00033 /* Convert str from multibyte char to wchar with specified code page */ 00034 static inline void 00035 convert_mb_to_wchar(VALUE str, wchar_t **wstr, wchar_t **wstr_pos, size_t *wstr_len, UINT code_page) 00036 { 00037 size_t len; 00038 00039 if (NIL_P(str)) 00040 return; 00041 00042 len = MultiByteToWideChar(code_page, 0, RSTRING_PTR(str), -1, NULL, 0) + 1; 00043 *wstr = (wchar_t *)xmalloc(len * sizeof(wchar_t)); 00044 if (wstr_pos) 00045 *wstr_pos = *wstr; 00046 00047 MultiByteToWideChar(code_page, 0, RSTRING_PTR(str), -1, *wstr, len); 00048 *wstr_len = len - 2; 00049 } 00050 00051 static inline void 00052 convert_wchar_to_mb(const wchar_t *wstr, char **str, size_t *str_len, UINT code_page) 00053 { 00054 size_t len; 00055 00056 len = WideCharToMultiByte(code_page, 0, wstr, -1, NULL, 0, NULL, NULL); 00057 *str = (char *)xmalloc(len * sizeof(char)); 00058 WideCharToMultiByte(code_page, 0, wstr, -1, *str, len, NULL, NULL); 00059 00060 /* do not count terminator as part of the string length */ 00061 *str_len = len - 1; 00062 } 00063 00064 /* 00065 Return user's home directory using environment variables combinations. 00066 Memory allocated by this function should be manually freed afterwards. 00067 00068 Try: 00069 HOME, HOMEDRIVE + HOMEPATH and USERPROFILE environment variables 00070 TODO: Special Folders - Profile and Personal 00071 */ 00072 static wchar_t * 00073 home_dir(void) 00074 { 00075 wchar_t *buffer = NULL; 00076 size_t buffer_len = 0, len = 0; 00077 size_t home_env = 0; 00078 00079 /* 00080 GetEnvironmentVariableW when used with NULL will return the required 00081 buffer size and its terminating character. 00082 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx 00083 */ 00084 00085 if (len = GetEnvironmentVariableW(L"HOME", NULL, 0)) { 00086 buffer_len = len; 00087 home_env = 1; 00088 } 00089 else if (len = GetEnvironmentVariableW(L"HOMEDRIVE", NULL, 0)) { 00090 buffer_len = len; 00091 if (len = GetEnvironmentVariableW(L"HOMEPATH", NULL, 0)) { 00092 buffer_len += len; 00093 home_env = 2; 00094 } 00095 else { 00096 buffer_len = 0; 00097 } 00098 } 00099 else if (len = GetEnvironmentVariableW(L"USERPROFILE", NULL, 0)) { 00100 buffer_len = len; 00101 home_env = 3; 00102 } 00103 00104 /* allocate buffer */ 00105 if (home_env) 00106 buffer = (wchar_t *)xmalloc(buffer_len * sizeof(wchar_t)); 00107 00108 switch (home_env) { 00109 case 1: 00110 /* HOME */ 00111 GetEnvironmentVariableW(L"HOME", buffer, buffer_len); 00112 break; 00113 case 2: 00114 /* HOMEDRIVE + HOMEPATH */ 00115 len = GetEnvironmentVariableW(L"HOMEDRIVE", buffer, buffer_len); 00116 GetEnvironmentVariableW(L"HOMEPATH", buffer + len, buffer_len - len); 00117 break; 00118 case 3: 00119 /* USERPROFILE */ 00120 GetEnvironmentVariableW(L"USERPROFILE", buffer, buffer_len); 00121 break; 00122 default: 00123 break; 00124 } 00125 00126 if (home_env) { 00127 /* sanitize backslashes with forwardslashes */ 00128 replace_wchar(buffer, L'\\', L'/'); 00129 00130 return buffer; 00131 } 00132 00133 return NULL; 00134 } 00135 00136 /* Remove trailing invalid ':$DATA' of the path. */ 00137 static inline size_t 00138 remove_invalid_alternative_data(wchar_t *wfullpath, size_t size) 00139 { 00140 static const wchar_t prime[] = L":$DATA"; 00141 enum { prime_len = (sizeof(prime) / sizeof(wchar_t)) -1 }; 00142 00143 if (size <= prime_len || _wcsnicmp(wfullpath + size - prime_len, prime, prime_len) != 0) 00144 return size; 00145 00146 /* alias of stream */ 00147 /* get rid of a bug of x64 VC++ */ 00148 if (wfullpath[size - (prime_len + 1)] == ':') { 00149 /* remove trailing '::$DATA' */ 00150 size -= prime_len + 1; /* prime */ 00151 wfullpath[size] = L'\0'; 00152 } 00153 else { 00154 /* remove trailing ':$DATA' of paths like '/aa:a:$DATA' */ 00155 wchar_t *pos = wfullpath + size - (prime_len + 1); 00156 while (!IS_DIR_SEPARATOR_P(*pos) && pos != wfullpath) { 00157 if (*pos == L':') { 00158 size -= prime_len; /* alternative */ 00159 wfullpath[size] = L'\0'; 00160 break; 00161 } 00162 pos--; 00163 } 00164 } 00165 return size; 00166 } 00167 00168 /* Return system code page. */ 00169 static inline UINT 00170 system_code_page(void) 00171 { 00172 return AreFileApisANSI() ? CP_ACP : CP_OEMCP; 00173 } 00174 00175 /* 00176 Return code page number of the encoding. 00177 Cache code page into a hash for performance since finding the code page in 00178 Encoding#names is slow. 00179 */ 00180 static UINT 00181 code_page(rb_encoding *enc) 00182 { 00183 VALUE code_page_value, name_key; 00184 VALUE encoding, names_ary = Qundef, name; 00185 char *enc_name; 00186 struct RString fake_str; 00187 ID names; 00188 long i; 00189 00190 if (!enc) 00191 return system_code_page(); 00192 00193 enc_name = (char *)rb_enc_name(enc); 00194 00195 fake_str.basic.flags = T_STRING|RSTRING_NOEMBED; 00196 fake_str.basic.klass = rb_cString; 00197 fake_str.as.heap.len = strlen(enc_name); 00198 fake_str.as.heap.ptr = enc_name; 00199 fake_str.as.heap.aux.capa = fake_str.as.heap.len; 00200 name_key = (VALUE)&fake_str; 00201 ENCODING_CODERANGE_SET(name_key, rb_usascii_encindex(), ENC_CODERANGE_7BIT); 00202 00203 code_page_value = rb_hash_lookup(rb_code_page, name_key); 00204 if (code_page_value != Qnil) 00205 return (UINT)FIX2INT(code_page_value); 00206 00207 name_key = rb_usascii_str_new2(enc_name); 00208 00209 encoding = rb_enc_from_encoding(enc); 00210 if (!NIL_P(encoding)) { 00211 CONST_ID(names, "names"); 00212 names_ary = rb_funcall(encoding, names, 0); 00213 } 00214 00215 /* map US-ASCII and ASCII-8bit as code page 20127 (us-ascii) */ 00216 if (enc == rb_usascii_encoding() || enc == rb_ascii8bit_encoding()) { 00217 UINT code_page = 20127; 00218 rb_hash_aset(rb_code_page, name_key, INT2FIX(code_page)); 00219 return code_page; 00220 } 00221 00222 if (names_ary != Qundef) { 00223 for (i = 0; i < RARRAY_LEN(names_ary); i++) { 00224 name = RARRAY_PTR(names_ary)[i]; 00225 if (strncmp("CP", RSTRING_PTR(name), 2) == 0) { 00226 int code_page = atoi(RSTRING_PTR(name) + 2); 00227 if (code_page != 0) { 00228 rb_hash_aset(rb_code_page, name_key, INT2FIX(code_page)); 00229 return (UINT)code_page; 00230 } 00231 } 00232 } 00233 } 00234 00235 rb_hash_aset(rb_code_page, name_key, INT2FIX(INVALID_CODE_PAGE)); 00236 return INVALID_CODE_PAGE; 00237 } 00238 00239 static inline VALUE 00240 fix_string_encoding(VALUE str, rb_encoding *encoding) 00241 { 00242 VALUE result, tmp; 00243 00244 tmp = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), encoding); 00245 result = rb_str_encode(tmp, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil); 00246 00247 return result; 00248 } 00249 00250 /* 00251 Replace the last part of the path to long name. 00252 We try to avoid to call FindFirstFileW() since it takes long time. 00253 */ 00254 static inline size_t 00255 replace_to_long_name(wchar_t **wfullpath, size_t size, int heap) 00256 { 00257 WIN32_FIND_DATAW find_data; 00258 HANDLE find_handle; 00259 00260 /* 00261 Skip long name conversion if the path is already long name. 00262 Short name is 8.3 format. 00263 http://en.wikipedia.org/wiki/8.3_filename 00264 This check can be skipped for directory components that have file 00265 extensions longer than 3 characters, or total lengths longer than 00266 12 characters. 00267 http://msdn.microsoft.com/en-us/library/windows/desktop/aa364980(v=vs.85).aspx 00268 */ 00269 size_t const max_short_name_size = 8 + 1 + 3; 00270 size_t const max_extension_size = 3; 00271 size_t path_len = 1, extension_len = 0; 00272 wchar_t *pos = *wfullpath; 00273 00274 if (size == 3 && pos[1] == L':' && pos[2] == L'\\' && pos[3] == L'\0') { 00275 /* root path doesn't need short name expansion */ 00276 return size; 00277 } 00278 00279 pos = *wfullpath + size - 1; 00280 while (!IS_DIR_SEPARATOR_P(*pos) && pos != *wfullpath) { 00281 if (!extension_len && *pos == L'.') { 00282 extension_len = path_len - 1; 00283 } 00284 if (path_len > max_short_name_size || extension_len > max_extension_size) { 00285 return size; 00286 } 00287 path_len++; 00288 pos--; 00289 } 00290 00291 find_handle = FindFirstFileW(*wfullpath, &find_data); 00292 if (find_handle != INVALID_HANDLE_VALUE) { 00293 size_t trail_pos = wcslen(*wfullpath); 00294 size_t file_len = wcslen(find_data.cFileName); 00295 00296 FindClose(find_handle); 00297 while (trail_pos > 0) { 00298 if (IS_DIR_SEPARATOR_P((*wfullpath)[trail_pos])) 00299 break; 00300 trail_pos--; 00301 } 00302 size = trail_pos + 1 + file_len; 00303 if ((size + 1) > sizeof(*wfullpath) / sizeof((*wfullpath)[0])) { 00304 wchar_t *buf = (wchar_t *)xmalloc((size + 1) * sizeof(wchar_t)); 00305 wcsncpy(buf, *wfullpath, trail_pos + 1); 00306 if (heap) 00307 xfree(*wfullpath); 00308 *wfullpath = buf; 00309 } 00310 wcsncpy(*wfullpath + trail_pos + 1, find_data.cFileName, file_len + 1); 00311 } 00312 return size; 00313 } 00314 00315 VALUE 00316 rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_name, VALUE result) 00317 { 00318 size_t size = 0, wpath_len = 0, wdir_len = 0, whome_len = 0; 00319 size_t buffer_len = 0; 00320 char *fullpath = NULL; 00321 wchar_t *wfullpath = NULL, *wpath = NULL, *wpath_pos = NULL, *wdir = NULL; 00322 wchar_t *whome = NULL, *buffer = NULL, *buffer_pos = NULL; 00323 UINT path_cp, cp; 00324 VALUE path = fname, dir = dname; 00325 wchar_t wfullpath_buffer[PATH_BUFFER_SIZE]; 00326 wchar_t path_drive = L'\0', dir_drive = L'\0'; 00327 int ignore_dir = 0; 00328 rb_encoding *path_encoding; 00329 int tainted = 0; 00330 00331 /* tainted if path is tainted */ 00332 tainted = OBJ_TAINTED(path); 00333 00334 /* get path encoding */ 00335 if (NIL_P(dir)) { 00336 path_encoding = rb_enc_get(path); 00337 } 00338 else { 00339 path_encoding = rb_enc_check(path, dir); 00340 } 00341 00342 cp = path_cp = code_page(path_encoding); 00343 00344 /* workaround invalid codepage */ 00345 if (path_cp == INVALID_CODE_PAGE) { 00346 cp = CP_UTF8; 00347 if (!NIL_P(path)) { 00348 path = fix_string_encoding(path, path_encoding); 00349 } 00350 } 00351 00352 /* convert char * to wchar_t */ 00353 convert_mb_to_wchar(path, &wpath, &wpath_pos, &wpath_len, cp); 00354 00355 /* determine if we need the user's home directory */ 00356 /* expand '~' only if NOT rb_file_absolute_path() where `abs_mode` is 1 */ 00357 if (abs_mode == 0 && wpath_len > 0 && wpath_pos[0] == L'~' && 00358 (wpath_len == 1 || IS_DIR_SEPARATOR_P(wpath_pos[1]))) { 00359 /* tainted if expanding '~' */ 00360 tainted = 1; 00361 00362 whome = home_dir(); 00363 if (whome == NULL) { 00364 xfree(wpath); 00365 rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'"); 00366 } 00367 whome_len = wcslen(whome); 00368 00369 if (PathIsRelativeW(whome) && !(whome_len >= 2 && IS_DIR_UNC_P(whome))) { 00370 xfree(wpath); 00371 rb_raise(rb_eArgError, "non-absolute home"); 00372 } 00373 00374 /* use filesystem encoding if expanding home dir */ 00375 path_encoding = rb_filesystem_encoding(); 00376 cp = path_cp = system_code_page(); 00377 00378 /* ignores dir since we are expading home */ 00379 ignore_dir = 1; 00380 00381 /* exclude ~ from the result */ 00382 wpath_pos++; 00383 wpath_len--; 00384 00385 /* exclude separator if present */ 00386 if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) { 00387 wpath_pos++; 00388 wpath_len--; 00389 } 00390 } 00391 else if (wpath_len >= 2 && wpath_pos[1] == L':') { 00392 if (wpath_len >= 3 && IS_DIR_SEPARATOR_P(wpath_pos[2])) { 00393 /* ignore dir since path contains a drive letter and a root slash */ 00394 ignore_dir = 1; 00395 } 00396 else { 00397 /* determine if we ignore dir or not later */ 00398 path_drive = wpath_pos[0]; 00399 } 00400 } 00401 else if (abs_mode == 0 && wpath_len >= 2 && wpath_pos[0] == L'~') { 00402 wchar_t *wuser = wpath_pos + 1; 00403 wchar_t *pos = wuser; 00404 char *user; 00405 00406 /* tainted if expanding '~' */ 00407 tainted = 1; 00408 00409 while (!IS_DIR_SEPARATOR_P(*pos) && *pos != '\0') 00410 pos++; 00411 00412 *pos = '\0'; 00413 convert_wchar_to_mb(wuser, &user, &size, cp); 00414 00415 /* convert to VALUE and set the path encoding */ 00416 if (path_cp == INVALID_CODE_PAGE) { 00417 VALUE tmp = rb_enc_str_new(user, size, rb_utf8_encoding()); 00418 result = rb_str_encode(tmp, rb_enc_from_encoding(path_encoding), 0, Qnil); 00419 rb_str_resize(tmp, 0); 00420 } 00421 else { 00422 result = rb_enc_str_new(user, size, path_encoding); 00423 } 00424 00425 xfree(wpath); 00426 if (user) 00427 xfree(user); 00428 00429 rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result)); 00430 } 00431 00432 /* convert dir */ 00433 if (!ignore_dir && !NIL_P(dir)) { 00434 /* fix string encoding */ 00435 if (path_cp == INVALID_CODE_PAGE) { 00436 dir = fix_string_encoding(dir, path_encoding); 00437 } 00438 00439 /* convert char * to wchar_t */ 00440 convert_mb_to_wchar(dir, &wdir, NULL, &wdir_len, cp); 00441 00442 if (wdir_len >= 2 && wdir[1] == L':') { 00443 dir_drive = wdir[0]; 00444 if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) { 00445 wdir_len = 2; 00446 } 00447 } 00448 else if (wdir_len >= 2 && IS_DIR_UNC_P(wdir)) { 00449 /* UNC path */ 00450 if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) { 00451 /* cut the UNC path tail to '//host/share' */ 00452 size_t separators = 0; 00453 size_t pos = 2; 00454 while (pos < wdir_len && separators < 2) { 00455 if (IS_DIR_SEPARATOR_P(wdir[pos])) { 00456 separators++; 00457 } 00458 pos++; 00459 } 00460 if (separators == 2) 00461 wdir_len = pos - 1; 00462 } 00463 } 00464 } 00465 00466 /* determine if we ignore dir or not */ 00467 if (!ignore_dir && path_drive && dir_drive) { 00468 if (towupper(path_drive) == towupper(dir_drive)) { 00469 /* exclude path drive letter to use dir */ 00470 wpath_pos += 2; 00471 wpath_len -= 2; 00472 } 00473 else { 00474 /* ignore dir since path drive is different from dir drive */ 00475 ignore_dir = 1; 00476 wdir_len = 0; 00477 } 00478 } 00479 00480 if (!ignore_dir && wpath_len >= 2 && IS_DIR_UNC_P(wpath)) { 00481 /* ignore dir since path has UNC root */ 00482 ignore_dir = 1; 00483 wdir_len = 0; 00484 } 00485 else if (!ignore_dir && wpath_len >= 1 && IS_DIR_SEPARATOR_P(wpath[0]) && 00486 !dir_drive && !(wdir_len >= 2 && IS_DIR_UNC_P(wdir))) { 00487 /* ignore dir since path has root slash and dir doesn't have drive or UNC root */ 00488 ignore_dir = 1; 00489 wdir_len = 0; 00490 } 00491 00492 buffer_len = wpath_len + 1 + wdir_len + 1 + whome_len + 1; 00493 00494 buffer = buffer_pos = (wchar_t *)xmalloc((buffer_len + 1) * sizeof(wchar_t)); 00495 00496 /* add home */ 00497 if (whome_len) { 00498 wcsncpy(buffer_pos, whome, whome_len); 00499 buffer_pos += whome_len; 00500 } 00501 00502 /* Add separator if required */ 00503 if (whome_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) { 00504 buffer_pos[0] = L'\\'; 00505 buffer_pos++; 00506 } 00507 00508 if (wdir_len) { 00509 /* tainted if dir is used and dir is tainted */ 00510 if (!tainted && OBJ_TAINTED(dir)) 00511 tainted = 1; 00512 00513 wcsncpy(buffer_pos, wdir, wdir_len); 00514 buffer_pos += wdir_len; 00515 } 00516 00517 /* add separator if required */ 00518 if (wdir_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) { 00519 buffer_pos[0] = L'\\'; 00520 buffer_pos++; 00521 } 00522 00523 /* now deal with path */ 00524 if (wpath_len) { 00525 wcsncpy(buffer_pos, wpath_pos, wpath_len); 00526 buffer_pos += wpath_len; 00527 } 00528 00529 /* GetFullPathNameW requires at least "." to determine current directory */ 00530 if (wpath_len == 0) { 00531 buffer_pos[0] = L'.'; 00532 buffer_pos++; 00533 } 00534 00535 /* Ensure buffer is NULL terminated */ 00536 buffer_pos[0] = L'\0'; 00537 00538 /* tainted if path is relative */ 00539 if (!tainted && PathIsRelativeW(buffer) && !(buffer_len >= 2 && IS_DIR_UNC_P(buffer))) 00540 tainted = 1; 00541 00542 /* FIXME: Make this more robust */ 00543 /* Determine require buffer size */ 00544 size = GetFullPathNameW(buffer, PATH_BUFFER_SIZE, wfullpath_buffer, NULL); 00545 if (size > PATH_BUFFER_SIZE) { 00546 /* allocate more memory than alloted originally by PATH_BUFFER_SIZE */ 00547 wfullpath = (wchar_t *)xmalloc(size * sizeof(wchar_t)); 00548 size = GetFullPathNameW(buffer, size, wfullpath, NULL); 00549 } 00550 else { 00551 wfullpath = wfullpath_buffer; 00552 } 00553 00554 /* Remove any trailing slashes */ 00555 if (IS_DIR_SEPARATOR_P(wfullpath[size - 1]) && 00556 wfullpath[size - 2] != L':' && 00557 !(size == 2 && IS_DIR_UNC_P(wfullpath))) { 00558 size -= 1; 00559 wfullpath[size] = L'\0'; 00560 } 00561 00562 /* Remove any trailing dot */ 00563 if (wfullpath[size - 1] == L'.') { 00564 size -= 1; 00565 wfullpath[size] = L'\0'; 00566 } 00567 00568 /* removes trailing invalid ':$DATA' */ 00569 size = remove_invalid_alternative_data(wfullpath, size); 00570 00571 /* Replace the trailing path to long name */ 00572 if (long_name) 00573 size = replace_to_long_name(&wfullpath, size, (wfullpath != wfullpath_buffer)); 00574 00575 /* sanitize backslashes with forwardslashes */ 00576 replace_wchar(wfullpath, L'\\', L'/'); 00577 00578 /* convert to char * */ 00579 size = WideCharToMultiByte(cp, 0, wfullpath, size, NULL, 0, NULL, NULL); 00580 if (size > (size_t)RSTRING_LEN(result)) { 00581 rb_str_modify(result); 00582 rb_str_resize(result, size); 00583 } 00584 00585 WideCharToMultiByte(cp, 0, wfullpath, size, RSTRING_PTR(result), size, NULL, NULL); 00586 rb_str_set_len(result, size); 00587 00588 /* convert to VALUE and set the path encoding */ 00589 if (path_cp == INVALID_CODE_PAGE) { 00590 VALUE tmp; 00591 size_t len; 00592 00593 rb_enc_associate(result, rb_utf8_encoding()); 00594 ENC_CODERANGE_CLEAR(result); 00595 tmp = rb_str_encode(result, rb_enc_from_encoding(path_encoding), 0, Qnil); 00596 len = RSTRING_LEN(tmp); 00597 rb_str_modify(result); 00598 rb_str_resize(result, len); 00599 memcpy(RSTRING_PTR(result), RSTRING_PTR(tmp), len); 00600 rb_str_resize(tmp, 0); 00601 } 00602 rb_enc_associate(result, path_encoding); 00603 ENC_CODERANGE_CLEAR(result); 00604 00605 /* makes the result object tainted if expanding tainted strings or returning modified path */ 00606 if (tainted) 00607 OBJ_TAINT(result); 00608 00609 /* TODO: better cleanup */ 00610 if (buffer) 00611 xfree(buffer); 00612 00613 if (wpath) 00614 xfree(wpath); 00615 00616 if (wdir) 00617 xfree(wdir); 00618 00619 if (whome) 00620 xfree(whome); 00621 00622 if (wfullpath && wfullpath != wfullpath_buffer) 00623 xfree(wfullpath); 00624 00625 if (fullpath) 00626 xfree(fullpath); 00627 00628 return result; 00629 } 00630 00631 int 00632 rb_file_load_ok(const char *path) 00633 { 00634 int ret = 1; 00635 DWORD attr = GetFileAttributes(path); 00636 if (attr == INVALID_FILE_ATTRIBUTES || 00637 attr & FILE_ATTRIBUTE_DIRECTORY) { 00638 ret = 0; 00639 } 00640 else { 00641 HANDLE h = CreateFile(path, GENERIC_READ, 00642 FILE_SHARE_READ | FILE_SHARE_WRITE, 00643 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 00644 if (h != INVALID_HANDLE_VALUE) { 00645 CloseHandle(h); 00646 } 00647 else { 00648 ret = 0; 00649 } 00650 } 00651 return ret; 00652 } 00653 00654 void 00655 rb_w32_init_file(void) 00656 { 00657 rb_code_page = rb_hash_new(); 00658 00659 /* prevent GC removing rb_code_page */ 00660 rb_gc_register_mark_object(rb_code_page); 00661 } 00662