win32-file 0.6.9 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,27 @@
1
+ require 'ffi'
2
+
3
+ module Windows
4
+ module File
5
+ module Constants
6
+ FILE_ATTRIBUTE_NORMAL = 0x00000080
7
+ FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400
8
+ FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
9
+ FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
10
+ FILE_SHARE_READ = 1
11
+
12
+ FILE_TYPE_UNKNOWN = 0x0000
13
+ FILE_TYPE_CHAR = 0x0002
14
+ NO_ERROR = 0
15
+
16
+ GENERIC_READ = 0x80000000
17
+ INVALID_HANDLE_VALUE = (1 << FFI::Platform::ADDRESS_SIZE) - 1
18
+ INVALID_FILE_ATTRIBUTES = (1 << FFI::Platform::ADDRESS_SIZE) - 1
19
+ IO_REPARSE_TAG_SYMLINK = 0xA000000C
20
+ OPEN_EXISTING = 3
21
+
22
+ DRIVE_REMOVABLE = 2
23
+ DRIVE_CDROM = 5
24
+ DRIVE_RAMDISK = 6
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,49 @@
1
+ module Windows
2
+ module File
3
+ module Functions
4
+ extend FFI::Library
5
+ ffi_lib :kernel32
6
+
7
+ typedef :ulong, :dword
8
+ typedef :uintptr_t, :handle
9
+ typedef :pointer, :ptr
10
+
11
+ def self.attach_pfunc(*args)
12
+ attach_function(*args)
13
+ private args[0]
14
+ end
15
+
16
+ attach_pfunc :CloseHandle, [:handle], :bool
17
+ attach_pfunc :CreateFileW, [:buffer_in, :dword, :dword, :pointer, :dword, :dword, :handle], :handle
18
+ attach_pfunc :CreateSymbolicLinkW, [:buffer_in, :buffer_in, :dword], :bool
19
+ attach_pfunc :FindFirstFileW, [:buffer_in, :pointer], :handle
20
+ attach_pfunc :GetDiskFreeSpaceW, [:buffer_in, :pointer, :pointer, :pointer, :pointer], :bool
21
+ attach_pfunc :GetDriveTypeW, [:buffer_in], :uint
22
+ attach_pfunc :GetFileType, [:handle], :dword
23
+ attach_pfunc :GetFileAttributesW, [:buffer_in], :dword
24
+ attach_pfunc :GetFinalPathNameByHandleW, [:handle, :buffer_out, :dword, :dword], :dword
25
+ attach_pfunc :GetShortPathNameW, [:buffer_in, :buffer_out, :dword], :dword
26
+ attach_pfunc :GetLongPathNameW, [:buffer_in, :buffer_out, :dword], :dword
27
+ attach_pfunc :QueryDosDeviceA, [:string, :buffer_out, :dword], :dword
28
+
29
+ ffi_lib :shlwapi
30
+
31
+ attach_pfunc :PathFindExtensionW, [:buffer_in], :pointer
32
+ attach_pfunc :PathIsRootW, [:buffer_in], :bool
33
+ attach_pfunc :PathStripPathW, [:pointer], :void
34
+ attach_pfunc :PathRemoveBackslashW, [:buffer_in], :string
35
+ attach_pfunc :PathRemoveFileSpecW, [:pointer], :bool
36
+ attach_pfunc :PathRemoveExtensionW, [:buffer_in], :void
37
+ attach_pfunc :PathStripToRootW, [:buffer_in], :bool
38
+ end
39
+ end
40
+ end
41
+
42
+ class String
43
+ # Read a wide character string up until the first double null, and delete
44
+ # any remaining null characters.
45
+ def wstrip
46
+ self.force_encoding('UTF-16LE').encode('UTF-8',:invalid=>:replace,:undef=>:replace).
47
+ split("\x00")[0].encode(Encoding.default_external)
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ module Windows
2
+ module File
3
+ module Structs
4
+ class FILETIME < FFI::Struct
5
+ layout(:dwLowDateTime, :ulong, :dwHighDateTime, :ulong)
6
+ end
7
+
8
+ class WIN32_FIND_DATA < FFI::Struct
9
+ layout(
10
+ :dwFileAttributes, :ulong,
11
+ :ftCreationTime, FILETIME,
12
+ :ftLastAccessTime, FILETIME,
13
+ :ftLastWriteTime, FILETIME,
14
+ :nFileSizeHigh, :ulong,
15
+ :nFileSizeLow, :ulong,
16
+ :dwReserved0, :ulong,
17
+ :dwReserved1, :ulong,
18
+ :cFileName, [:uint8, 260*2],
19
+ :cAlternateFileName, [:uint8, 14*2]
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,141 @@
1
+ #############################################################################
2
+ # test_win32_file_link.rb
3
+ #
4
+ # Test case for the link related methods of win32-file. You should run this
5
+ # test via the 'rake test' or 'rake test:link' task.
6
+ #############################################################################
7
+ require 'test-unit'
8
+ require 'win32/security'
9
+ require 'win32/file'
10
+
11
+ class TC_Win32_File_Link < Test::Unit::TestCase
12
+ def self.startup
13
+ Dir.chdir(File.expand_path(File.dirname(__FILE__)))
14
+ @@file = File.join(Dir.pwd, 'link_test.txt')
15
+ File.open(@@file, 'w'){ |fh| fh.puts "This is a link test." }
16
+ end
17
+
18
+ def setup
19
+ @link = "this_is_a_symlink"
20
+ @file = "link_test.txt"
21
+ @admin = Win32::Security.elevated_security?
22
+ end
23
+
24
+ test "symlink basic functionality" do
25
+ assert_respond_to(File, :symlink)
26
+ end
27
+
28
+ test "symlink to a file works as expected" do
29
+ omit_unless(@admin)
30
+ assert_nothing_raised{ File.symlink(@@file, @link) }
31
+ assert_true(File.exists?(@link))
32
+ assert_true(File.symlink?(@link))
33
+ end
34
+
35
+ test "symlink method returns zero" do
36
+ omit_unless(@admin)
37
+ assert_equal(0, File.symlink(@@file, @link))
38
+ end
39
+
40
+ test "symlink requires two arguments" do
41
+ assert_raise(ArgumentError){ File.symlink }
42
+ assert_raise(ArgumentError){ File.symlink(@link) }
43
+ assert_raise(ArgumentError){ File.symlink(@@file, @link, @link) }
44
+ end
45
+
46
+ test "symlink fails if link already exists" do
47
+ omit_unless(@admin)
48
+ File.symlink(@@file, @link)
49
+ assert_raise(SystemCallError){ File.symlink(@@file, @link) }
50
+ end
51
+
52
+ test "symlink does not fail if target does not exist" do
53
+ omit_unless(@admin)
54
+ assert_nothing_raised{ File.symlink('bogus.txt', @link) }
55
+ end
56
+
57
+ test "symlink? basic functionality" do
58
+ assert_respond_to(File, :symlink?)
59
+ assert_boolean(File.symlink?(@@file))
60
+ end
61
+
62
+ test "symlink? returns expected result" do
63
+ omit_unless(@admin)
64
+ File.symlink(@@file, @link)
65
+ assert_true(File.symlink?(@link))
66
+ assert_false(File.symlink?(@file))
67
+ end
68
+
69
+ test "symlink? requires one argument only" do
70
+ assert_raise(ArgumentError){ File.symlink? }
71
+ assert_raise(ArgumentError){ File.symlink?(@@file, @@file) }
72
+ end
73
+
74
+ test "readlink basic functionality" do
75
+ assert_respond_to(File, :readlink)
76
+ end
77
+
78
+ test "readlink returns the expected value when reading a symlink" do
79
+ omit_unless(@admin)
80
+ File.symlink(@file, @link)
81
+ expected = File.expand_path(@file).tr("/", "\\")
82
+ assert_equal(expected, File.readlink(@link))
83
+ end
84
+
85
+ test "readlink raises an error when reading a regular file" do
86
+ assert_raise(Errno::EINVAL){ File.readlink(@@file) }
87
+ end
88
+
89
+ test "readlink requires one argument only" do
90
+ assert_raise(ArgumentError){ File.readlink }
91
+ assert_raise(ArgumentError){ File.readlink(@link, @link) }
92
+ end
93
+
94
+ test "readlink raises an error if the file is not found" do
95
+ assert_raise(Errno::ENOENT){ File.readlink('bogus.txt') }
96
+ end
97
+
98
+ test "realdirpath basic functionality" do
99
+ assert_respond_to(File, :realdirpath)
100
+ end
101
+
102
+ test "realdirpath returns the expected value for a regular file" do
103
+ assert_equal(Dir.pwd, File.realdirpath(Dir.pwd))
104
+ assert_equal(@@file, File.realdirpath(@@file).tr("/", "\\"))
105
+ end
106
+
107
+ test "realdirpath returns the expected value for a symlink" do
108
+ omit_unless(@admin)
109
+ File.symlink(@@file, @link)
110
+ expected = File.expand_path(@file).tr("/", "\\")
111
+ assert_equal(expected, File.realdirpath(@link))
112
+ end
113
+
114
+ test "realpath basic functionality" do
115
+ assert_respond_to(File, :realpath)
116
+ end
117
+
118
+ test "realpath returns the expected value for a regular file" do
119
+ assert_equal(Dir.pwd, File.realpath(Dir.pwd))
120
+ assert_equal(@@file, File.realpath(@@file).tr("/", "\\"))
121
+ end
122
+
123
+ test "realpath returns the expected value for a symlink" do
124
+ omit_unless(@admin)
125
+ File.symlink(@@file, @link)
126
+ expected = File.expand_path(@file).tr("/", "\\")
127
+ assert_equal(expected, File.realpath(@link))
128
+ end
129
+
130
+ def teardown
131
+ File.delete(@link) rescue nil # Necessary for dangling links
132
+ @link = nil
133
+ @admin = nil
134
+ @file = nil
135
+ end
136
+
137
+ def self.shutdown
138
+ File.delete(@@file) if File.exists?(@@file)
139
+ @@file = nil
140
+ end
141
+ end
@@ -0,0 +1,16 @@
1
+ ########################################################################
2
+ # Miscellaneous tests for win32-file that didn't fit anywhere else.
3
+ ########################################################################
4
+ require 'win32/file'
5
+ require 'test-unit'
6
+
7
+ class TC_Win32_File_Misc < Test::Unit::TestCase
8
+ test "version constant is set to expected value" do
9
+ assert_equal('0.7.0', File::WIN32_FILE_VERSION)
10
+ end
11
+
12
+ test "ffi functions are private" do
13
+ assert_not_respond_to(File, :CloseHandle)
14
+ assert_not_respond_to(File, :CreateFileW)
15
+ end
16
+ end
@@ -2,32 +2,29 @@
2
2
  # test_win32_file_path.rb
3
3
  #
4
4
  # Test case for the path related methods of win32-file. You should run this
5
- # test via the 'rake test' or 'rake test_path' task.
5
+ # test via the 'rake' or 'rake test:path' task.
6
6
  #############################################################################
7
- require 'rubygems'
8
- gem 'test-unit'
9
-
10
- require 'test/unit'
7
+ require 'test-unit'
11
8
  require 'win32/file'
12
9
 
13
10
  class TC_Win32_File_Path < Test::Unit::TestCase
14
11
  def self.startup
15
- Dir.chdir(File.dirname(File.expand_path(File.basename(__FILE__))))
12
+ Dir.chdir(File.expand_path(File.dirname(__FILE__)))
16
13
  @@file = File.join(Dir.pwd, 'path_test.txt')
17
14
  File.open(@@file, 'w'){ |fh| fh.puts "This is a path test." }
18
15
  end
19
16
 
20
17
  def setup
21
- @long_file = File.join(Dir.pwd, 'path_test.txt')
22
- @short_file = File.join(Dir.pwd, 'PATH_T~1.TXT')
18
+ @long_file = File.join(Dir.pwd, 'path_test.txt').tr("/", "\\")
19
+ @short_file = File.join(Dir.pwd, 'PATH_T~1.TXT').tr("/", "\\")
23
20
  end
24
-
21
+
25
22
  test "basename method basic functionality" do
26
23
  assert_respond_to(File, :basename)
27
24
  assert_nothing_raised{ File.basename("C:\\foo") }
28
25
  assert_kind_of(String, File.basename("C:\\foo"))
29
26
  end
30
-
27
+
31
28
  test "basename method handles standard paths" do
32
29
  assert_equal("baz.txt", File.basename("C:\\foo\\bar\\baz.txt"))
33
30
  assert_equal("baz", File.basename("C:\\foo\\bar\\baz.txt", ".txt"))
@@ -37,14 +34,14 @@ class TC_Win32_File_Path < Test::Unit::TestCase
37
34
  assert_equal("foo", File.basename("C:\\foo"))
38
35
  assert_equal("C:\\", File.basename("C:\\"))
39
36
  end
40
-
37
+
41
38
  test "basename method handles unc paths" do
42
39
  assert_equal("baz.txt", File.basename("\\\\foo\\bar\\baz.txt"))
43
40
  assert_equal("baz", File.basename("\\\\foo\\bar\\baz"))
44
41
  assert_equal("\\\\foo", File.basename("\\\\foo"))
45
42
  assert_equal("\\\\foo\\bar", File.basename("\\\\foo\\bar"))
46
43
  end
47
-
44
+
48
45
  test "basename method handles forward slashes in standard unix paths" do
49
46
  assert_equal("bar", File.basename("/foo/bar"))
50
47
  assert_equal("bar.txt", File.basename("/foo/bar.txt"))
@@ -58,7 +55,7 @@ class TC_Win32_File_Path < Test::Unit::TestCase
58
55
  assert_equal("\\\\foo", File.basename("//foo"))
59
56
  assert_equal("\\\\foo\\bar", File.basename("//foo/bar"))
60
57
  end
61
-
58
+
62
59
  test "basename method handles forward slashes in windows paths" do
63
60
  assert_equal("bar", File.basename("C:/foo/bar"))
64
61
  assert_equal("bar", File.basename("C:/foo/bar/"))
@@ -66,14 +63,14 @@ class TC_Win32_File_Path < Test::Unit::TestCase
66
63
  assert_equal("C:\\", File.basename("C:/"))
67
64
  assert_equal("bar", File.basename("C:/foo/bar//"))
68
65
  end
69
-
66
+
70
67
  test "basename handles edge cases as expected" do
71
68
  assert_equal("", File.basename(""))
72
69
  assert_equal(".", File.basename("."))
73
70
  assert_equal("..", File.basename(".."))
74
71
  assert_equal("foo", File.basename("//foo/"))
75
72
  end
76
-
73
+
77
74
  test "basename handles path names with suffixes" do
78
75
  assert_equal("bar", File.basename("bar.txt", ".txt"))
79
76
  assert_equal("bar", File.basename("/foo/bar.txt", ".txt"))
@@ -83,11 +80,11 @@ class TC_Win32_File_Path < Test::Unit::TestCase
83
80
  assert_equal("bar", File.basename("bar.txt", ".*"))
84
81
  assert_equal("bar.txt", File.basename("bar.txt.exe", ".*"))
85
82
  end
86
-
83
+
87
84
  test "basename method does not modify its argument" do
88
85
  path = "C:\\foo\\bar"
89
86
  assert_nothing_raised{ File.basename(path) }
90
- assert_equal("C:\\foo\\bar", path)
87
+ assert_equal("C:\\foo\\bar", path)
91
88
  end
92
89
 
93
90
  test "basename removes all trailing slashes" do
@@ -99,13 +96,13 @@ class TC_Win32_File_Path < Test::Unit::TestCase
99
96
  assert_equal("foo.txt", File.basename("C:\\foo.txt\\\\\\"))
100
97
  assert_equal("foo.txt", File.basename("foo.txt\\\\\\"))
101
98
  end
102
-
99
+
103
100
  test "dirname basic functionality" do
104
101
  assert_respond_to(File, :dirname)
105
102
  assert_nothing_raised{ File.dirname("C:\\foo") }
106
103
  assert_kind_of(String, File.dirname("C:\\foo"))
107
104
  end
108
-
105
+
109
106
  test "dirname handles standard windows paths as expected" do
110
107
  assert_equal("C:\\foo", File.dirname("C:\\foo\\bar.txt"))
111
108
  assert_equal("C:\\foo", File.dirname("C:\\foo\\bar"))
@@ -113,14 +110,14 @@ class TC_Win32_File_Path < Test::Unit::TestCase
113
110
  assert_equal("C:\\", File.dirname("C:\\"))
114
111
  assert_equal(".", File.dirname("foo"))
115
112
  end
116
-
113
+
117
114
  test "dirname handles unc windows paths as expected" do
118
115
  assert_equal("\\\\foo\\bar", File.dirname("\\\\foo\\bar\\baz"))
119
116
  assert_equal("\\\\foo\\bar", File.dirname("\\\\foo\\bar"))
120
117
  assert_equal("\\\\foo", File.dirname("\\\\foo"))
121
118
  assert_equal("\\\\", File.dirname("\\\\"))
122
119
  end
123
-
120
+
124
121
  test "dirname handles forward slashes in standard windows path names" do
125
122
  assert_equal("C:\\foo", File.dirname("C:/foo/bar.txt"))
126
123
  assert_equal("C:\\foo", File.dirname("C:/foo/bar"))
@@ -139,14 +136,14 @@ class TC_Win32_File_Path < Test::Unit::TestCase
139
136
  assert_equal(".", File.dirname("./foo"))
140
137
  assert_equal(".\\foo", File.dirname("./foo/bar"))
141
138
  end
142
-
139
+
143
140
  test "dirname handles various edge cases as expected" do
144
141
  assert_equal(".", File.dirname(""))
145
142
  assert_equal(".", File.dirname("."))
146
143
  assert_equal(".", File.dirname(".."))
147
144
  assert_equal(".", File.dirname("./"))
148
145
  end
149
-
146
+
150
147
  test "dirname method does not modify its argument" do
151
148
  path = "C:\\foo\\bar"
152
149
  assert_nothing_raised{ File.dirname(path) }
@@ -171,9 +168,9 @@ class TC_Win32_File_Path < Test::Unit::TestCase
171
168
  assert_nothing_raised{ File.split("C:\\foo\\bar") }
172
169
  assert_kind_of(Array, File.split("C:\\foo\\bar"))
173
170
  end
174
-
171
+
175
172
  test "split method handles standard windows path names" do
176
- assert_equal(["C:\\foo", "bar"], File.split("C:\\foo\\bar"))
173
+ assert_equal(["C:\\foo", "bar"], File.split("C:\\foo\\bar"))
177
174
  assert_equal([".", "foo"], File.split("foo"))
178
175
  end
179
176
 
@@ -181,13 +178,13 @@ class TC_Win32_File_Path < Test::Unit::TestCase
181
178
  assert_equal(["C:\\foo", "bar"], File.split("C:/foo/bar"))
182
179
  assert_equal([".", "foo"], File.split("foo"))
183
180
  end
184
-
181
+
185
182
  test "split method handles standard unix paths as expected" do
186
183
  assert_equal(["\\foo","bar"], File.split("/foo/bar"))
187
184
  assert_equal(["\\", "foo"], File.split("/foo"))
188
185
  assert_equal([".", "foo"], File.split("foo"))
189
186
  end
190
-
187
+
191
188
  test "split method handles unc paths as expected" do
192
189
  assert_equal(["\\\\foo\\bar", "baz"], File.split("\\\\foo\\bar\\baz"))
193
190
  assert_equal(["\\\\foo\\bar", ""], File.split("\\\\foo\\bar"))
@@ -199,22 +196,32 @@ class TC_Win32_File_Path < Test::Unit::TestCase
199
196
  assert_equal(["C:\\", ""], File.split("C:\\"))
200
197
  assert_equal(["", ""], File.split(""))
201
198
  end
202
-
199
+
203
200
  test "split method does not modify its arguments" do
204
201
  path = "C:\\foo\\bar"
205
202
  assert_nothing_raised{ File.split(path) }
206
203
  assert_equal("C:\\foo\\bar", path)
207
204
  end
208
-
209
- test "long_path method works as expected" do
205
+
206
+ test "File.long_path basic functionality" do
210
207
  assert_respond_to(File, :long_path)
208
+ assert_nothing_raised{ File.long_path(@short_file) }
209
+ assert_kind_of(String, File.long_path(@short_file))
210
+ end
211
+
212
+ test "File.long_path returns the expected result" do
211
213
  assert_equal(@long_file, File.long_path(@short_file))
212
- assert_equal('PATH_T~1.TXT', File.basename(@short_file))
213
214
  end
214
-
215
- test "short_path method works as expected" do
215
+
216
+ test "File.short_path basic functionality" do
216
217
  assert_respond_to(File, :short_path)
217
- assert_equal('path_test.txt', File.basename(@long_file))
218
+ assert_nothing_raised{ File.short_path(@short_file) }
219
+ assert_kind_of(String, File.short_path(@short_file))
220
+ end
221
+
222
+ test "File.short_path returns the expected result" do
223
+ path = File.short_path(@long_file)
224
+ assert_equal('PATH_T~1.TXT', File.basename(path))
218
225
  end
219
226
 
220
227
  test "join method works as expected" do
@@ -243,7 +250,7 @@ class TC_Win32_File_Path < Test::Unit::TestCase
243
250
  assert_equal('foo', File.join('foo'))
244
251
  assert_equal('c:', File.join('c:'))
245
252
  end
246
-
253
+
247
254
  def teardown
248
255
  @short_file = nil
249
256
  @long_file = nil