summaryrefslogtreecommitdiff
path: root/chef
diff options
context:
space:
mode:
authorSeth Chisamore <schisamo@opscode.com>2011-11-18 16:11:23 -0500
committerSeth Chisamore <schisamo@opscode.com>2011-12-08 20:10:56 -0500
commit447604d5a06a149087d38725b3281e712e18e7db (patch)
treee09789ba0f61d3d55413853122d2dd82693c84a1 /chef
parent701f1aa0458b3353f14ea1dd86a6812592798f9f (diff)
downloadchef-447604d5a06a149087d38725b3281e712e18e7db.tar.gz
added readlink to Chef::Win32::File
Diffstat (limited to 'chef')
-rw-r--r--chef/lib/chef/win32/api/file.rb31
-rw-r--r--chef/lib/chef/win32/file.rb41
2 files changed, 71 insertions, 1 deletions
diff --git a/chef/lib/chef/win32/api/file.rb b/chef/lib/chef/win32/api/file.rb
index f0ef9fba49..5f1c5fc901 100644
--- a/chef/lib/chef/win32/api/file.rb
+++ b/chef/lib/chef/win32/api/file.rb
@@ -49,6 +49,13 @@ class Chef
SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1
+ FILE_NAME_NORMALIZED = 0x0
+ FILE_NAME_OPENED = 0x8
+
+ # TODO add the rest of these CONSTS
+ FILE_SHARE_READ = 0x00000001
+ OPEN_EXISTING = 3
+
=begin
typedef struct _FILETIME {
DWORD dwLowDateTime;
@@ -101,6 +108,19 @@ typedef struct _WIN32_FIND_DATA {
end
=begin
+HANDLE WINAPI CreateFile(
+ __in LPCTSTR lpFileName,
+ __in DWORD dwDesiredAccess,
+ __in DWORD dwShareMode,
+ __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ __in DWORD dwCreationDisposition,
+ __in DWORD dwFlagsAndAttributes,
+ __in_opt HANDLE hTemplateFile
+);
+=end
+ attach_function :CreateFileW, [:LPCTSTR, :DWORD, :DWORD, :LPSECURITY_ATTRIBUTES, :DWORD, :DWORD, :pointer], :HANDLE
+
+=begin
BOOL WINAPI FindClose(
__inout HANDLE hFindFile
);
@@ -113,6 +133,17 @@ DWORD WINAPI GetFileAttributes(
);
=end
attach_function :GetFileAttributesW, [:LPCWSTR], :DWORD
+
+=begin
+DWORD WINAPI GetFinalPathNameByHandle(
+ __in HANDLE hFile,
+ __out LPTSTR lpszFilePath,
+ __in DWORD cchFilePath,
+ __in DWORD dwFlags
+);
+=end
+ attach_function :GetFinalPathNameByHandleW, [:HANDLE, :LPTSTR, :DWORD, :DWORD], :DWORD
+
=begin
HANDLE WINAPI FindFirstFile(
__in LPCTSTR lpFileName,
diff --git a/chef/lib/chef/win32/file.rb b/chef/lib/chef/win32/file.rb
index 86f8505931..b330a6bc95 100644
--- a/chef/lib/chef/win32/file.rb
+++ b/chef/lib/chef/win32/file.rb
@@ -18,6 +18,7 @@
#
require 'chef/win32/api/file'
+require 'chef/win32/api/security'
require 'chef/win32/error'
require 'chef/win32/unicode'
@@ -27,6 +28,7 @@ class Chef
class << self
include Chef::Win32::API::File
+ include Chef::Win32::API::Security
# Creates a symbolic link called +new_name+ for the file or directory
# +old_name+.
@@ -79,6 +81,24 @@ class Chef
is_symlink
end
+ # Returns the path of the of the symbolic link referred to by +file+.
+ #
+ # Requires Windows Vista or later. On older versions of Windows it
+ # will raise a NotImplementedError, as per MRI.
+ #
+ def readlink(link_name)
+ # TODO do a check for GetFinalPathNameByHandleW and
+ # raise NotImplemented exception on older Windows
+ open_file(link_name) do |handle|
+ buffer = FFI::MemoryPointer.new(0.chr * MAX_PATH)
+ num_chars = GetFinalPathNameByHandleW(handle, buffer, buffer.size, FILE_NAME_NORMALIZED)
+ if num_chars == 0
+ Chef::Win32::Error.raise! #could be misleading if problem is too small buffer size as GetLastError won't report failure
+ end
+ buffer.read_wstring(num_chars).sub(path_prepender, "")
+ end
+ end
+
private
# takes the given path pre-pends "\\?\" and
@@ -86,7 +106,11 @@ class Chef
# to be passed to the *W vesion of WinAPI File
# functions
def encode_path(path)
- ("\\\\?\\" << path).to_wstring
+ (path_prepender << path).to_wstring
+ end
+
+ def path_prepender
+ "\\\\?\\"
end
# retrieves a file search handle and passes it
@@ -106,6 +130,21 @@ class Chef
end
end
+ def open_file(path, &block)
+ begin
+ path = encode_path(path)
+ handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
+ nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nil)
+
+ if handle == INVALID_HANDLE_VALUE
+ Chef::Win32::Error.raise!
+ end
+ block.call(handle)
+ ensure
+ FindClose(handle) if handle && handle != INVALID_HANDLE_VALUE
+ end
+ end
+
end
end