win32-file-stat 1.3.4 → 1.3.5

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.
data/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ == 1.3.5 - 21-Nov-2011
2
+ * Fixed a bug in the dev method for 1.9.x.
3
+ * Fixed some method redefinition warnings.
4
+ * Refactored the Rakefile and gemspec. The old install task has been
5
+ removed from the Rakefile.
6
+
1
7
  == 1.3.4 - 13-Aug-2009
2
8
  * Changed license to Artistic 2.0.
3
9
  * Some gemspec updates, including the addition of a license, an updated
@@ -91,4 +97,4 @@
91
97
  * Some optimization in the constructor.
92
98
 
93
99
  == 1.0.0 - 13-Apr-2006
94
- * Initial release
100
+ * Initial release
data/Rakefile CHANGED
@@ -1,24 +1,26 @@
1
1
  require 'rake'
2
+ require 'rake/clean'
2
3
  require 'rake/testtask'
3
- require 'rbconfig'
4
- include Config
5
4
 
6
- desc 'Install the win32-file-stat library (non-gem)'
7
- task :install do
8
- install_dir = File.join(CONFIG['sitelibdir'], 'win32', 'file')
9
- file = 'lib\win32\file\stat.rb'
10
- FileUtils.mkdir_p(install_dir)
11
- FileUtils.cp(file, install_dir, :verbose => true)
12
- end
5
+ CLEAN.include("**/*.gem", "**/*.rbx", "**/*.rbc")
6
+
7
+ namespace :gem do
8
+ desc "Create the win32-file-stat gem"
9
+ task :create => [:clean] do
10
+ spec = eval(IO.read("win32-file-stat.gemspec"))
11
+ Gem::Builder.new(spec).build
12
+ end
13
13
 
14
- desc 'Install the win32-file-stat library as a gem'
15
- task :install_gem do
16
- ruby 'win32-file-stat.gemspec'
17
- file = Dir["win32-file-stat*.gem"].first
18
- sh "gem install #{file}"
14
+ desc "Install the win32-file-stat gem"
15
+ task :install => [:create] do
16
+ file = Dir["win32-file-stat*.gem"].first
17
+ sh "gem install #{file}"
18
+ end
19
19
  end
20
20
 
21
21
  Rake::TestTask.new do |t|
22
- t.verbose = true
23
- t.warning = true
24
- end
22
+ t.verbose = true
23
+ t.warning = true
24
+ end
25
+
26
+ task :default => :test
@@ -14,727 +14,736 @@ require 'windows/ntfs/winternl'
14
14
  require 'pp'
15
15
 
16
16
  class File::Stat
17
- include Windows::MSVCRT::Buffer
18
- include Windows::MSVCRT::File
19
- include Windows::DeviceIO
20
- include Windows::FileSystem
21
- include Windows::Path
22
- include Windows::File
23
- include Windows::Error
24
- include Windows::Handle
25
- include Windows::Volume
26
- include Windows::Process
27
- include Windows::Security
28
- include Windows::Time
29
- include Windows::NTFS::Winternl
30
- include Comparable
31
-
32
- # The version of the win32-file-stat library
33
- VERSION = '1.3.4'
34
-
35
- private
36
-
37
- # :stopdoc:
38
-
39
- # Defined in Ruby's win32.h. Not meant for public consumption.
40
- S_IWGRP = 0020
41
- S_IWOTH = 0002
42
-
43
- # This is the only way to avoid a -w warning for initialize. We remove
44
- # it later, after we've defined our initialize method.
45
- alias old_init initialize
46
-
47
- # Make this library -w clean
48
- undef_method(:atime, :blksize, :blockdev?, :blocks, :chardev?, :ctime)
49
- undef_method(:dev, :directory?, :executable?, :file?, :ftype, :gid, :ino)
50
- undef_method(:executable_real?, :grpowned?, :mode, :mtime, :nlink, :owned?)
51
- undef_method(:pipe?, :readable?, :rdev, :readable_real?, :setgid?, :setuid?)
52
- undef_method(:size, :size?, :socket?, :sticky?, :symlink?, :uid, :writable?)
53
- undef_method(:writable_real?, :zero?)
54
- undef_method(:pretty_print, :inspect, :<=>)
55
-
56
- public
57
-
58
- # Always nil. Provided for interface compatibility only.
59
- attr_reader :dev_major
60
- attr_reader :dev_minor
61
- attr_reader :rdev_major
62
- attr_reader :rdev_minor
63
-
64
- # :startdoc:
65
-
66
- # Creates and returns a File::Stat object, which encapsulate common status
67
- # information for File objects on MS Windows sytems. The information is
68
- # recorded at the moment the File::Stat object is created; changes made to
69
- # the file after that point will not be reflected.
70
- #
71
- def initialize(file)
72
- @file = File.expand_path(file)
73
- @file = @file.tr('/', "\\")
74
- @file = multi_to_wide(@file)
75
-
76
- @file_type = get_file_type(@file)
77
- @chardev = @file_type == FILE_TYPE_CHAR
78
-
79
- case GetDriveTypeW(@file)
80
- when DRIVE_REMOVABLE, DRIVE_CDROM, DRIVE_RAMDISK
81
- @blockdev = true
82
- else
83
- @blockdev = false
84
- end
17
+ include Windows::MSVCRT::Buffer
18
+ include Windows::MSVCRT::File
19
+ include Windows::DeviceIO
20
+ include Windows::FileSystem
21
+ include Windows::Path
22
+ include Windows::File
23
+ include Windows::Error
24
+ include Windows::Handle
25
+ include Windows::Volume
26
+ include Windows::Process
27
+ include Windows::Security
28
+ include Windows::Time
29
+ include Windows::NTFS::Winternl
30
+ include Comparable
31
+
32
+ # The version of the win32-file-stat library
33
+ VERSION = '1.3.5'
34
+
35
+ private
36
+
37
+ # :stopdoc:
38
+
39
+ # Defined in Ruby's win32.h. Not meant for public consumption.
40
+ S_IWGRP = 0020
41
+ S_IWOTH = 0002
42
+
43
+ # This is the only way to avoid a -w warning for initialize. We remove
44
+ # it later, after we've defined our initialize method.
45
+ alias old_init initialize
46
+
47
+ # Make this library -w clean
48
+ undef_method(:atime, :blksize, :blockdev?, :blocks, :chardev?, :ctime)
49
+ undef_method(:dev, :directory?, :executable?, :file?, :ftype, :gid, :ino)
50
+ undef_method(:executable_real?, :grpowned?, :mode, :mtime, :nlink, :owned?)
51
+ undef_method(:pipe?, :readable?, :rdev, :readable_real?, :setgid?, :setuid?)
52
+ undef_method(:size, :size?, :socket?, :sticky?, :symlink?, :uid, :writable?)
53
+ undef_method(:dev_major, :dev_minor, :rdev_major, :rdev_minor)
54
+ undef_method(:writable_real?, :zero?)
55
+ undef_method(:pretty_print, :inspect, :<=>)
56
+
57
+ public
58
+
59
+ # Always nil. Provided for interface compatibility only.
60
+ attr_reader :dev_major
61
+ attr_reader :dev_minor
62
+ attr_reader :rdev_major
63
+ attr_reader :rdev_minor
64
+
65
+ # :startdoc:
66
+
67
+ # Creates and returns a File::Stat object, which encapsulate common status
68
+ # information for File objects on MS Windows sytems. The information is
69
+ # recorded at the moment the File::Stat object is created; changes made to
70
+ # the file after that point will not be reflected.
71
+ #
72
+ def initialize(file)
73
+ @file = File.expand_path(file)
74
+ @file = @file.tr('/', "\\")
75
+ @file = multi_to_wide(@file)
76
+
77
+ @file_type = get_file_type(@file)
78
+ @chardev = @file_type == FILE_TYPE_CHAR
79
+
80
+ case GetDriveTypeW(@file)
81
+ when DRIVE_REMOVABLE, DRIVE_CDROM, DRIVE_RAMDISK
82
+ @blockdev = true
83
+ else
84
+ @blockdev = false
85
+ end
85
86
 
86
- # The stat struct in stat.h only has 11 members on Windows
87
- stat_buf = [0,0,0,0,0,0,0,0,0,0,0].pack('ISSsssIQQQQ')
88
-
89
- # The stat64 function doesn't seem to like character devices
90
- if wstat64(@file, stat_buf) != 0
91
- raise ArgumentError, get_last_error unless @chardev
92
- end
93
-
94
- # Some bytes skipped (padding for struct alignment)
95
- @dev = stat_buf[0, 4].unpack('I').first # Drive number
96
- @ino = stat_buf[4, 2].unpack('S').first # Meaningless
97
- @mode = stat_buf[6, 2].unpack('S').first # File mode bit mask
98
- @nlink = stat_buf[8, 2].unpack('s').first # Always 1
99
- @uid = stat_buf[10, 2].unpack('s').first # Always 0
100
- @gid = stat_buf[12, 2].unpack('s').first # Always 0
101
- @rdev = stat_buf[16, 4].unpack('I').first # Same as dev
102
- @size = stat_buf[24, 8].unpack('Q').first # Size of file in bytes
87
+ # The stat struct in stat.h only has 11 members on Windows
88
+ stat_buf = [0,0,0,0,0,0,0,0,0,0,0].pack('ISSsssIQQQQ')
89
+
90
+ # The stat64 function doesn't seem to like character devices
91
+ if wstat64(@file, stat_buf) != 0
92
+ raise ArgumentError, get_last_error unless @chardev
93
+ end
94
+
95
+ # Some bytes skipped (padding for struct alignment)
96
+ @dev = stat_buf[0, 4].unpack('I').first # Drive number
97
+ @ino = stat_buf[4, 2].unpack('S').first # Meaningless
98
+ @mode = stat_buf[6, 2].unpack('S').first # File mode bit mask
99
+ @nlink = stat_buf[8, 2].unpack('s').first # Always 1
100
+ @uid = stat_buf[10, 2].unpack('s').first # Always 0
101
+ @gid = stat_buf[12, 2].unpack('s').first # Always 0
102
+ @rdev = stat_buf[16, 4].unpack('I').first # Same as dev
103
+ @size = stat_buf[24, 8].unpack('Q').first # Size of file in bytes
103
104
 
104
- # This portion can fail in rare, FS related instances. If it does, set
105
- # the various times to Time.at(0).
106
- begin
107
- @atime = Time.at(stat_buf[32, 8].unpack('Q').first) # Access time
108
- @mtime = Time.at(stat_buf[40, 8].unpack('Q').first) # Mod time
109
- @ctime = Time.at(stat_buf[48, 8].unpack('Q').first) # Creation time
110
- rescue
111
- @atime = Time.at(0)
112
- @mtime = Time.at(0)
113
- @ctime = Time.at(0)
114
- end
105
+ # This portion can fail in rare, FS related instances. If it does, set
106
+ # the various times to Time.at(0).
107
+ begin
108
+ @atime = Time.at(stat_buf[32, 8].unpack('Q').first) # Access time
109
+ @mtime = Time.at(stat_buf[40, 8].unpack('Q').first) # Mod time
110
+ @ctime = Time.at(stat_buf[48, 8].unpack('Q').first) # Creation time
111
+ rescue
112
+ @atime = Time.at(0)
113
+ @mtime = Time.at(0)
114
+ @ctime = Time.at(0)
115
+ end
115
116
 
116
- @mode = 33188 if @chardev
117
+ @mode = 33188 if @chardev
117
118
 
118
- attributes = GetFileAttributesW(@file)
119
- error_num = GetLastError()
119
+ attributes = GetFileAttributesW(@file)
120
+ error_num = GetLastError()
120
121
 
121
- # Locked files.
122
- if error_num == ERROR_SHARING_VIOLATION
123
- buffer = 0.chr * 512
122
+ # Locked files.
123
+ if error_num == ERROR_SHARING_VIOLATION
124
+ buffer = 0.chr * 512
124
125
 
125
- begin
126
- handle = FindFirstFileW(@file, buffer)
126
+ begin
127
+ handle = FindFirstFileW(@file, buffer)
127
128
 
128
- if handle == INVALID_HANDLE_VALUE
129
- raise SystemCallError, get_last_error()
130
- end
131
- ensure
132
- FindClose(handle) if handle != INVALID_HANDLE_VALUE
133
- end
134
-
135
- attributes = buffer[0,4].unpack('L').first
136
- st = 0.chr * 16
137
- FileTimeToSystemTime(buffer[4,8],st)
138
- y,m,w,d,h,n,s,i = st.unpack('SSSSSSSS')
139
- @ctime = Time.local(y,m,d,h,n,s)
140
-
141
- st = 0.chr * 16
142
- FileTimeToSystemTime(buffer[12,8],st)
143
- y,m,w,d,h,n,s,i = st.unpack('SSSSSSSS')
144
- @atime = Time.local(y,m,d,h,n,s)
145
-
146
- st = 0.chr * 16
147
- FileTimeToSystemTime(buffer[20,8],st)
148
- y,m,w,d,h,n,s,i = st.unpack('SSSSSSSS')
149
- @mtime = Time.local(y,m,d,h,n,s)
129
+ if handle == INVALID_HANDLE_VALUE
130
+ raise SystemCallError, get_last_error()
131
+ end
132
+ ensure
133
+ FindClose(handle) if handle != INVALID_HANDLE_VALUE
150
134
  end
151
135
 
152
- # Ignore errors caused by empty/open/used block devices.
153
- if attributes == INVALID_FILE_ATTRIBUTES
154
- unless error_num == ERROR_NOT_READY
155
- raise ArgumentError, get_last_error(error_num)
156
- end
136
+ attributes = buffer[0,4].unpack('L').first
137
+ st = 0.chr * 16
138
+ FileTimeToSystemTime(buffer[4,8],st)
139
+ y,m,w,d,h,n,s,i = st.unpack('SSSSSSSS')
140
+ @ctime = Time.local(y,m,d,h,n,s)
141
+
142
+ st = 0.chr * 16
143
+ FileTimeToSystemTime(buffer[12,8],st)
144
+ y,m,w,d,h,n,s,i = st.unpack('SSSSSSSS')
145
+ @atime = Time.local(y,m,d,h,n,s)
146
+
147
+ st = 0.chr * 16
148
+ FileTimeToSystemTime(buffer[20,8],st)
149
+ y,m,w,d,h,n,s,i = st.unpack('SSSSSSSS')
150
+ @mtime = Time.local(y,m,d,h,n,s)
151
+ end
152
+
153
+ # Ignore errors caused by empty/open/used block devices.
154
+ if attributes == INVALID_FILE_ATTRIBUTES
155
+ unless error_num == ERROR_NOT_READY
156
+ raise ArgumentError, get_last_error(error_num)
157
157
  end
158
+ end
158
159
 
159
- @blksize = get_blksize(@file)
160
+ @blksize = get_blksize(@file)
160
161
 
161
- # This is a reasonable guess
162
- case @blksize
163
- when nil
164
- @blocks = nil
165
- when 0
166
- @blocks = 0
167
- else
168
- @blocks = (@size.to_f / @blksize.to_f).ceil
169
- end
162
+ # This is a reasonable guess
163
+ case @blksize
164
+ when nil
165
+ @blocks = nil
166
+ when 0
167
+ @blocks = 0
168
+ else
169
+ @blocks = (@size.to_f / @blksize.to_f).ceil
170
+ end
170
171
 
171
- @readonly = attributes & FILE_ATTRIBUTE_READONLY > 0
172
- @hidden = attributes & FILE_ATTRIBUTE_HIDDEN > 0
173
- @system = attributes & FILE_ATTRIBUTE_SYSTEM > 0
174
- @archive = attributes & FILE_ATTRIBUTE_ARCHIVE > 0
175
- @directory = attributes & FILE_ATTRIBUTE_DIRECTORY > 0
176
- @encrypted = attributes & FILE_ATTRIBUTE_ENCRYPTED > 0
177
- @normal = attributes & FILE_ATTRIBUTE_NORMAL > 0
178
- @temporary = attributes & FILE_ATTRIBUTE_TEMPORARY > 0
179
- @sparse = attributes & FILE_ATTRIBUTE_SPARSE_FILE > 0
180
- @reparse_point = attributes & FILE_ATTRIBUTE_REPARSE_POINT > 0
181
- @compressed = attributes & FILE_ATTRIBUTE_COMPRESSED > 0
182
- @offline = attributes & FILE_ATTRIBUTE_OFFLINE > 0
183
- @indexed = attributes & ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED > 0
172
+ @readonly = attributes & FILE_ATTRIBUTE_READONLY > 0
173
+ @hidden = attributes & FILE_ATTRIBUTE_HIDDEN > 0
174
+ @system = attributes & FILE_ATTRIBUTE_SYSTEM > 0
175
+ @archive = attributes & FILE_ATTRIBUTE_ARCHIVE > 0
176
+ @directory = attributes & FILE_ATTRIBUTE_DIRECTORY > 0
177
+ @encrypted = attributes & FILE_ATTRIBUTE_ENCRYPTED > 0
178
+ @normal = attributes & FILE_ATTRIBUTE_NORMAL > 0
179
+ @temporary = attributes & FILE_ATTRIBUTE_TEMPORARY > 0
180
+ @sparse = attributes & FILE_ATTRIBUTE_SPARSE_FILE > 0
181
+ @reparse_point = attributes & FILE_ATTRIBUTE_REPARSE_POINT > 0
182
+ @compressed = attributes & FILE_ATTRIBUTE_COMPRESSED > 0
183
+ @offline = attributes & FILE_ATTRIBUTE_OFFLINE > 0
184
+ @indexed = attributes & ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED > 0
184
185
 
185
- @executable = GetBinaryTypeW(@file, '')
186
- @regular = @file_type == FILE_TYPE_DISK
187
- @pipe = @file_type == FILE_TYPE_PIPE
186
+ @executable = GetBinaryTypeW(@file, '')
187
+ @regular = @file_type == FILE_TYPE_DISK
188
+ @pipe = @file_type == FILE_TYPE_PIPE
188
189
 
189
- # Not supported and/or meaningless
190
- @dev_major = nil
191
- @dev_minor = nil
192
- @grpowned = true
193
- @owned = true
194
- @readable = true
195
- @readable_real = true
196
- @rdev_major = nil
197
- @rdev_minor = nil
198
- @setgid = false
199
- @setuid = false
200
- @sticky = false
201
- @symlink = false
202
- @writable = true
203
- @writable_real = true
204
- end
205
-
206
- ## Comparable
207
-
208
- # Compares two File::Stat objects. Comparsion is based on mtime only.
209
- #
210
- def <=>(other)
211
- @mtime.to_i <=> other.mtime.to_i
212
- end
213
-
214
- ## Miscellaneous
215
-
216
- # Returns whether or not the file is a block device. For MS Windows a
217
- # block device is a removable drive, cdrom or ramdisk.
218
- #
219
- def blockdev?
220
- @blockdev
221
- end
222
-
223
- # Returns whether or not the file is a character device.
224
- #
225
- def chardev?
226
- @chardev
227
- end
228
-
229
- # Returns whether or not the file is executable. Generally speaking, this
230
- # means .bat, .cmd, .com, and .exe files.
231
- #
232
- def executable?
233
- @executable
234
- end
235
-
236
- alias :executable_real? :executable?
237
-
238
- # Returns whether or not the file is a regular file, as opposed to a pipe,
239
- # socket, etc.
240
- #
241
- def file?
242
- @regular
243
- end
244
-
245
- # Identifies the type of file. The return string is one of: file,
246
- # directory, characterSpecial, socket or unknown.
247
- #
248
- def ftype
249
- return 'directory' if directory?
250
- case @file_type
251
- when FILE_TYPE_CHAR
252
- 'characterSpecial'
253
- when FILE_TYPE_DISK
254
- 'file'
255
- when FILE_TYPE_PIPE
256
- 'socket'
257
- else
258
- if blockdev?
259
- 'blockSpecial'
260
- else
261
- 'unknown'
262
- end
190
+ # Not supported and/or meaningless
191
+ @dev_major = nil
192
+ @dev_minor = nil
193
+ @grpowned = true
194
+ @owned = true
195
+ @readable = true
196
+ @readable_real = true
197
+ @rdev_major = nil
198
+ @rdev_minor = nil
199
+ @setgid = false
200
+ @setuid = false
201
+ @sticky = false
202
+ @symlink = false
203
+ @writable = true
204
+ @writable_real = true
205
+ end
206
+
207
+ ## Comparable
208
+
209
+ # Compares two File::Stat objects. Comparsion is based on mtime only.
210
+ #
211
+ def <=>(other)
212
+ @mtime.to_i <=> other.mtime.to_i
213
+ end
214
+
215
+ ## Miscellaneous
216
+
217
+ # Returns whether or not the file is a block device. For MS Windows a
218
+ # block device is a removable drive, cdrom or ramdisk.
219
+ #
220
+ def blockdev?
221
+ @blockdev
222
+ end
223
+
224
+ # Returns whether or not the file is a character device.
225
+ #
226
+ def chardev?
227
+ @chardev
228
+ end
229
+
230
+ # Returns whether or not the file is executable. Generally speaking, this
231
+ # means .bat, .cmd, .com, and .exe files.
232
+ #
233
+ def executable?
234
+ @executable
235
+ end
236
+
237
+ alias :executable_real? :executable?
238
+
239
+ # Returns whether or not the file is a regular file, as opposed to a pipe,
240
+ # socket, etc.
241
+ #
242
+ def file?
243
+ @regular
244
+ end
245
+
246
+ # Identifies the type of file. The return string is one of 'file',
247
+ # 'directory', 'characterSpecial', 'socket' or 'unknown'.
248
+ #
249
+ def ftype
250
+ return 'directory' if directory?
251
+ case @file_type
252
+ when FILE_TYPE_CHAR
253
+ 'characterSpecial'
254
+ when FILE_TYPE_DISK
255
+ 'file'
256
+ when FILE_TYPE_PIPE
257
+ 'socket'
258
+ else
259
+ if blockdev?
260
+ 'blockSpecial'
261
+ else
262
+ 'unknown'
263
+ end
264
+ end
265
+ end
266
+
267
+ # Meaningless on Windows.
268
+ #
269
+ def grpowned?
270
+ @grpowned
271
+ end
272
+
273
+ # Always true on Windows
274
+ def owned?
275
+ @owned
276
+ end
277
+
278
+ # Returns whether or not the file is a pipe.
279
+ #
280
+ def pipe?
281
+ @pipe
282
+ end
283
+
284
+ alias :socket? :pipe?
285
+
286
+ # Meaningless on Windows
287
+ #
288
+ def readable?
289
+ @readable
290
+ end
291
+
292
+ # Meaningless on Windows
293
+ #
294
+ def readable_real?
295
+ @readable_real
296
+ end
297
+
298
+ # Meaningless on Windows
299
+ #
300
+ def setgid?
301
+ @setgid
302
+ end
303
+
304
+ # Meaningless on Windows
305
+ #
306
+ def setuid?
307
+ @setuid
308
+ end
309
+
310
+ # Returns nil if statfile is a zero-length file; otherwise, returns the
311
+ # file size. Usable as a condition in tests.
312
+ #
313
+ def size?
314
+ @size > 0 ? @size : nil
315
+ end
316
+
317
+ # Meaningless on Windows.
318
+ #
319
+ def sticky?
320
+ @sticky
321
+ end
322
+
323
+ # Meaningless on Windows at the moment. This may change in the future.
324
+ #
325
+ def symlink?
326
+ @symlink
327
+ end
328
+
329
+ # Meaningless on Windows.
330
+ #
331
+ def writable?
332
+ @writable
333
+ end
334
+
335
+ # Meaningless on Windows.
336
+ #
337
+ def writable_real?
338
+ @writable_real
339
+ end
340
+
341
+ # Returns whether or not the file size is zero.
342
+ #
343
+ def zero?
344
+ @size == 0
345
+ end
346
+
347
+ ## Attribute members
348
+
349
+ # Returns whether or not the file is an archive file.
350
+ #
351
+ def archive?
352
+ @archive
353
+ end
354
+
355
+ # Returns whether or not the file is compressed.
356
+ #
357
+ def compressed?
358
+ @compressed
359
+ end
360
+
361
+ # Returns whether or not the file is a directory.
362
+ #
363
+ def directory?
364
+ @directory
365
+ end
366
+
367
+ # Returns whether or not the file in encrypted.
368
+ #
369
+ def encrypted?
370
+ @encrypted
371
+ end
372
+
373
+ # Returns whether or not the file is hidden.
374
+ #
375
+ def hidden?
376
+ @hidden
377
+ end
378
+
379
+ # Returns whether or not the file is content indexed.
380
+ #
381
+ def indexed?
382
+ @indexed
383
+ end
384
+
385
+ alias :content_indexed? :indexed?
386
+
387
+ # Returns whether or not the file is 'normal'. This is only true if
388
+ # virtually all other attributes are false.
389
+ #
390
+ def normal?
391
+ @normal
392
+ end
393
+
394
+ # Returns whether or not the file is offline.
395
+ #
396
+ def offline?
397
+ @offline
398
+ end
399
+
400
+ # Returns whether or not the file is readonly.
401
+ #
402
+ def readonly?
403
+ @readonly
404
+ end
405
+
406
+ alias :read_only? :readonly?
407
+
408
+ # Returns whether or not the file is a reparse point.
409
+ #
410
+ def reparse_point?
411
+ @reparse_point
412
+ end
413
+
414
+ # Returns whether or not the file is a sparse file. In most cases a sparse
415
+ # file is an image file.
416
+ #
417
+ def sparse?
418
+ @sparse
419
+ end
420
+
421
+ # Returns whether or not the file is a system file.
422
+ #
423
+ def system?
424
+ @system
425
+ end
426
+
427
+ # Returns whether or not the file is being used for temporary storage.
428
+ #
429
+ def temporary?
430
+ @temporary
431
+ end
432
+
433
+ ## Standard stat members
434
+
435
+ # Returns a Time object containing the last access time.
436
+ #
437
+ def atime
438
+ @atime
439
+ end
440
+
441
+ # Returns the file system's block size, or nil if it cannot be determined.
442
+ #
443
+ def blksize
444
+ @blksize
445
+ end
446
+
447
+ # Returns the number of blocks used by the file, where a block is defined
448
+ # as size divided by blksize, rounded up.
449
+ #
450
+ #--
451
+ # This is a fudge. A search of the internet reveals different ways people
452
+ # have defined st_blocks on MS Windows.
453
+ #
454
+ def blocks
455
+ @blocks
456
+ end
457
+
458
+ # Returns a Time object containing the time that the file status associated
459
+ # with the file was changed.
460
+ #
461
+ def ctime
462
+ @ctime
463
+ end
464
+
465
+ # Drive letter (A-Z) of the disk containing the file. If the path is a
466
+ # UNC path then the drive number (probably -1) is returned instead.
467
+ #
468
+ def dev
469
+ if PathIsUNCW(@file)
470
+ @dev
471
+ else
472
+ if RUBY_VERSION.to_f >= 1.9
473
+ (@dev + 'A'.ord).chr + ':'
474
+ else
475
+ (@dev + ?A).chr + ':'
263
476
  end
264
- end
265
-
266
- # Meaningless on Windows.
267
- #
268
- def grpowned?
269
- @grpowned
270
- end
271
-
272
- # Always true on Windows
273
- def owned?
274
- @owned
275
- end
276
-
277
- # Returns whether or not the file is a pipe.
278
- #
279
- def pipe?
280
- @pipe
281
- end
282
-
283
- alias :socket? :pipe?
284
-
285
- # Meaningless on Windows
286
- #
287
- def readable?
288
- @readable
289
- end
290
-
291
- # Meaningless on Windows
292
- #
293
- def readable_real?
294
- @readable_real
295
- end
296
-
297
- # Meaningless on Windows
298
- #
299
- def setgid?
300
- @setgid
301
- end
302
-
303
- # Meaningless on Windows
304
- #
305
- def setuid?
306
- @setuid
307
- end
308
-
309
- # Returns nil if statfile is a zero-length file; otherwise, returns the
310
- # file size. Usable as a condition in tests.
311
- #
312
- def size?
313
- @size > 0 ? @size : nil
314
- end
315
-
316
- # Meaningless on Windows.
317
- #
318
- def sticky?
319
- @sticky
320
- end
321
-
322
- # Meaningless on Windows at the moment. This may change in the future.
323
- #
324
- def symlink?
325
- @symlink
326
- end
327
-
328
- # Meaningless on Windows.
329
- #
330
- def writable?
331
- @writable
332
- end
333
-
334
- # Meaningless on Windows.
335
- #
336
- def writable_real?
337
- @writable_real
338
- end
339
-
340
- # Returns whether or not the file size is zero.
341
- #
342
- def zero?
343
- @size == 0
344
- end
345
-
346
- ## Attribute members
347
-
348
- # Returns whether or not the file is an archive file.
349
- #
350
- def archive?
351
- @archive
352
- end
353
-
354
- # Returns whether or not the file is compressed.
355
- #
356
- def compressed?
357
- @compressed
358
- end
359
-
360
- # Returns whether or not the file is a directory.
361
- #
362
- def directory?
363
- @directory
364
- end
365
-
366
- # Returns whether or not the file in encrypted.
367
- #
368
- def encrypted?
369
- @encrypted
370
- end
371
-
372
- # Returns whether or not the file is hidden.
373
- #
374
- def hidden?
375
- @hidden
376
- end
377
-
378
- # Returns whether or not the file is content indexed.
379
- #
380
- def indexed?
381
- @indexed
382
- end
383
- alias :content_indexed? :indexed?
384
-
385
- # Returns whether or not the file is 'normal'. This is only true if
386
- # virtually all other attributes are false.
387
- #
388
- def normal?
389
- @normal
390
- end
391
-
392
- # Returns whether or not the file is offline.
393
- #
394
- def offline?
395
- @offline
396
- end
397
-
398
- # Returns whether or not the file is readonly.
399
- #
400
- def readonly?
401
- @readonly
402
- end
403
-
404
- alias :read_only? :readonly?
405
-
406
- # Returns whether or not the file is a reparse point.
407
- #
408
- def reparse_point?
409
- @reparse_point
410
- end
411
-
412
- # Returns whether or not the file is a sparse file. In most cases a sparse
413
- # file is an image file.
414
- #
415
- def sparse?
416
- @sparse
417
- end
418
-
419
- # Returns whether or not the file is a system file.
420
- #
421
- def system?
422
- @system
423
- end
424
-
425
- # Returns whether or not the file is being used for temporary storage.
426
- #
427
- def temporary?
428
- @temporary
429
- end
430
-
431
- ## Standard stat members
432
-
433
- # Returns a Time object containing the last access time.
434
- #
435
- def atime
436
- @atime
437
- end
438
-
439
- # Returns the file system's block size, or nil if it cannot be determined.
440
- #
441
- def blksize
442
- @blksize
443
- end
444
-
445
- # Returns the number of blocks used by the file, where a block is defined
446
- # as size divided by blksize, rounded up.
447
- #
448
- #--
449
- # This is a fudge. A search of the internet reveals different ways people
450
- # have defined st_blocks on MS Windows.
451
- #
452
- def blocks
453
- @blocks
454
- end
455
-
456
- # Returns a Time object containing the time that the file status associated
457
- # with the file was changed.
458
- #
459
- def ctime
460
- @ctime
461
- end
462
-
463
- # Drive letter (A-Z) of the disk containing the file. If the path is a
464
- # UNC path then the drive number (probably -1) is returned instead.
465
- #
466
- def dev
467
- if PathIsUNCW(@file)
468
- @dev
477
+ end
478
+ end
479
+
480
+ # Group ID. Always 0.
481
+ #
482
+ def gid
483
+ @gid
484
+ end
485
+
486
+ # Inode number. Meaningless on NTFS.
487
+ #
488
+ def ino
489
+ @ino
490
+ end
491
+
492
+ # Bit mask for file-mode information.
493
+ #
494
+ # :no-doc:
495
+ # This was taken from rb_win32_stat() in win32.c. I'm not entirely
496
+ # sure what the point is.
497
+ #
498
+ def mode
499
+ @mode &= ~(S_IWGRP | S_IWOTH)
500
+ end
501
+
502
+ # Returns a Time object containing the modification time.
503
+ #
504
+ def mtime
505
+ @mtime
506
+ end
507
+
508
+ # Drive number of the disk containing the file.
509
+ #
510
+ def rdev
511
+ @rdev
512
+ end
513
+
514
+ # Always 1
515
+ #
516
+ def nlink
517
+ @nlink
518
+ end
519
+
520
+ # Returns the size of the file, in bytes.
521
+ #
522
+ def size
523
+ @size
524
+ end
525
+
526
+ # User ID. Always 0.
527
+ #
528
+ def uid
529
+ @uid
530
+ end
531
+
532
+ # Returns a stringified version of a File::Stat object.
533
+ #
534
+ def inspect
535
+ members = %w[
536
+ archive? atime blksize blockdev? blocks compressed? ctime dev
537
+ encrypted? gid hidden? indexed? ino mode mtime rdev nlink normal?
538
+ offline? readonly? reparse_point? size sparse? system? temporary?
539
+ uid
540
+ ]
541
+
542
+ str = "#<#{self.class}"
543
+
544
+ members.sort.each{ |mem|
545
+ if mem == 'mode'
546
+ str << " #{mem}=" << sprintf("0%o", send(mem.intern))
547
+ elsif mem[-1].chr == '?'
548
+ str << " #{mem.chop}=" << send(mem.intern).to_s
469
549
  else
470
- (@dev + ?A).chr + ':'
550
+ str << " #{mem}=" << send(mem.intern).to_s
471
551
  end
472
- end
473
-
474
- # Group ID. Always 0.
475
- #
476
- def gid
477
- @gid
478
- end
479
-
480
- # Inode number. Meaningless on NTFS.
481
- #
482
- def ino
483
- @ino
484
- end
485
-
486
- # Bit mask for file-mode information.
487
- #
488
- # :no-doc:
489
- # This was taken from rb_win32_stat() in win32.c. I'm not entirely
490
- # sure what the point is.
491
- #
492
- def mode
493
- @mode &= ~(S_IWGRP | S_IWOTH)
494
- end
495
-
496
- # Returns a Time object containing the modification time.
497
- #
498
- def mtime
499
- @mtime
500
- end
501
-
502
- # Drive number of the disk containing the file.
503
- #
504
- def rdev
505
- @rdev
506
- end
507
-
508
- # Always 1
509
- #
510
- def nlink
511
- @nlink
512
- end
513
-
514
- # Returns the size of the file, in bytes.
515
- #
516
- def size
517
- @size
518
- end
519
-
520
- # User ID. Always 0.
521
- #
522
- def uid
523
- @uid
524
- end
525
-
526
- # Returns a stringified version of a File::Stat object.
527
- #
528
- def inspect
529
- members = %w/
530
- archive? atime blksize blockdev? blocks compressed? ctime dev
531
- encrypted? gid hidden? indexed? ino mode mtime rdev nlink normal?
532
- offline? readonly? reparse_point? size sparse? system? temporary?
533
- uid
534
- /
535
- str = "#<#{self.class}"
536
- members.sort.each{ |mem|
537
- if mem == 'mode'
538
- str << " #{mem}=" << sprintf("0%o", send(mem.intern))
539
- elsif mem[-1].chr == '?'
540
- str << " #{mem.chop}=" << send(mem.intern).to_s
541
- else
542
- str << " #{mem}=" << send(mem.intern).to_s
543
- end
544
- }
545
- str
546
- end
547
-
548
- # A custom pretty print method. This was necessary not only to handle
549
- # the additional attributes, but to work around an error caused by the
550
- # builtin method for the current File::Stat class (see pp.rb).
551
- #
552
- def pretty_print(q)
553
- members = %w/
554
- archive? atime blksize blockdev? blocks compressed? ctime dev
555
- encrypted? gid hidden? indexed? ino mode mtime rdev nlink normal?
556
- offline? readonly? reparse_point? size sparse? system? temporary?
557
- uid
558
- /
559
-
560
- q.object_group(self){
561
- q.breakable
562
- members.each{ |mem|
563
- q.group{
564
- q.text("#{mem}".ljust(15) + "=> ")
565
- if mem == 'mode'
566
- q.text(sprintf("0%o", send(mem.intern)))
567
- else
568
- val = self.send(mem.intern)
569
- if val.nil?
570
- q.text('nil')
571
- else
572
- q.text(val.to_s)
573
- end
574
- end
575
- }
576
- q.comma_breakable unless mem == members.last
577
- }
552
+ }
553
+
554
+ str
555
+ end
556
+
557
+ # A custom pretty print method. This was necessary not only to handle
558
+ # the additional attributes, but to work around an error caused by the
559
+ # builtin method for the current File::Stat class (see pp.rb).
560
+ #
561
+ def pretty_print(q)
562
+ members = %w[
563
+ archive? atime blksize blockdev? blocks compressed? ctime dev
564
+ encrypted? gid hidden? indexed? ino mode mtime rdev nlink normal?
565
+ offline? readonly? reparse_point? size sparse? system? temporary?
566
+ uid
567
+ ]
568
+
569
+ q.object_group(self){
570
+ q.breakable
571
+ members.each{ |mem|
572
+ q.group{
573
+ q.text("#{mem}".ljust(15) + "=> ")
574
+ if mem == 'mode'
575
+ q.text(sprintf("0%o", send(mem.intern)))
576
+ else
577
+ val = self.send(mem.intern)
578
+ if val.nil?
579
+ q.text('nil')
580
+ else
581
+ q.text(val.to_s)
582
+ end
583
+ end
584
+ }
585
+ q.comma_breakable unless mem == members.last
578
586
  }
579
- end
587
+ }
588
+ end
580
589
 
581
- # Since old_init was added strictly to avoid a warning, we remove it now.
582
- remove_method(:old_init)
590
+ # Since old_init was added strictly to avoid a warning, we remove it now.
591
+ remove_method(:old_init)
583
592
 
584
- private
593
+ private
585
594
 
586
- # Returns the file system's block size.
587
- #
588
- def get_blksize(file)
589
- size = nil
590
-
591
- sectors = [0].pack('L')
592
- bytes = [0].pack('L')
593
- free = [0].pack('L')
594
- total = [0].pack('L')
595
+ # Returns the file system's block size.
596
+ #
597
+ def get_blksize(file)
598
+ size = nil
599
+
600
+ sectors = [0].pack('L')
601
+ bytes = [0].pack('L')
602
+ free = [0].pack('L')
603
+ total = [0].pack('L')
595
604
 
596
- # If there's a drive letter it must contain a trailing backslash.
597
- # The dup is necessary here because the function modifies the argument.
598
- file = file.dup
605
+ # If there's a drive letter it must contain a trailing backslash.
606
+ # The dup is necessary here because the function modifies the argument.
607
+ file = file.dup
599
608
 
600
- if PathStripToRootA(wide_to_multi(file))
601
- file = file[/^[^\0]*/] << ':'
602
- file << "\\" unless file[-1].chr == "\\"
603
- else
604
- file = nil # Default to the root drive on relative paths
605
- end
609
+ if PathStripToRootA(wide_to_multi(file))
610
+ file = file[/^[^\0]*/] << ':'
611
+ file << "\\" unless file[-1].chr == "\\"
612
+ else
613
+ file = nil # Default to the root drive on relative paths
614
+ end
606
615
 
607
- # Don't check for an error here. Just default to nil.
608
- if GetDiskFreeSpaceA(file, sectors, bytes, free, total)
609
- size = sectors.unpack('L').first * bytes.unpack('L').first
610
- end
616
+ # Don't check for an error here. Just default to nil.
617
+ if GetDiskFreeSpaceA(file, sectors, bytes, free, total)
618
+ size = sectors.unpack('L').first * bytes.unpack('L').first
619
+ end
611
620
 
612
- size
613
- end
614
-
615
- # Private method to get a HANDLE when CreateFile() won't cut it.
616
- #
617
- def get_handle(file)
618
- file = file.upcase
619
-
620
- begin
621
- hdlTokenHandle = 0.chr * 4
622
-
623
- OpenProcessToken(
624
- GetCurrentProcess(),
625
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
626
- hdlTokenHandle
627
- )
628
-
629
- hdlTokenHandle = hdlTokenHandle.unpack('L').first
630
-
631
- # Get the LUID for shutdown privilege.
632
- tmpLuid = 0.chr * 8
633
- LookupPrivilegeValue("", "SeDebugPrivilege", tmpLuid)
634
- tkp = [1].pack('L') + tmpLuid + [SE_PRIVILEGE_ENABLED].pack('L')
635
-
636
- # Enable the shutdown privilege in the access token of this process.
637
- AdjustTokenPrivileges(hdlTokenHandle, 0,tkp, tkp.length , nil, nil)
638
- ensure
639
- CloseHandle(hdlTokenHandle)
640
- end
621
+ size
622
+ end
623
+
624
+ # Private method to get a HANDLE when CreateFile() won't cut it.
625
+ #
626
+ def get_handle(file)
627
+ file = file.upcase
628
+
629
+ begin
630
+ hdlTokenHandle = 0.chr * 4
631
+
632
+ OpenProcessToken(
633
+ GetCurrentProcess(),
634
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
635
+ hdlTokenHandle
636
+ )
637
+
638
+ hdlTokenHandle = hdlTokenHandle.unpack('L').first
639
+
640
+ # Get the LUID for shutdown privilege.
641
+ tmpLuid = 0.chr * 8
642
+ LookupPrivilegeValue("", "SeDebugPrivilege", tmpLuid)
643
+ tkp = [1].pack('L') + tmpLuid + [SE_PRIVILEGE_ENABLED].pack('L')
644
+
645
+ # Enable the shutdown privilege in the access token of this process.
646
+ AdjustTokenPrivileges(hdlTokenHandle, 0,tkp, tkp.length , nil, nil)
647
+ ensure
648
+ CloseHandle(hdlTokenHandle)
649
+ end
641
650
 
642
- # First call is to get the required length
643
- handle_info = 0.chr * 4096
644
- required = 0.chr * 4
645
- NtQuerySystemInformation(16, handle_info, 4096, required)
646
-
647
- # Second call is the actual call
648
- handle_info = 0.chr * required.unpack('L').first
649
- NtQuerySystemInformation(16, handle_info, handle_info.length, required)
650
-
651
- count = handle_info[0,4].unpack('L').first
652
-
653
- for i in 0...count
654
- pid, type, handle, addr, access = handle_info[4+i*16,16].unpack('LSSLL')
655
- if access & 0xffff == 3
656
- begin
657
- process = OpenProcess(0x40,1,pid)
658
- dup_handle = 0.chr * 4
659
-
660
- DuplicateHandle(
661
- process,
662
- handle,
663
- GetCurrentProcess(),
664
- dup_handle,
665
- 0,
666
- 1,
667
- 2
668
- )
669
- ensure
670
- CloseHandle(process)
671
- end
672
-
673
- handle = dup_handle.unpack('L').first
674
- buffer = 0.chr * 0x2000
675
- NtQueryObject(handle, 1, buffer, 0x2000, nil)
676
- len = buffer[0,2].unpack('S').first
677
-
678
- if len>0
679
- if buffer[8..-1].upcase[file]
680
- return handle
681
- end
682
- end
683
- CloseHandle(handle)
684
- end
685
- end
686
-
687
- return 0
688
- end
689
-
690
- # Returns the file's type (as a numeric).
691
- #
692
- def get_file_type(file)
693
- begin
694
- handle = CreateFileW(
695
- file,
696
- 0,
651
+ # First call is to get the required length
652
+ handle_info = 0.chr * 4096
653
+ required = 0.chr * 4
654
+ NtQuerySystemInformation(16, handle_info, 4096, required)
655
+
656
+ # Second call is the actual call
657
+ handle_info = 0.chr * required.unpack('L').first
658
+ NtQuerySystemInformation(16, handle_info, handle_info.length, required)
659
+
660
+ count = handle_info[0,4].unpack('L').first
661
+
662
+ for i in 0...count
663
+ pid, type, handle, addr, access = handle_info[4+i*16,16].unpack('LSSLL')
664
+ if access & 0xffff == 3
665
+ begin
666
+ process = OpenProcess(0x40,1,pid)
667
+ dup_handle = 0.chr * 4
668
+
669
+ DuplicateHandle(
670
+ process,
671
+ handle,
672
+ GetCurrentProcess(),
673
+ dup_handle,
697
674
  0,
698
- nil,
699
- OPEN_EXISTING,
700
- FILE_FLAG_BACKUP_SEMANTICS, # Need this for directories
701
- nil
702
- )
703
-
704
- error_num = GetLastError()
705
-
706
- # CreateFile() chokes on locked files
707
- if error_num == ERROR_SHARING_VIOLATION
708
- drive = file[0,4] + 0.chr * 2
709
- device = 0.chr * 512
710
- QueryDosDeviceW(drive, device, 256)
711
- file = device.strip + 0.chr + file[4..-1]
712
- handle = get_handle(file)
713
- end
714
-
715
- # We raise a SystemCallError explicitly here in order to maintain
716
- # compatibility with the FileUtils module.
717
- if handle == INVALID_HANDLE_VALUE
718
- raise SystemCallError, get_last_error(error_num)
719
- end
675
+ 1,
676
+ 2
677
+ )
678
+ ensure
679
+ CloseHandle(process)
680
+ end
681
+
682
+ handle = dup_handle.unpack('L').first
683
+ buffer = 0.chr * 0x2000
684
+ NtQueryObject(handle, 1, buffer, 0x2000, nil)
685
+ len = buffer[0,2].unpack('S').first
686
+
687
+ if len>0
688
+ if buffer[8..-1].upcase[file]
689
+ return handle
690
+ end
691
+ end
692
+ CloseHandle(handle)
693
+ end
694
+ end
695
+
696
+ return 0
697
+ end
698
+
699
+ # Returns the file's type (as a numeric).
700
+ #
701
+ def get_file_type(file)
702
+ begin
703
+ handle = CreateFileW(
704
+ file,
705
+ 0,
706
+ 0,
707
+ nil,
708
+ OPEN_EXISTING,
709
+ FILE_FLAG_BACKUP_SEMANTICS, # Need this for directories
710
+ nil
711
+ )
720
712
 
721
- file_type = GetFileType(handle)
722
- error_num = GetLastError()
723
- ensure
724
- CloseHandle(handle)
713
+ error_num = GetLastError()
714
+
715
+ # CreateFile() chokes on locked files
716
+ if error_num == ERROR_SHARING_VIOLATION
717
+ drive = file[0,4] + 0.chr * 2
718
+ device = 0.chr * 512
719
+ QueryDosDeviceW(drive, device, 256)
720
+ file = device.strip + 0.chr + file[4..-1]
721
+ handle = get_handle(file)
725
722
  end
726
723
 
727
- if file_type == FILE_TYPE_UNKNOWN && error_num != NO_ERROR
728
- raise SystemCallError, get_last_error(error_num)
724
+ # We raise a SystemCallError explicitly here in order to maintain
725
+ # compatibility with the FileUtils module.
726
+ if handle == INVALID_HANDLE_VALUE
727
+ raise SystemCallError, get_last_error(error_num)
729
728
  end
730
729
 
731
- file_type
732
- end
730
+ file_type = GetFileType(handle)
731
+ error_num = GetLastError()
732
+ ensure
733
+ CloseHandle(handle)
734
+ end
735
+
736
+ if file_type == FILE_TYPE_UNKNOWN && error_num != NO_ERROR
737
+ raise SystemCallError, get_last_error(error_num)
738
+ end
739
+
740
+ file_type
741
+ end
733
742
 
734
- private
743
+ private
735
744
 
736
- # Verifies that a value is either true or false
737
- def check_bool(val)
738
- raise TypeError unless val == true || val == false
739
- end
740
- end
745
+ # Verifies that a value is either true or false
746
+ def check_bool(val)
747
+ raise TypeError unless val == true || val == false
748
+ end
749
+ end