Chromium Code Reviews| Index: runtime/bin/file_win.cc |
| diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc |
| index b23049dce5bfc7241347d89db5fae8060409d6d5..a7f77e7dff3e8a6cd5534f2e82bc47c49ce41d21 100644 |
| --- a/runtime/bin/file_win.cc |
| +++ b/runtime/bin/file_win.cc |
| @@ -167,6 +167,7 @@ typedef struct _REPARSE_DATA_BUFFER { |
| USHORT SubstituteNameLength; |
| USHORT PrintNameOffset; |
| USHORT PrintNameLength; |
| + ULONG Flags; |
| WCHAR PathBuffer[1]; |
| } SymbolicLinkReparseBuffer; |
| @@ -279,6 +280,103 @@ off_t File::LengthFromPath(const char* name) { |
| } |
| +char* File::LinkTarget(const char* pathname) { |
| + const wchar_t* name = StringUtils::Utf8ToWide(pathname); |
| + HANDLE dir_handle = CreateFileW( |
| + name, |
| + GENERIC_READ, |
| + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| + NULL, |
| + OPEN_EXISTING, |
| + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, |
| + NULL); |
| + free(const_cast<wchar_t*>(name)); |
| + if (dir_handle == INVALID_HANDLE_VALUE) { |
| + return NULL; |
| + } |
| + |
| + int reparse_data_buffer_size = |
| + sizeof REPARSE_DATA_BUFFER + 2 * (MAX_PATH + 1) * sizeof WCHAR; |
| + REPARSE_DATA_BUFFER* reparse_data_buffer = |
| + static_cast<REPARSE_DATA_BUFFER*>(calloc(reparse_data_buffer_size, 1)); |
| + DWORD received_bytes; |
| + int result = DeviceIoControl( |
| + dir_handle, |
| + FSCTL_GET_REPARSE_POINT, |
| + NULL, |
| + 0, |
| + reparse_data_buffer, |
| + reparse_data_buffer_size, |
| + &received_bytes, |
| + NULL); |
| + if (result == 0) { |
| + DWORD error = GetLastError(); |
|
Bill Hesse
2013/03/18 16:13:27
This code occurs, slightly differently, 4 times, b
|
| + CloseHandle(dir_handle); // Might reset the error. |
| + SetLastError(error); |
| + return NULL; |
| + } |
| + if (CloseHandle(dir_handle) == 0) return NULL; |
| + bool junction = |
| + reparse_data_buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT; |
| + bool symlink = reparse_data_buffer->ReparseTag == IO_REPARSE_TAG_SYMLINK; |
| + if (!junction && !symlink) { |
| + SetLastError(ERROR_NOT_A_REPARSE_POINT); |
| + return NULL; |
| + } |
| + wchar_t* target; |
| + size_t target_offset; |
| + size_t target_length; |
| + if (junction) { |
| + target = reparse_data_buffer->MountPointReparseBuffer.PathBuffer; |
| + target_offset = |
| + reparse_data_buffer->MountPointReparseBuffer.SubstituteNameOffset; |
| + target_length = |
| + reparse_data_buffer->MountPointReparseBuffer.SubstituteNameLength; |
| + } |
| + if (symlink) { |
| + target = reparse_data_buffer->SymbolicLinkReparseBuffer.PathBuffer; |
| + target_offset = |
| + reparse_data_buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset; |
| + target_length = |
| + reparse_data_buffer->SymbolicLinkReparseBuffer.SubstituteNameLength; |
| + } |
| + target_offset /= sizeof(wchar_t); // Offset and length are in bytes. |
| + target_length /= sizeof(wchar_t); |
| + target += target_offset; |
| + // Remove "\??\" from beginning of target. |
| + if (target_length > 4 && wcsncmp(L"\\??\\", target, 4) == 0) { |
| + target += 4; |
| + target_length -=4; |
| + } |
| + int utf8_length = WideCharToMultiByte(CP_UTF8, |
| + 0, |
| + target, |
| + target_length, |
| + NULL, |
| + 0, |
| + NULL, |
| + NULL); |
| + char* utf8_target = reinterpret_cast<char*>(malloc(utf8_length + 1)); |
| + if (0 == WideCharToMultiByte(CP_UTF8, |
| + 0, |
| + target, |
| + target_length, |
| + utf8_target, |
| + utf8_length, |
| + NULL, |
| + NULL)) { |
| + DWORD error = GetLastError(); |
| + free(reparse_data_buffer); |
| + free(utf8_target); |
| + SetLastError(error); |
| + return NULL; |
| + } |
| + utf8_target[utf8_length] = '\0'; |
| + free(reparse_data_buffer); |
| + return utf8_target; |
| +} |
| + |
| + |
| time_t File::LastModified(const char* name) { |
| struct _stat st; |
| const wchar_t* system_name = StringUtils::Utf8ToWide(name); |