win32-file 0.5.6 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|