Last active
August 29, 2015 14:04
-
-
Save taichi/3f774b667c2602cba85b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static int | |
winnt_stat(const WCHAR *path, struct stati64 *st) | |
{ | |
HANDLE h; | |
WIN32_FIND_DATAW wfd; | |
WIN32_FILE_ATTRIBUTE_DATA wfa; | |
const WCHAR *p = path; | |
memset(st, 0, sizeof(*st)); | |
st->st_nlink = 1; | |
if (wcsncmp(p, L"\\\\?\\", 4) == 0) p += 4; | |
if (wcspbrk(p, L"?*")) { | |
errno = ENOENT; | |
return -1; | |
} | |
if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) { | |
if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | |
if (check_valid_dir(path)) return -1; | |
st->st_size = 0; | |
} | |
else { | |
st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow; | |
} | |
st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path); | |
st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime); | |
st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime); | |
st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime); | |
} | |
else { | |
/* GetFileAttributesEx failed; check why. */ | |
int e = GetLastError(); | |
if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME) | |
|| (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) { | |
errno = map_errno(e); | |
return -1; | |
} | |
/* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */ | |
h = FindFirstFileW(path, &wfd); | |
if (h != INVALID_HANDLE_VALUE) { | |
FindClose(h); | |
st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path); | |
st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime); | |
st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime); | |
st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime); | |
st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow; | |
} | |
else { | |
errno = map_errno(GetLastError()); | |
return -1; | |
} | |
} | |
st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ? | |
towupper(path[0]) - L'A' : _getdrive() - 1; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "ffi" | |
module Win32 | |
extend FFI::Library | |
ffi_lib 'kernel32' | |
ffi_convention :stdcall | |
typedef :uint , :DWORD | |
typedef :pointer , :HANDLE | |
typedef :bool , :BOOL | |
typedef :ulong_long , :ULONGLONG | |
typedef :pointer , :LPTSTR | |
typedef :pointer , :LPCTSTR | |
typedef :pointer , :LPCVOID | |
typedef :pointer , :LPSECURITY_ATTRIBUTES | |
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx | |
class FILETIME < FFI::Struct | |
layout( | |
:dwLowDateTime , :DWORD, | |
:dwHighDateTime, :DWORD, | |
) | |
end | |
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa363788(v=vs.85).aspx | |
class FILE_INFORMATION < FFI::Struct | |
layout( | |
:dwFileAttributes, :DWORD , | |
:ftCreationTime, FILETIME, | |
:ftLastAccessTime, FILETIME, | |
:ftLastWriteTime, FILETIME, | |
:dwVolumeSerialNumber, :DWORD , | |
:nFileSizeHigh, :DWORD , | |
:nFileSizeLow, :DWORD , | |
:nNumberOfLinks, :DWORD , | |
:nFileIndexHigh, :DWORD , | |
:nFileIndexLow, :DWORD , | |
) | |
end | |
INVALID_HANDLE_VALUE = -1 | |
# http://msdn.microsoft.com/ja-jp/library/windows/desktop/ms724211(v=vs.85).aspx | |
attach_function :CloseHandle, [:HANDLE], :BOOL | |
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa374892(v=vs.85).aspx | |
GENERIC_READ = 0x80000000 | |
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx | |
FILE_SHARE_READ = 0x00000001 | |
FILE_SHARE_WRITE = 0x00000002 | |
FILE_SHARE_DELETE= 0x00000004 | |
OPEN_EXISTING = 3 | |
FILE_ATTRIBUTE_NORMAL = 0x00000080 | |
attach_function :CreateFile, :CreateFileW, [ | |
:LPCTSTR , # lpFileName, | |
:DWORD , # dwDesiredAccess, | |
:DWORD , # dwShareMode, | |
:LPSECURITY_ATTRIBUTES , # lpSecurityAttributes, | |
:DWORD , # dwCreationDisposition, | |
:DWORD , # dwFlagsAndAttributes, | |
:HANDLE , # hTemplateFile | |
], :HANDLE | |
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa364952(v=vs.85).aspx | |
typedef :pointer, :LPBY_HANDLE_FILE_INFORMATION | |
attach_function :GetFileInformationByHandle, [ | |
:HANDLE, | |
:LPBY_HANDLE_FILE_INFORMATION | |
], :BOOL | |
def self.last_error(err_at, err = FFI.errno) | |
SystemCallError.new(err_at, err) | |
end | |
def self.to_unicode(path) | |
(path.tr(::File::SEPARATOR, ::File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE') | |
end | |
def self.to_large_integer(h, l) | |
(h << 32) | l | |
end | |
def self.to_time(ft) | |
t = to_large_integer ft[:dwHighDateTime], ft[:dwLowDateTime] | |
Time.at t / 10000000 - 11644473600 | |
end | |
class File | |
def self.stat(path) | |
share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE | |
wpath = Win32.to_unicode path | |
handle = Win32.CreateFile(wpath, GENERIC_READ, share, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nil) | |
if INVALID_HANDLE_VALUE == handle.address | |
raise Errno::ENOENT.new path | |
end | |
begin | |
fi = FILE_INFORMATION.new | |
unless Win32.GetFileInformationByHandle(handle, fi) | |
raise last_error("GetFileInformationByHandle") | |
end | |
Stat.new fi | |
ensure | |
Win32.CloseHandle(handle) | |
end | |
end | |
class Stat | |
attr_reader :rdev | |
attr_reader :ino | |
attr_reader :size | |
attr_reader :atime | |
attr_reader :mtime | |
attr_reader :ctime | |
def initialize(fi) | |
@rdev = fi[:dwVolumeSerialNumber] | |
@ino = Win32.to_large_integer fi[:nFileIndexHigh], fi[:nFileIndexLow] | |
@size = Win32.to_large_integer fi[:nFileSizeHigh] , fi[:nFileSizeLow] | |
@atime = Win32.to_time fi[:ftLastAccessTime] | |
@mtime = Win32.to_time fi[:ftLastWriteTime] | |
@ctime = Win32.to_time fi[:ftCreationTime] | |
end | |
def to_s | |
"#<Win32::File::Stat rdev=#{@rdev} ino=#{@ino} size=#{@size} atime=#{@atime} mtime=#{@mtime} ctime=#{@ctime}>" | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment