win32-file 0.6.9 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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