win32-file 0.5.6 → 0.6.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.
- data/CHANGES +11 -0
- data/lib/win32/file.rb +192 -89
- data/test/test_win32_file_attributes.rb +2 -2
- data/test/test_win32_file_path.rb +17 -17
- data/test/test_win32_file_stat.rb +1 -1
- data/win32-file.gemspec +5 -3
- metadata +24 -4
data/CHANGES
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
== 0.6.0 - 14-Nov-2008
|
|
2
|
+
* Converted methods to use wide character handling.
|
|
3
|
+
* Added working implementations for the File.readlink, File.symlink and
|
|
4
|
+
File.symlink? singleton methods. These require Windows Vista or later to
|
|
5
|
+
work properly. Otherwise, they follow current MRI behavior.
|
|
6
|
+
* To work properly in conjunction with win32-file-stat, a custom version
|
|
7
|
+
of the File.directory? method was implemented.
|
|
8
|
+
* Changed VERSION to WIN32_FILE_VERSION to be more consistent with other
|
|
9
|
+
Win32Utils libraries, and to avoid any potential conflicts with Ruby itself.
|
|
10
|
+
* Prerequisite updates.
|
|
11
|
+
|
|
1
12
|
== 0.5.6 - 30-Sep-2008
|
|
2
13
|
* The File.long_path and File.short_path methods now return the full path
|
|
3
14
|
instead of just the basename of the path. I really have no idea why I was
|
data/lib/win32/file.rb
CHANGED
|
@@ -16,9 +16,10 @@ class File
|
|
|
16
16
|
extend Windows::Security
|
|
17
17
|
extend Windows::MSVCRT::Buffer
|
|
18
18
|
extend Windows::Limits
|
|
19
|
+
extend Windows::Handle
|
|
19
20
|
|
|
20
21
|
# The version of the win32-file library
|
|
21
|
-
|
|
22
|
+
WIN32_FILE_VERSION = '0.6.0'
|
|
22
23
|
|
|
23
24
|
# Abbreviated attribute constants for convenience
|
|
24
25
|
|
|
@@ -58,11 +59,15 @@ class File
|
|
|
58
59
|
alias basename_orig basename
|
|
59
60
|
alias blockdev_orig blockdev?
|
|
60
61
|
alias chardev_orig chardev?
|
|
62
|
+
alias directory_orig? directory?
|
|
61
63
|
alias dirname_orig dirname
|
|
62
64
|
alias lstat_orig lstat
|
|
65
|
+
alias readlink_orig readlink
|
|
63
66
|
alias size_orig size
|
|
64
67
|
alias split_orig split
|
|
65
68
|
alias stat_orig stat
|
|
69
|
+
alias symlink_orig symlink
|
|
70
|
+
alias symlink_orig? symlink?
|
|
66
71
|
|
|
67
72
|
## Security
|
|
68
73
|
|
|
@@ -104,8 +109,11 @@ class File
|
|
|
104
109
|
# * GENERIC_ALL
|
|
105
110
|
#
|
|
106
111
|
def set_permissions(file, perms)
|
|
112
|
+
raise TypeError unless file.is_a?(String)
|
|
107
113
|
raise TypeError unless perms.kind_of?(Hash)
|
|
108
114
|
|
|
115
|
+
file = multi_to_wide(file)
|
|
116
|
+
|
|
109
117
|
account_rights = 0
|
|
110
118
|
sec_desc = 0.chr * SECURITY_DESCRIPTOR_MIN_LENGTH
|
|
111
119
|
|
|
@@ -211,7 +219,7 @@ class File
|
|
|
211
219
|
raise ArgumentError, get_last_error
|
|
212
220
|
end
|
|
213
221
|
|
|
214
|
-
unless
|
|
222
|
+
unless SetFileSecurityW(file, DACL_SECURITY_INFORMATION, sec_desc)
|
|
215
223
|
raise ArgumentError, get_last_error
|
|
216
224
|
end
|
|
217
225
|
|
|
@@ -253,8 +261,8 @@ class File
|
|
|
253
261
|
sec_buf = ''
|
|
254
262
|
|
|
255
263
|
loop do
|
|
256
|
-
bool =
|
|
257
|
-
file,
|
|
264
|
+
bool = GetFileSecurityW(
|
|
265
|
+
multi_to_wide(file),
|
|
258
266
|
DACL_SECURITY_INFORMATION,
|
|
259
267
|
sec_buf,
|
|
260
268
|
sec_buf.length,
|
|
@@ -366,7 +374,7 @@ class File
|
|
|
366
374
|
# Windows 2000 or later only.
|
|
367
375
|
#
|
|
368
376
|
def encrypt(file)
|
|
369
|
-
unless
|
|
377
|
+
unless EncryptFileW(multi_to_wide(file))
|
|
370
378
|
raise ArgumentError, get_last_error
|
|
371
379
|
end
|
|
372
380
|
self
|
|
@@ -385,7 +393,7 @@ class File
|
|
|
385
393
|
# Windows 2000 or later only.
|
|
386
394
|
#
|
|
387
395
|
def decrypt(file)
|
|
388
|
-
unless
|
|
396
|
+
unless DecryptFileW(multi_to_wide(file), 0)
|
|
389
397
|
raise ArgumentError, get_last_error
|
|
390
398
|
end
|
|
391
399
|
self
|
|
@@ -401,6 +409,9 @@ class File
|
|
|
401
409
|
# paths properly, i.e. it should not return anything less than the root.
|
|
402
410
|
# In all other respects it is identical to the current implementation.
|
|
403
411
|
#
|
|
412
|
+
# Unlike MRI, this version will convert all forward slashes to
|
|
413
|
+
# backslashes automatically.
|
|
414
|
+
#
|
|
404
415
|
# Examples:
|
|
405
416
|
#
|
|
406
417
|
# File.basename("C:\\foo\\bar.txt") -> "bar.txt"
|
|
@@ -408,49 +419,45 @@ class File
|
|
|
408
419
|
# File.basename("\\\\foo\\bar") -> "\\\\foo\\bar"
|
|
409
420
|
#
|
|
410
421
|
def basename(file, suffix = nil)
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
422
|
+
raise TypeError unless file.is_a?(String)
|
|
423
|
+
raise TypeError unless suffix.is_a?(String) if suffix
|
|
424
|
+
|
|
425
|
+
return file if file.empty? # Return an empty path as-is.
|
|
426
|
+
file = multi_to_wide(file)
|
|
427
|
+
|
|
428
|
+
# Required for Windows API functions to work properly.
|
|
429
|
+
file.tr!(File::SEPARATOR, File::ALT_SEPARATOR)
|
|
430
|
+
|
|
431
|
+
# Return a root path as-is.
|
|
432
|
+
return wide_to_multi(file) if PathIsRootW(file)
|
|
420
433
|
|
|
421
|
-
#
|
|
422
|
-
if file.empty? || PathIsRoot(file)
|
|
423
|
-
file.tr!("\\", '/') if fpath
|
|
424
|
-
return file
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
PathStripPath(file) # Gives us the basename
|
|
434
|
+
PathStripPathW(file) # Gives us the basename
|
|
428
435
|
|
|
429
436
|
if suffix
|
|
430
437
|
if suffix == '.*'
|
|
431
|
-
|
|
438
|
+
PathRemoveExtensionW(file)
|
|
432
439
|
else
|
|
433
|
-
if
|
|
434
|
-
|
|
440
|
+
if PathFindExtensionA(wide_to_multi(file)) == suffix
|
|
441
|
+
PathRemoveExtensionW(file)
|
|
435
442
|
end
|
|
436
443
|
end
|
|
437
444
|
end
|
|
438
|
-
|
|
439
|
-
file = file
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
while file[-1].chr == "\\"
|
|
443
|
-
file.chop!
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
# Return forward slashes if that's how the path was passed in.
|
|
447
|
-
if fpath
|
|
448
|
-
file.tr!("\\", '/')
|
|
449
|
-
end
|
|
450
|
-
|
|
445
|
+
|
|
446
|
+
file = wide_to_multi(file)
|
|
447
|
+
file.chop! while file[-1].chr == "\\" # Trim trailing slashes
|
|
448
|
+
|
|
451
449
|
file
|
|
452
450
|
end
|
|
453
451
|
|
|
452
|
+
# Returns true if +file+ is a directory, false otherwise.
|
|
453
|
+
#--
|
|
454
|
+
# This method was redefined to handle wide character strings.
|
|
455
|
+
#
|
|
456
|
+
def directory?(file)
|
|
457
|
+
file = multi_to_wide(file)
|
|
458
|
+
GetFileAttributesW(file) & FILE_ATTRIBUTE_DIRECTORY > 0
|
|
459
|
+
end
|
|
460
|
+
|
|
454
461
|
# Returns all components of the filename given in +filename+ except the
|
|
455
462
|
# last one.
|
|
456
463
|
#
|
|
@@ -458,36 +465,33 @@ class File
|
|
|
458
465
|
# paths properly, i.e. it should not return anything less than the root.
|
|
459
466
|
# In all other respects it is identical to the current implementation.
|
|
460
467
|
#
|
|
468
|
+
# Also, this method will convert all forward slashes to backslashes.
|
|
469
|
+
#
|
|
461
470
|
# Examples:
|
|
462
471
|
#
|
|
463
472
|
# File.dirname("C:\\foo\\bar\\baz.txt") -> "C:\\foo\\bar"
|
|
464
473
|
# File.dirname("\\\\foo\\bar") -> "\\\\foo\\bar"
|
|
465
474
|
#
|
|
466
|
-
def dirname(file)
|
|
467
|
-
|
|
468
|
-
file = file
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
fpath = true
|
|
473
|
-
end
|
|
475
|
+
def dirname(file)
|
|
476
|
+
raise TypeError unless file.is_a?(String)
|
|
477
|
+
file = multi_to_wide(file)
|
|
478
|
+
|
|
479
|
+
# Convert slashes to backslashes for the Windows API functions
|
|
480
|
+
file.tr!(File::SEPARATOR, File::ALT_SEPARATOR)
|
|
474
481
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
return file
|
|
478
|
-
end
|
|
482
|
+
# Return a root path as-is.
|
|
483
|
+
return wide_to_multi(file) if PathIsRootW(file)
|
|
479
484
|
|
|
480
|
-
|
|
481
|
-
file
|
|
485
|
+
# Remove trailing file name and backslash, if present
|
|
486
|
+
PathRemoveFileSpecW(file)
|
|
487
|
+
|
|
488
|
+
file = wide_to_multi(file)
|
|
482
489
|
|
|
483
490
|
# Empty paths, short relative paths
|
|
484
491
|
if file.nil? || (file && file.empty?)
|
|
485
492
|
return '.'
|
|
486
493
|
end
|
|
487
494
|
|
|
488
|
-
PathRemoveBackslash(file)
|
|
489
|
-
|
|
490
|
-
file.tr!("\\", '/') if fpath
|
|
491
495
|
file
|
|
492
496
|
end
|
|
493
497
|
|
|
@@ -501,10 +505,48 @@ class File
|
|
|
501
505
|
#
|
|
502
506
|
def long_path(path)
|
|
503
507
|
buf = 0.chr * MAXPATH
|
|
504
|
-
if
|
|
508
|
+
if GetLongPathNameW(multi_to_wide(path), buf, buf.size) == 0
|
|
505
509
|
raise ArgumentError, get_last_error
|
|
506
510
|
end
|
|
507
|
-
buf
|
|
511
|
+
wide_to_multi(buf)
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
# Returns the path of the of the symbolic link referred to by +file+.
|
|
515
|
+
#
|
|
516
|
+
# Requires Windows Vista or later. On older versions of Windows it
|
|
517
|
+
# will raise a NotImplementedError, as per MRI.
|
|
518
|
+
#
|
|
519
|
+
def readlink(file)
|
|
520
|
+
if defined? GetFinalPathNameByHandle
|
|
521
|
+
file = multi_to_wide(file)
|
|
522
|
+
|
|
523
|
+
begin
|
|
524
|
+
handle = CreateFileW(
|
|
525
|
+
file,
|
|
526
|
+
GENERIC_READ,
|
|
527
|
+
FILE_SHARE_READ,
|
|
528
|
+
nil,
|
|
529
|
+
OPEN_EXISTING,
|
|
530
|
+
FILE_ATTRIBUTE_NORMAL,
|
|
531
|
+
nil
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
if handle == INVALID_HANDLE_VALUE
|
|
535
|
+
raise ArgumentError, get_last_error
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
path = 0.chr * MAXPATH
|
|
539
|
+
|
|
540
|
+
GetFinalPathNameByHandleW(handle, path, path.size, 0)
|
|
541
|
+
ensure
|
|
542
|
+
CloseHandle(handle)
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
wide_to_multi(path).strip[4..-1] # get rid of prepending "\\?\"
|
|
546
|
+
else
|
|
547
|
+
msg = "readlink() function is unimplemented on this machine"
|
|
548
|
+
raise NotImplementedError, msg
|
|
549
|
+
end
|
|
508
550
|
end
|
|
509
551
|
|
|
510
552
|
# Returns +path+ in 8.3 format. For example, 'c:\documentation.doc'
|
|
@@ -512,10 +554,10 @@ class File
|
|
|
512
554
|
#
|
|
513
555
|
def short_path(path)
|
|
514
556
|
buf = 0.chr * MAXPATH
|
|
515
|
-
if
|
|
557
|
+
if GetShortPathNameW(multi_to_wide(path), buf, buf.size) == 0
|
|
516
558
|
raise ArgumentError, get_last_error
|
|
517
559
|
end
|
|
518
|
-
buf
|
|
560
|
+
wide_to_multi(buf)
|
|
519
561
|
end
|
|
520
562
|
|
|
521
563
|
# Splits the given string into a directory and a file component and
|
|
@@ -525,7 +567,7 @@ class File
|
|
|
525
567
|
def split(file)
|
|
526
568
|
array = []
|
|
527
569
|
|
|
528
|
-
if file.empty? ||
|
|
570
|
+
if file.empty? || PathIsRootW(multi_to_wide(file))
|
|
529
571
|
array.push(file, '')
|
|
530
572
|
else
|
|
531
573
|
array.push(File.dirname(file), File.basename(file))
|
|
@@ -533,6 +575,57 @@ class File
|
|
|
533
575
|
array
|
|
534
576
|
end
|
|
535
577
|
|
|
578
|
+
# Creates a symbolic link called +new_name+ for the file or directory
|
|
579
|
+
# +old_name+.
|
|
580
|
+
#
|
|
581
|
+
# This method requires Windows Vista or later to work. Otherwise, it
|
|
582
|
+
# returns nil as per MRI.
|
|
583
|
+
#
|
|
584
|
+
def symlink(old_name, new_name)
|
|
585
|
+
if defined? CreateSymbolicLink
|
|
586
|
+
old_name = multi_to_wide(old_name)
|
|
587
|
+
new_name = multi_to_wide(new_name)
|
|
588
|
+
flags = File.directory?(wide_to_multi(old_name)) ? 1 : 0
|
|
589
|
+
|
|
590
|
+
unless CreateSymbolicLinkW(new_name, old_name, flags)
|
|
591
|
+
raise ArgumentError, get_last_error
|
|
592
|
+
end
|
|
593
|
+
else
|
|
594
|
+
nil
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
# Return true if the named file is a symbolic link, false otherwise.
|
|
599
|
+
#
|
|
600
|
+
# This method requires Windows Vista or later to work. Otherwise, it
|
|
601
|
+
# always returns false as per MRI.
|
|
602
|
+
#
|
|
603
|
+
def symlink?(file)
|
|
604
|
+
bool = false
|
|
605
|
+
file = multi_to_wide(file)
|
|
606
|
+
attr = GetFileAttributesW(file)
|
|
607
|
+
|
|
608
|
+
# Differentiate between a symlink and other kinds of reparse points
|
|
609
|
+
if attr & FILE_ATTRIBUTE_REPARSE_POINT > 0
|
|
610
|
+
begin
|
|
611
|
+
buffer = 0.chr * 278 # WIN32_FIND_DATA
|
|
612
|
+
handle = FindFirstFileW(file, buffer)
|
|
613
|
+
|
|
614
|
+
if handle == INVALID_HANDLE_VALUE
|
|
615
|
+
raise ArgumentError, get_last_error
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
if buffer[36,4].unpack('L')[0] == IO_REPARSE_TAG_SYMLINK
|
|
619
|
+
bool = true
|
|
620
|
+
end
|
|
621
|
+
ensure
|
|
622
|
+
CloseHandle(handle)
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
bool
|
|
627
|
+
end
|
|
628
|
+
|
|
536
629
|
## Stat methods
|
|
537
630
|
|
|
538
631
|
# Returns a File::Stat object, as defined in the win32-file-stat package.
|
|
@@ -578,8 +671,9 @@ class File
|
|
|
578
671
|
|
|
579
672
|
# We no longer need the aliases, so remove them
|
|
580
673
|
remove_method(:basename_orig, :blockdev_orig, :chardev_orig)
|
|
581
|
-
remove_method(:dirname_orig, :lstat_orig, :size_orig)
|
|
582
|
-
remove_method(:
|
|
674
|
+
remove_method(:dirname_orig, :lstat_orig, :size_orig, :split_orig)
|
|
675
|
+
remove_method(:stat_orig, :symlink_orig, :symlink_orig?, :readlink_orig)
|
|
676
|
+
remove_method(:directory_orig?)
|
|
583
677
|
end # class << self
|
|
584
678
|
|
|
585
679
|
## Attribute methods
|
|
@@ -646,8 +740,6 @@ class File
|
|
|
646
740
|
def self.readonly?(file)
|
|
647
741
|
File::Stat.new(file).readonly?
|
|
648
742
|
end
|
|
649
|
-
|
|
650
|
-
|
|
651
743
|
|
|
652
744
|
# Returns true if the file or directory has an associated reparse point. A
|
|
653
745
|
# reparse point is a collection of user defined data associated with a file
|
|
@@ -703,7 +795,8 @@ class File
|
|
|
703
795
|
# temporary
|
|
704
796
|
#
|
|
705
797
|
def self.attributes(file)
|
|
706
|
-
|
|
798
|
+
file = multi_to_wide(file)
|
|
799
|
+
attributes = GetFileAttributesW(file)
|
|
707
800
|
arr = []
|
|
708
801
|
|
|
709
802
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
@@ -731,7 +824,8 @@ class File
|
|
|
731
824
|
# not remove existing attributes, it merely adds to them.
|
|
732
825
|
#
|
|
733
826
|
def self.set_attributes(file, flags)
|
|
734
|
-
|
|
827
|
+
file = multi_to_wide(file)
|
|
828
|
+
attributes = GetFileAttributesW(file)
|
|
735
829
|
|
|
736
830
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
737
831
|
raise ArgumentError, get_last_error
|
|
@@ -739,7 +833,7 @@ class File
|
|
|
739
833
|
|
|
740
834
|
attributes |= flags
|
|
741
835
|
|
|
742
|
-
if
|
|
836
|
+
if SetFileAttributesW(file, attributes) == 0
|
|
743
837
|
raise ArgumentError, get_last_error
|
|
744
838
|
end
|
|
745
839
|
|
|
@@ -749,7 +843,8 @@ class File
|
|
|
749
843
|
# Removes the file attributes based on the given (numeric) +flags+.
|
|
750
844
|
#
|
|
751
845
|
def self.remove_attributes(file, flags)
|
|
752
|
-
|
|
846
|
+
file = multi_to_wide(file)
|
|
847
|
+
attributes = GetFileAttributesW(file)
|
|
753
848
|
|
|
754
849
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
755
850
|
raise ArgumentError, get_last_error
|
|
@@ -757,7 +852,7 @@ class File
|
|
|
757
852
|
|
|
758
853
|
attributes &= ~flags
|
|
759
854
|
|
|
760
|
-
if
|
|
855
|
+
if SetFileAttributesW(file, attributes) == 0
|
|
761
856
|
raise ArgumentError, get_last_error
|
|
762
857
|
end
|
|
763
858
|
|
|
@@ -773,7 +868,8 @@ class File
|
|
|
773
868
|
# Sets whether or not the file is an archive file.
|
|
774
869
|
#
|
|
775
870
|
def archive=(bool)
|
|
776
|
-
|
|
871
|
+
wide_path = multi_to_wide(self.path)
|
|
872
|
+
attributes = GetFileAttributesW(wide_path)
|
|
777
873
|
|
|
778
874
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
779
875
|
raise ArgumentError, get_last_error
|
|
@@ -785,7 +881,7 @@ class File
|
|
|
785
881
|
attributes &= ~FILE_ATTRIBUTE_ARCHIVE;
|
|
786
882
|
end
|
|
787
883
|
|
|
788
|
-
if
|
|
884
|
+
if SetFileAttributesW(wide_path, attributes) == 0
|
|
789
885
|
raise ArgumentError, get_last_error
|
|
790
886
|
end
|
|
791
887
|
|
|
@@ -800,8 +896,8 @@ class File
|
|
|
800
896
|
bytes = [0].pack('L')
|
|
801
897
|
|
|
802
898
|
# We can't use get_osfhandle here because we need specific attributes
|
|
803
|
-
handle =
|
|
804
|
-
self.path,
|
|
899
|
+
handle = CreateFileW(
|
|
900
|
+
multi_to_wide(self.path),
|
|
805
901
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
|
806
902
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
807
903
|
0,
|
|
@@ -840,7 +936,8 @@ class File
|
|
|
840
936
|
# true means that the file is not included in an ordinary directory listing.
|
|
841
937
|
#
|
|
842
938
|
def hidden=(bool)
|
|
843
|
-
|
|
939
|
+
wide_path = multi_to_wide(self.path)
|
|
940
|
+
attributes = GetFileAttributesW(wide_path)
|
|
844
941
|
|
|
845
942
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
846
943
|
raise ArgumentError, get_last_error
|
|
@@ -852,9 +949,10 @@ class File
|
|
|
852
949
|
attributes &= ~FILE_ATTRIBUTE_HIDDEN;
|
|
853
950
|
end
|
|
854
951
|
|
|
855
|
-
if
|
|
952
|
+
if SetFileAttributesW(wide_path, attributes) == 0
|
|
856
953
|
raise ArgumentError, get_last_error
|
|
857
954
|
end
|
|
955
|
+
|
|
858
956
|
self
|
|
859
957
|
end
|
|
860
958
|
|
|
@@ -863,7 +961,8 @@ class File
|
|
|
863
961
|
# service.
|
|
864
962
|
#
|
|
865
963
|
def indexed=(bool)
|
|
866
|
-
|
|
964
|
+
wide_path = multi_to_wide(self.path)
|
|
965
|
+
attributes = GetFileAttributesW(wide_path)
|
|
867
966
|
|
|
868
967
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
869
968
|
raise ArgumentError, get_last_error
|
|
@@ -875,7 +974,7 @@ class File
|
|
|
875
974
|
attributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
|
|
876
975
|
end
|
|
877
976
|
|
|
878
|
-
if SetFileAttributes(
|
|
977
|
+
if SetFileAttributes(wide_path, attributes) == 0
|
|
879
978
|
raise ArgumentError, get_last_error
|
|
880
979
|
end
|
|
881
980
|
|
|
@@ -884,7 +983,7 @@ class File
|
|
|
884
983
|
|
|
885
984
|
alias :content_indexed= :indexed=
|
|
886
985
|
|
|
887
|
-
# Sets the normal attribute.
|
|
986
|
+
# Sets the normal attribute. Note that only 'true' is a valid argument,
|
|
888
987
|
# which has the effect of removing most other attributes. Attempting to
|
|
889
988
|
# pass any value except true will raise an ArgumentError.
|
|
890
989
|
#
|
|
@@ -893,7 +992,7 @@ class File
|
|
|
893
992
|
raise ArgumentError, "only 'true' may be passed as an argument"
|
|
894
993
|
end
|
|
895
994
|
|
|
896
|
-
if
|
|
995
|
+
if SetFileAttributesW(multi_to_wide(self.path),FILE_ATTRIBUTE_NORMAL) == 0
|
|
897
996
|
raise ArgumentError, get_last_error
|
|
898
997
|
end
|
|
899
998
|
|
|
@@ -909,7 +1008,8 @@ class File
|
|
|
909
1008
|
# Applications should not arbitrarily change this attribute.
|
|
910
1009
|
#
|
|
911
1010
|
def offline=(bool)
|
|
912
|
-
|
|
1011
|
+
wide_path = multi_to_wide(self.path)
|
|
1012
|
+
attributes = GetFileAttributesW(wide_path)
|
|
913
1013
|
|
|
914
1014
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
915
1015
|
raise ArgumentError, get_last_error
|
|
@@ -921,7 +1021,7 @@ class File
|
|
|
921
1021
|
attributes &= ~FILE_ATTRIBUTE_OFFLINE;
|
|
922
1022
|
end
|
|
923
1023
|
|
|
924
|
-
if
|
|
1024
|
+
if SetFileAttributesW(wide_path, attributes) == 0
|
|
925
1025
|
raise ArgumentError, get_last_error
|
|
926
1026
|
end
|
|
927
1027
|
|
|
@@ -933,7 +1033,8 @@ class File
|
|
|
933
1033
|
# it. In the case of a directory, applications cannot delete it.
|
|
934
1034
|
#
|
|
935
1035
|
def readonly=(bool)
|
|
936
|
-
|
|
1036
|
+
wide_path = multi_to_wide(self.path)
|
|
1037
|
+
attributes = GetFileAttributesW(wide_path)
|
|
937
1038
|
|
|
938
1039
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
939
1040
|
raise ArgumentError, get_last_error
|
|
@@ -945,7 +1046,7 @@ class File
|
|
|
945
1046
|
attributes &= ~FILE_ATTRIBUTE_READONLY;
|
|
946
1047
|
end
|
|
947
1048
|
|
|
948
|
-
if
|
|
1049
|
+
if SetFileAttributesW(wide_path, attributes) == 0
|
|
949
1050
|
raise ArgumentError, get_last_error
|
|
950
1051
|
end
|
|
951
1052
|
|
|
@@ -963,8 +1064,8 @@ class File
|
|
|
963
1064
|
|
|
964
1065
|
bytes = [0].pack('L')
|
|
965
1066
|
|
|
966
|
-
handle =
|
|
967
|
-
self.path,
|
|
1067
|
+
handle = CreateFileW(
|
|
1068
|
+
multi_to_wide(self.path),
|
|
968
1069
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
|
969
1070
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
970
1071
|
0,
|
|
@@ -1003,7 +1104,8 @@ class File
|
|
|
1003
1104
|
# that is part of the operating system or is used exclusively by it.
|
|
1004
1105
|
#
|
|
1005
1106
|
def system=(bool)
|
|
1006
|
-
|
|
1107
|
+
wide_path = multi_to_wide(self.path)
|
|
1108
|
+
attributes = GetFileAttributesW(wide_path)
|
|
1007
1109
|
|
|
1008
1110
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
1009
1111
|
raise ArgumentError, get_last_error
|
|
@@ -1015,7 +1117,7 @@ class File
|
|
|
1015
1117
|
attributes &= ~FILE_ATTRIBUTE_SYSTEM;
|
|
1016
1118
|
end
|
|
1017
1119
|
|
|
1018
|
-
if
|
|
1120
|
+
if SetFileAttributesW(wide_path, attributes) == 0
|
|
1019
1121
|
raise ArgumentError, get_last_error
|
|
1020
1122
|
end
|
|
1021
1123
|
|
|
@@ -1031,7 +1133,8 @@ class File
|
|
|
1031
1133
|
# after the handle is closed.
|
|
1032
1134
|
#
|
|
1033
1135
|
def temporary=(bool)
|
|
1034
|
-
|
|
1136
|
+
wide_path = multi_to_wide(self.path)
|
|
1137
|
+
attributes = GetFileAttributesW(wide_path)
|
|
1035
1138
|
|
|
1036
1139
|
if attributes == INVALID_FILE_ATTRIBUTES
|
|
1037
1140
|
raise ArgumentError, get_last_error
|
|
@@ -1043,7 +1146,7 @@ class File
|
|
|
1043
1146
|
attributes &= ~FILE_ATTRIBUTE_TEMPORARY;
|
|
1044
1147
|
end
|
|
1045
1148
|
|
|
1046
|
-
if
|
|
1149
|
+
if SetFileAttributesW(wide_path, attributes) == 0
|
|
1047
1150
|
raise ArgumentError, get_last_error
|
|
1048
1151
|
end
|
|
1049
1152
|
|
|
@@ -26,7 +26,7 @@ class TC_Win32_File_Attributes < Test::Unit::TestCase
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def test_version
|
|
29
|
-
assert_equal('0.
|
|
29
|
+
assert_equal('0.6.0', File::WIN32_FILE_VERSION)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def test_temporary
|
|
@@ -268,7 +268,7 @@ class TC_Win32_File_Attributes < Test::Unit::TestCase
|
|
|
268
268
|
end
|
|
269
269
|
|
|
270
270
|
def teardown
|
|
271
|
-
|
|
271
|
+
SetFileAttributesA(@@file, @attr)
|
|
272
272
|
@fh.close
|
|
273
273
|
end
|
|
274
274
|
|
|
@@ -12,7 +12,7 @@ require 'win32/file'
|
|
|
12
12
|
|
|
13
13
|
class TC_Win32_File_Path < Test::Unit::TestCase
|
|
14
14
|
def self.startup
|
|
15
|
-
Dir.chdir('test') unless File.basename(Dir.pwd) == 'test'
|
|
15
|
+
Dir.chdir('test') rescue nil #unless File.basename(Dir.pwd) == 'test'
|
|
16
16
|
@@file = File.join(Dir.pwd, 'path_test.txt')
|
|
17
17
|
File.open(@@file, 'w'){ |fh| fh.puts "This is a path test." }
|
|
18
18
|
end
|
|
@@ -52,16 +52,16 @@ class TC_Win32_File_Path < Test::Unit::TestCase
|
|
|
52
52
|
assert_equal("bar", File.basename("/bar"))
|
|
53
53
|
assert_equal("bar", File.basename("/bar/"))
|
|
54
54
|
assert_equal("baz", File.basename("//foo/bar/baz"))
|
|
55
|
-
assert_equal("
|
|
56
|
-
assert_equal("
|
|
55
|
+
assert_equal("\\\\foo", File.basename("//foo"))
|
|
56
|
+
assert_equal("\\\\foo\\bar", File.basename("//foo/bar"))
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def test_basename_with_forward_slashes
|
|
60
60
|
assert_equal("bar", File.basename("C:/foo/bar"))
|
|
61
61
|
assert_equal("bar", File.basename("C:/foo/bar/"))
|
|
62
62
|
assert_equal("foo", File.basename("C:/foo"))
|
|
63
|
-
assert_equal("C
|
|
64
|
-
assert_equal("bar", File.basename("C:/foo/bar
|
|
63
|
+
assert_equal("C:\\", File.basename("C:/"))
|
|
64
|
+
assert_equal("bar", File.basename("C:/foo/bar//"))
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def test_basename_edge_cases
|
|
@@ -109,16 +109,16 @@ class TC_Win32_File_Path < Test::Unit::TestCase
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
def test_dirname_forward_slashes
|
|
112
|
-
assert_equal("C
|
|
113
|
-
assert_equal("C
|
|
114
|
-
assert_equal("C
|
|
115
|
-
assert_equal("C
|
|
116
|
-
assert_equal("
|
|
117
|
-
assert_equal("
|
|
118
|
-
assert_equal("
|
|
119
|
-
assert_equal("
|
|
112
|
+
assert_equal("C:\\foo", File.dirname("C:/foo/bar.txt"))
|
|
113
|
+
assert_equal("C:\\foo", File.dirname("C:/foo/bar"))
|
|
114
|
+
assert_equal("C:\\", File.dirname("C:/foo"))
|
|
115
|
+
assert_equal("C:\\", File.dirname("C:/"))
|
|
116
|
+
assert_equal("\\\\foo\\bar", File.dirname("//foo/bar/baz"))
|
|
117
|
+
assert_equal("\\\\foo\\bar", File.dirname("//foo/bar"))
|
|
118
|
+
assert_equal("\\\\foo", File.dirname("//foo"))
|
|
119
|
+
assert_equal("\\\\", File.dirname("//"))
|
|
120
120
|
assert_equal(".", File.dirname("./foo"))
|
|
121
|
-
assert_equal("
|
|
121
|
+
assert_equal(".\\foo", File.dirname("./foo/bar"))
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
def test_dirname_edge_cases
|
|
@@ -147,13 +147,13 @@ class TC_Win32_File_Path < Test::Unit::TestCase
|
|
|
147
147
|
end
|
|
148
148
|
|
|
149
149
|
def test_split_forward_slashes
|
|
150
|
-
assert_equal(["C
|
|
150
|
+
assert_equal(["C:\\foo", "bar"], File.split("C:/foo/bar"))
|
|
151
151
|
assert_equal([".", "foo"], File.split("foo"))
|
|
152
152
|
end
|
|
153
153
|
|
|
154
154
|
def test_split_unix_paths
|
|
155
|
-
assert_equal(["
|
|
156
|
-
assert_equal(["
|
|
155
|
+
assert_equal(["\\foo","bar"], File.split("/foo/bar"))
|
|
156
|
+
assert_equal(["\\", "foo"], File.split("/foo"))
|
|
157
157
|
assert_equal([".", "foo"], File.split("foo"))
|
|
158
158
|
end
|
|
159
159
|
|
|
@@ -55,7 +55,7 @@ class TC_Win32_File_Stat < Test::Unit::TestCase
|
|
|
55
55
|
assert_nothing_raised{ File.blockdev?("C:\\") }
|
|
56
56
|
assert_equal(false, File.blockdev?("NUL"))
|
|
57
57
|
|
|
58
|
-
omit_unless(File.exists?(
|
|
58
|
+
omit_unless(File.exists?(@@block_dev), "No media in device - skipping")
|
|
59
59
|
assert_equal(true, File.blockdev?(@@block_dev))
|
|
60
60
|
end
|
|
61
61
|
|
data/win32-file.gemspec
CHANGED
|
@@ -2,7 +2,7 @@ require "rubygems"
|
|
|
2
2
|
|
|
3
3
|
spec = Gem::Specification.new do |gem|
|
|
4
4
|
gem.name = "win32-file"
|
|
5
|
-
gem.version = "0.
|
|
5
|
+
gem.version = "0.6.0"
|
|
6
6
|
gem.authors = ["Daniel J. Berger", "Park Heesob"]
|
|
7
7
|
gem.email = "djberg96@gmail.com"
|
|
8
8
|
gem.homepage = "http://www.rubyforge.org/projects/win32utils"
|
|
@@ -15,12 +15,14 @@ spec = Gem::Specification.new do |gem|
|
|
|
15
15
|
gem.files.reject! { |fn| fn.include? "CVS" }
|
|
16
16
|
gem.require_path = "lib"
|
|
17
17
|
gem.extra_rdoc_files = ["README", "CHANGES"]
|
|
18
|
-
gem.add_dependency("win32-
|
|
18
|
+
gem.add_dependency("win32-api", ">= 1.2.1")
|
|
19
|
+
gem.add_dependency("win32-file-stat", ">= 1.3.2")
|
|
19
20
|
gem.add_dependency("test-unit", ">= 2.0.0")
|
|
21
|
+
gem.add_dependency("windows-pr", ">= 0.9.6")
|
|
20
22
|
gem.rubyforge_project = "win32utils"
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
if $0 == __FILE__
|
|
24
|
-
Gem.manage_gems
|
|
26
|
+
Gem.manage_gems if Gem::RubyGemsVersion.to_f < 1.3
|
|
25
27
|
Gem::Builder.new(spec).build
|
|
26
28
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: win32-file
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel J. Berger
|
|
@@ -10,9 +10,19 @@ autorequire:
|
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
12
|
|
|
13
|
-
date: 2008-
|
|
13
|
+
date: 2008-11-14 00:00:00 -07:00
|
|
14
14
|
default_executable:
|
|
15
15
|
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: win32-api
|
|
18
|
+
type: :runtime
|
|
19
|
+
version_requirement:
|
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
21
|
+
requirements:
|
|
22
|
+
- - ">="
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: 1.2.1
|
|
25
|
+
version:
|
|
16
26
|
- !ruby/object:Gem::Dependency
|
|
17
27
|
name: win32-file-stat
|
|
18
28
|
type: :runtime
|
|
@@ -21,7 +31,7 @@ dependencies:
|
|
|
21
31
|
requirements:
|
|
22
32
|
- - ">="
|
|
23
33
|
- !ruby/object:Gem::Version
|
|
24
|
-
version: 1.2
|
|
34
|
+
version: 1.3.2
|
|
25
35
|
version:
|
|
26
36
|
- !ruby/object:Gem::Dependency
|
|
27
37
|
name: test-unit
|
|
@@ -33,6 +43,16 @@ dependencies:
|
|
|
33
43
|
- !ruby/object:Gem::Version
|
|
34
44
|
version: 2.0.0
|
|
35
45
|
version:
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: windows-pr
|
|
48
|
+
type: :runtime
|
|
49
|
+
version_requirement:
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.9.6
|
|
55
|
+
version:
|
|
36
56
|
description: Extra or redefined methods for the File class on Windows.
|
|
37
57
|
email: djberg96@gmail.com
|
|
38
58
|
executables: []
|
|
@@ -79,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
79
99
|
requirements: []
|
|
80
100
|
|
|
81
101
|
rubyforge_project: win32utils
|
|
82
|
-
rubygems_version: 1.3.
|
|
102
|
+
rubygems_version: 1.3.1
|
|
83
103
|
signing_key:
|
|
84
104
|
specification_version: 2
|
|
85
105
|
summary: Extra or redefined methods for the File class on Windows.
|