ruby-ole 1.2.9 → 1.2.10
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/ChangeLog +10 -0
- data/README +3 -1
- data/Rakefile +1 -94
- data/lib/ole/storage/base.rb +62 -34
- data/lib/ole/storage/file_system.rb +40 -69
- data/lib/ole/types/base.rb +42 -17
- metadata +2 -2
data/ChangeLog
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 1.2.10 / 2009-07-20
|
2
|
+
|
3
|
+
- Mostly more performance enhancements, significantly faster for
|
4
|
+
certain operations.
|
5
|
+
- Using lots of files is faster due to new hash lookup for dirents by name.
|
6
|
+
- Writes of many files are faster now too as Dirent & FileTime serialization
|
7
|
+
has been improved.
|
8
|
+
- Certain operations from the filesystem api have been profiled and sped up.
|
9
|
+
- Don't use syswrite on jruby to avoid the buffered stream warnings.
|
10
|
+
|
1
11
|
== 1.2.9 / 2009-07-14
|
2
12
|
|
3
13
|
- Lots of performance enhancements for RangesIO.
|
data/README
CHANGED
@@ -82,8 +82,9 @@ See the documentation for each class for more details.
|
|
82
82
|
|
83
83
|
= TODO
|
84
84
|
|
85
|
-
== 1.2.
|
85
|
+
== 1.2.11
|
86
86
|
|
87
|
+
* internal api cleanup
|
87
88
|
* add buffering to rangesio so that performance for small reads and writes
|
88
89
|
isn't so awful. maybe try and remove the bottlenecks of unbuffered first
|
89
90
|
with more profiling, then implement the buffering on top of that.
|
@@ -98,6 +99,7 @@ See the documentation for each class for more details.
|
|
98
99
|
|
99
100
|
== 1.3.1
|
100
101
|
|
102
|
+
* case insensitive open mode would be nice
|
101
103
|
* fix property sets a bit more. see TODO in Ole::Storage::MetaData
|
102
104
|
* ability to zero out padding and unused blocks
|
103
105
|
* case insensitive mode for ole/file_system?
|
data/Rakefile
CHANGED
@@ -73,7 +73,7 @@ end
|
|
73
73
|
|
74
74
|
Rake::GemPackageTask.new(spec) do |t|
|
75
75
|
t.gem_spec = spec
|
76
|
-
t.need_tar =
|
76
|
+
t.need_tar = false
|
77
77
|
t.need_zip = false
|
78
78
|
t.package_dir = 'build'
|
79
79
|
end
|
@@ -114,96 +114,3 @@ task :benchmark do
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
-
=begin
|
118
|
-
|
119
|
-
1.2.1:
|
120
|
-
|
121
|
-
user system total real
|
122
|
-
write_1mb_1x5 73.920000 8.400000 82.320000 ( 91.893138)
|
123
|
-
|
124
|
-
revision 17 (speed up AllocationTable#free_block by using
|
125
|
-
@sparse attribute, and using Array#index otherwise):
|
126
|
-
|
127
|
-
user system total real
|
128
|
-
write_1mb_1x5 57.910000 6.190000 64.100000 ( 66.207993)
|
129
|
-
write_1mb_2x5266.310000 31.750000 298.060000 (305.877203)
|
130
|
-
|
131
|
-
add in extra resize_chain fix (return blocks to avoid calling
|
132
|
-
AllocationTable#chain twice):
|
133
|
-
|
134
|
-
user system total real
|
135
|
-
write_1mb_1x5 43.140000 5.480000 48.620000 ( 51.835942)
|
136
|
-
|
137
|
-
add in RangesIOResizeable fix (cache @blocks, to avoid calling
|
138
|
-
AllocationTable#chain at all when resizing now, just pass it
|
139
|
-
to AllocationTable#resize_chain):
|
140
|
-
|
141
|
-
user system total real
|
142
|
-
write_1mb_1x5 29.770000 5.180000 34.950000 ( 39.916747)
|
143
|
-
|
144
|
-
40 seconds is still a really long time to write out 5 megs.
|
145
|
-
of course, this is all with a 1_000 byte block size, which is
|
146
|
-
a very small wite. upping this to 100_000 bytes:
|
147
|
-
|
148
|
-
user system total real
|
149
|
-
write_1mb_1x5 0.540000 0.130000 0.670000 ( 1.051862)
|
150
|
-
|
151
|
-
so it seems that that makes a massive difference. so i really
|
152
|
-
need buffering in RangesIO if I don't want it to really hurt
|
153
|
-
for small writes, as all the resize code is kind of expensive.
|
154
|
-
|
155
|
-
one of the costly things at the moment, is RangesIO#offset_and_size,
|
156
|
-
which is called for each write, and re-finds which range we are in.
|
157
|
-
that should obviously be changed, to a fixed one that is invalidated
|
158
|
-
on seeks. buffering would hide that problem to some extent, but i
|
159
|
-
should fix it anyway.
|
160
|
-
|
161
|
-
re-running the original 1.2.1 with 100_000 byte block size:
|
162
|
-
|
163
|
-
user system total real
|
164
|
-
write_1mb_1x5 15.590000 2.230000 17.820000 ( 18.704910)
|
165
|
-
|
166
|
-
so there the really badly non-linear AllocationTable#resize_chain is
|
167
|
-
being felt.
|
168
|
-
|
169
|
-
back to current working copy, running full benchmark:
|
170
|
-
|
171
|
-
user system total real
|
172
|
-
write_1mb_1x5 0.530000 0.150000 0.680000 ( 0.708919)
|
173
|
-
write_1mb_2x5227.940000 31.260000 259.200000 (270.200960)
|
174
|
-
|
175
|
-
not surprisingly, the second case hasn't been helped much by the fixes
|
176
|
-
so far, as they only really help multiple resizes and writes for a file.
|
177
|
-
this could be pain in the new file system code - potentially searching
|
178
|
-
through Dirent#children at creation time.
|
179
|
-
|
180
|
-
to test, i'll profile creating 1_000 files, without writing anything:
|
181
|
-
|
182
|
-
user system total real
|
183
|
-
write_1mb_2x5 16.990000 1.830000 18.820000 ( 19.900568)
|
184
|
-
|
185
|
-
hmmm, so thats not all of it. maybe its the initial chain calls, etc?
|
186
|
-
writing 1 byte:
|
187
|
-
|
188
|
-
user system total real
|
189
|
-
write_1mb_1x5 0.520000 0.120000 0.640000 ( 0.660638)
|
190
|
-
write_1mb_2x5 19.810000 2.280000 22.090000 ( 22.696214)
|
191
|
-
|
192
|
-
weird.
|
193
|
-
|
194
|
-
100 bytes:
|
195
|
-
|
196
|
-
user system total real
|
197
|
-
write_1mb_1x5 0.560000 0.140000 0.700000 ( 1.424974)
|
198
|
-
write_1mb_2x5 22.940000 2.840000 25.780000 ( 26.556346)
|
199
|
-
|
200
|
-
500 bytes:
|
201
|
-
|
202
|
-
user system total real
|
203
|
-
write_1mb_1x5 0.530000 0.150000 0.680000 ( 1.139738)
|
204
|
-
write_1mb_2x5 77.260000 10.130000 87.390000 ( 91.671086)
|
205
|
-
|
206
|
-
what happens there? very strange.
|
207
|
-
|
208
|
-
=end
|
209
|
-
|
data/lib/ole/storage/base.rb
CHANGED
@@ -21,7 +21,7 @@ module Ole # :nodoc:
|
|
21
21
|
class FormatError < StandardError # :nodoc:
|
22
22
|
end
|
23
23
|
|
24
|
-
VERSION = '1.2.
|
24
|
+
VERSION = '1.2.10'
|
25
25
|
|
26
26
|
# options used at creation time
|
27
27
|
attr_reader :params
|
@@ -180,7 +180,7 @@ module Ole # :nodoc:
|
|
180
180
|
|
181
181
|
# serialize the dirents using the bbat
|
182
182
|
RangesIOResizeable.open @bbat, 'w', :first_block => @header.dirent_start do |io|
|
183
|
-
@dirents.
|
183
|
+
io.write @dirents.map { |dirent| dirent.to_s }.join
|
184
184
|
padding = (io.size / @bbat.block_size.to_f).ceil * @bbat.block_size - io.size
|
185
185
|
io.write 0.chr * padding
|
186
186
|
@header.dirent_start = io.first_block
|
@@ -203,7 +203,7 @@ module Ole # :nodoc:
|
|
203
203
|
@bbat.map! do |b|
|
204
204
|
b == AllocationTable::BAT || b == AllocationTable::META_BAT ? AllocationTable::AVAIL : b
|
205
205
|
end
|
206
|
-
|
206
|
+
|
207
207
|
# currently we use a loop. this could be better, but basically,
|
208
208
|
# the act of writing out the bat, itself requires blocks which get
|
209
209
|
# recorded in the bat.
|
@@ -482,7 +482,7 @@ module Ole # :nodoc:
|
|
482
482
|
# The blocks are Big or Small blocks depending on the table type.
|
483
483
|
def blocks_to_ranges chain, size=nil
|
484
484
|
# truncate the chain if required
|
485
|
-
chain = chain[0
|
485
|
+
chain = chain[0, (size.to_f / block_size).ceil] if size
|
486
486
|
# convert chain to ranges of the block size
|
487
487
|
ranges = chain.map { |i| [block_size * i, block_size] }
|
488
488
|
# truncate final range if required
|
@@ -526,8 +526,8 @@ module Ole # :nodoc:
|
|
526
526
|
def free_block
|
527
527
|
if @sparse
|
528
528
|
i = index(AVAIL) and return i
|
529
|
+
@sparse = false
|
529
530
|
end
|
530
|
-
@sparse = false
|
531
531
|
push AVAIL
|
532
532
|
length - 1
|
533
533
|
end
|
@@ -565,8 +565,14 @@ module Ole # :nodoc:
|
|
565
565
|
end
|
566
566
|
|
567
567
|
# Big blocks are kind of -1 based, in order to not clash with the header.
|
568
|
-
def blocks_to_ranges
|
569
|
-
super
|
568
|
+
def blocks_to_ranges chain, size=nil
|
569
|
+
#super chain.map { |b| b + 1 }, size
|
570
|
+
# duplicated from AllocationTable#blocks_to_ranges to avoid chain.map
|
571
|
+
# which was decent part of benchmark profile
|
572
|
+
chain = chain[0, (size.to_f / block_size).ceil] if size
|
573
|
+
ranges = chain.map { |i| [block_size * (i + 1), block_size] }
|
574
|
+
ranges.last[1] -= (ranges.length * block_size - size) if ranges.last and size
|
575
|
+
ranges
|
570
576
|
end
|
571
577
|
end
|
572
578
|
|
@@ -711,13 +717,21 @@ module Ole # :nodoc:
|
|
711
717
|
AllocationTable::EOC, 0, 0.chr * 4
|
712
718
|
]
|
713
719
|
|
714
|
-
# i think its just used by the tree building
|
715
|
-
attr_accessor :idx
|
716
720
|
# This returns all the children of this +Dirent+. It is filled in
|
717
721
|
# when the tree structure is recreated.
|
718
|
-
|
719
|
-
|
722
|
+
attr_reader :children
|
723
|
+
attr_reader :name
|
720
724
|
attr_reader :ole, :type, :create_time, :modify_time
|
725
|
+
attr_reader :parent
|
726
|
+
|
727
|
+
# i think its just used by the tree building
|
728
|
+
attr_accessor :idx
|
729
|
+
|
730
|
+
# these are for internal use and are used for faster lookup.
|
731
|
+
attr_reader :name_lookup
|
732
|
+
attr_writer :parent
|
733
|
+
protected :name_lookup, :parent=
|
734
|
+
|
721
735
|
def initialize ole, values=DEFAULT, params={}
|
722
736
|
@ole = ole
|
723
737
|
values, params = DEFAULT, values if Hash === values
|
@@ -737,44 +751,46 @@ module Ole # :nodoc:
|
|
737
751
|
|
738
752
|
# further extra type specific stuff
|
739
753
|
if file?
|
740
|
-
default_time = @ole.params[:update_timestamps] ?
|
754
|
+
default_time = @ole.params[:update_timestamps] ? Types::FileTime.now : nil
|
741
755
|
@create_time ||= default_time
|
742
756
|
@modify_time ||= default_time
|
743
757
|
@create_time = Types::Variant.load(Types::VT_FILETIME, create_time_str) if create_time_str
|
744
758
|
@modify_time = Types::Variant.load(Types::VT_FILETIME, create_time_str) if modify_time_str
|
745
759
|
@children = nil
|
760
|
+
@name_lookup = nil
|
746
761
|
else
|
747
762
|
@create_time = nil
|
748
763
|
@modify_time = nil
|
749
764
|
self.size = 0 unless @type == :root
|
750
765
|
@children = []
|
766
|
+
@name_lookup = {}
|
751
767
|
end
|
768
|
+
|
769
|
+
@parent = nil
|
752
770
|
|
753
771
|
# to silence warnings. used for tree building at load time
|
754
772
|
# only.
|
755
773
|
@idx = nil
|
756
774
|
end
|
757
775
|
|
776
|
+
def name= name
|
777
|
+
if @parent
|
778
|
+
map = @parent.instance_variable_get :@name_lookup
|
779
|
+
map.delete @name
|
780
|
+
map[name] = self
|
781
|
+
end
|
782
|
+
@name = name
|
783
|
+
end
|
784
|
+
|
785
|
+
def children= children
|
786
|
+
@children = []
|
787
|
+
children.each { |child| self << child }
|
788
|
+
end
|
789
|
+
|
758
790
|
def open mode='r'
|
759
791
|
raise Errno::EISDIR unless file?
|
760
792
|
io = RangesIOMigrateable.new self, mode
|
761
|
-
|
762
|
-
# maybe let the io object know about the mode, so it can refuse
|
763
|
-
# to work for read/write appropriately. maybe redefine all unusable
|
764
|
-
# methods using singleton class to throw errors.
|
765
|
-
# for now, i just want to implement truncation on use of 'w'. later,
|
766
|
-
# i need to do 'a' etc.
|
767
|
-
case mode
|
768
|
-
when 'r', 'r+'
|
769
|
-
# as i don't enforce reading/writing, nothing changes here. kind of
|
770
|
-
# need to enforce tt if i want modify times to work better.
|
771
|
-
@modify_time = Time.now if mode == 'r+'
|
772
|
-
when 'w'
|
773
|
-
@modify_time = Time.now
|
774
|
-
# io.truncate 0
|
775
|
-
#else
|
776
|
-
# raise NotImplementedError, "unsupported mode - #{mode.inspect}"
|
777
|
-
end
|
793
|
+
@modify_time = Types::FileTime.now if io.mode.writeable?
|
778
794
|
if block_given?
|
779
795
|
begin yield io
|
780
796
|
ensure; io.close
|
@@ -798,7 +814,7 @@ module Ole # :nodoc:
|
|
798
814
|
|
799
815
|
# maybe need some options regarding case sensitivity.
|
800
816
|
def / name
|
801
|
-
|
817
|
+
@name_lookup[name]
|
802
818
|
end
|
803
819
|
|
804
820
|
def [] idx
|
@@ -887,11 +903,23 @@ module Ole # :nodoc:
|
|
887
903
|
str + '>'
|
888
904
|
end
|
889
905
|
|
890
|
-
def
|
906
|
+
def << child
|
907
|
+
child.parent = self
|
908
|
+
@name_lookup[child.name] = child
|
909
|
+
@children << child
|
910
|
+
end
|
911
|
+
|
912
|
+
# remove the Dirent +child+ from the children array, truncating the data
|
913
|
+
# by default.
|
914
|
+
def delete child, truncate=true
|
891
915
|
# remove from our child array, so that on reflatten and re-creation of @dirents, it will be gone
|
892
|
-
|
916
|
+
unless @children.delete(child)
|
917
|
+
raise ArgumentError, "#{child.inspect} not a child of #{self.inspect}"
|
918
|
+
end
|
919
|
+
@name_lookup.delete(child.name)
|
920
|
+
child.parent = nil
|
893
921
|
# free our blocks
|
894
|
-
child.open { |io| io.truncate 0 }
|
922
|
+
child.open { |io| io.truncate 0 } if child.file?
|
895
923
|
end
|
896
924
|
|
897
925
|
def self.copy src, dst
|
@@ -902,7 +930,7 @@ module Ole # :nodoc:
|
|
902
930
|
if src.dir?
|
903
931
|
src.children.each do |src_child|
|
904
932
|
dst_child = Dirent.new dst.ole, :type => src_child.type
|
905
|
-
dst
|
933
|
+
dst << dst_child
|
906
934
|
Dirent.copy src_child, dst_child
|
907
935
|
end
|
908
936
|
else
|
@@ -45,12 +45,13 @@ module Ole # :nodoc:
|
|
45
45
|
# (change it)
|
46
46
|
def dirent_from_path path
|
47
47
|
dirent = @root
|
48
|
-
path = file.expand_path
|
49
|
-
path = path.sub(/^\/*/, '').sub(/\/*$/, '').split(/\/+/)
|
48
|
+
path = file.expand_path(path).split('/')
|
50
49
|
until path.empty?
|
50
|
+
part = path.shift
|
51
|
+
next if part.empty?
|
51
52
|
return nil if dirent.file?
|
52
|
-
return nil unless dirent = dirent/
|
53
|
-
end
|
53
|
+
return nil unless dirent = dirent/part
|
54
|
+
end
|
54
55
|
dirent
|
55
56
|
end
|
56
57
|
|
@@ -107,14 +108,20 @@ module Ole # :nodoc:
|
|
107
108
|
end
|
108
109
|
|
109
110
|
def expand_path path
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
|
111
|
+
# its already absolute if it starts with a '/'
|
112
|
+
unless path =~ /^\//
|
113
|
+
# get the raw stored pwd value (its blank for root)
|
114
|
+
pwd = @ole.dir.instance_variable_get :@pwd
|
115
|
+
path = "#{pwd}/#{path}"
|
116
|
+
end
|
114
117
|
# at this point its already absolute. we use File.expand_path
|
115
118
|
# just for the .. and . handling
|
116
119
|
# No longer use RUBY_PLATFORM =~ /win/ as it matches darwin. better way?
|
117
|
-
File
|
120
|
+
if File::ALT_SEPARATOR != "\\"
|
121
|
+
File.expand_path(path)
|
122
|
+
else
|
123
|
+
File.expand_path(path)[2..-1]
|
124
|
+
end
|
118
125
|
end
|
119
126
|
|
120
127
|
# +orig_path+ is just so that we can use the requested path
|
@@ -122,7 +129,7 @@ module Ole # :nodoc:
|
|
122
129
|
def dirent_from_path path, orig_path=nil
|
123
130
|
orig_path ||= path
|
124
131
|
dirent = @ole.dirent_from_path path
|
125
|
-
raise Errno::ENOENT,
|
132
|
+
raise Errno::ENOENT, orig_path unless dirent
|
126
133
|
raise Errno::EISDIR, orig_path if dirent.dir?
|
127
134
|
dirent
|
128
135
|
end
|
@@ -152,7 +159,7 @@ module Ole # :nodoc:
|
|
152
159
|
# a get_parent_dirent function.
|
153
160
|
parent_path, basename = File.split expand_path(path)
|
154
161
|
parent = @ole.dir.send :dirent_from_path, parent_path, path
|
155
|
-
parent
|
162
|
+
parent << dirent = Dirent.new(@ole, :type => :file, :name => basename)
|
156
163
|
end
|
157
164
|
else
|
158
165
|
dirent = dirent_from_path path
|
@@ -211,31 +218,20 @@ module Ole # :nodoc:
|
|
211
218
|
1 + 1
|
212
219
|
end
|
213
220
|
# reparent the dirent
|
214
|
-
from_parent_path, from_basename = File.split expand_path(from_path)
|
215
221
|
to_parent_path, to_basename = File.split expand_path(to_path)
|
216
|
-
from_parent =
|
222
|
+
from_parent = dirent.parent
|
217
223
|
to_parent = @ole.dir.send :dirent_from_path, to_parent_path, to_path
|
218
|
-
from_parent.
|
224
|
+
from_parent.delete dirent, false
|
219
225
|
# and also change its name
|
220
226
|
dirent.name = to_basename
|
221
|
-
to_parent
|
227
|
+
to_parent << dirent
|
222
228
|
0
|
223
229
|
end
|
224
230
|
|
225
|
-
# crappy copy from Dir.
|
226
231
|
def unlink(*paths)
|
227
232
|
paths.each do |path|
|
228
|
-
dirent =
|
229
|
-
|
230
|
-
# allocation table.
|
231
|
-
# i think if you run repack, all free blocks should get zeroed,
|
232
|
-
# but currently the original data is there unmodified.
|
233
|
-
open(path) { |f| f.truncate 0 }
|
234
|
-
# remove ourself from our parent, so we won't be part of the dir
|
235
|
-
# tree at save time.
|
236
|
-
parent_path, basename = File.split expand_path(path)
|
237
|
-
parent = @ole.dir.send :dirent_from_path, parent_path, path
|
238
|
-
parent.children.delete dirent
|
233
|
+
dirent = dirent_from_path path
|
234
|
+
dirent.parent.delete dirent
|
239
235
|
end
|
240
236
|
paths.length # hmmm. as per ::File ?
|
241
237
|
end
|
@@ -243,15 +239,17 @@ module Ole # :nodoc:
|
|
243
239
|
end
|
244
240
|
|
245
241
|
#
|
246
|
-
#
|
242
|
+
# An *instance* of this class is supposed to provide similar methods
|
247
243
|
# to the class methods of Dir itself.
|
248
244
|
#
|
249
|
-
#
|
245
|
+
# Fairly complete - like zip/zipfilesystem's implementation, i provide
|
250
246
|
# everything except chroot and glob. glob could be done with a glob
|
251
|
-
# to regex
|
252
|
-
# recursive glob complicates that somewhat.
|
247
|
+
# to regex conversion, and then simply match in the entries array...
|
248
|
+
# although recursive glob complicates that somewhat.
|
249
|
+
#
|
250
|
+
# Dir.chroot, Dir.glob, Dir.[], and Dir.tmpdir is the complete list of
|
251
|
+
# methods still missing.
|
253
252
|
#
|
254
|
-
# Dir.chroot, Dir.glob, Dir.[], and Dir.tmpdir is the complete list.
|
255
253
|
class DirClass
|
256
254
|
def initialize ole
|
257
255
|
@ole = ole
|
@@ -271,11 +269,8 @@ module Ole # :nodoc:
|
|
271
269
|
|
272
270
|
def open path
|
273
271
|
dir = Dir.new path, entries(path)
|
274
|
-
|
275
|
-
|
276
|
-
else
|
277
|
-
dir
|
278
|
-
end
|
272
|
+
return dir unless block_given?
|
273
|
+
yield dir
|
279
274
|
end
|
280
275
|
|
281
276
|
# as for file, explicit alias to inhibit block
|
@@ -286,17 +281,14 @@ module Ole # :nodoc:
|
|
286
281
|
# pwd is always stored without the trailing slash. we handle
|
287
282
|
# the root case here
|
288
283
|
def pwd
|
289
|
-
if @pwd.empty?
|
290
|
-
|
291
|
-
else
|
292
|
-
@pwd
|
293
|
-
end
|
284
|
+
return '/' if @pwd.empty?
|
285
|
+
@pwd
|
294
286
|
end
|
295
287
|
alias getwd :pwd
|
296
288
|
|
297
289
|
def chdir orig_path
|
298
290
|
# make path absolute, squeeze slashes, and remove trailing slash
|
299
|
-
path = @ole.file.expand_path(orig_path).
|
291
|
+
path = @ole.file.expand_path(orig_path).squeeze('/').sub(/\/$/, '')
|
300
292
|
# this is just for the side effects of the exceptions if invalid
|
301
293
|
dirent_from_path path, orig_path
|
302
294
|
if block_given?
|
@@ -331,10 +323,7 @@ module Ole # :nodoc:
|
|
331
323
|
entries(path).each(&block)
|
332
324
|
end
|
333
325
|
|
334
|
-
# there are some other important ones, like:
|
335
|
-
# chroot (!), glob etc etc. for now, i think
|
336
326
|
def mkdir path
|
337
|
-
# as for rmdir below:
|
338
327
|
parent_path, basename = File.split @ole.file.expand_path(path)
|
339
328
|
# note that we will complain about the full path despite accessing
|
340
329
|
# the parent path. this is consistent with ::Dir
|
@@ -342,29 +331,14 @@ module Ole # :nodoc:
|
|
342
331
|
# now, we first should ensure that it doesn't already exist
|
343
332
|
# either as a file or a directory.
|
344
333
|
raise Errno::EEXIST, path if parent/basename
|
345
|
-
parent
|
334
|
+
parent << Dirent.new(@ole, :type => :dir, :name => basename)
|
346
335
|
0
|
347
336
|
end
|
348
337
|
|
349
338
|
def rmdir path
|
350
339
|
dirent = dirent_from_path path
|
351
340
|
raise Errno::ENOTEMPTY, path unless dirent.children.empty?
|
352
|
-
|
353
|
-
# now delete it, how to do that? the canonical representation that is
|
354
|
-
# maintained is the root tree, and the children array. we must remove it
|
355
|
-
# from the children array.
|
356
|
-
# we need the parent then. this sucks but anyway:
|
357
|
-
# we need to split the path. but before we can do that, we need
|
358
|
-
# to expand it first. eg. say we need the parent to unlink
|
359
|
-
# a/b/../c. the parent should be a, not a/b/.., or a/b.
|
360
|
-
parent_path, basename = File.split @ole.file.expand_path(path)
|
361
|
-
# this shouldn't be able to fail if the above didn't
|
362
|
-
parent = dirent_from_path parent_path
|
363
|
-
# note that the way this currently works, on save and repack time this will get
|
364
|
-
# reflected. to work properly, ie to make a difference now it would have to re-write
|
365
|
-
# the dirent. i think that Ole::Storage#close will handle that. and maybe include a
|
366
|
-
# #repack.
|
367
|
-
parent.children.delete dirent
|
341
|
+
dirent.parent.delete dirent
|
368
342
|
0 # hmmm. as per ::Dir ?
|
369
343
|
end
|
370
344
|
alias delete :rmdir
|
@@ -373,7 +347,6 @@ module Ole # :nodoc:
|
|
373
347
|
# note that there is nothing remotely ole specific about
|
374
348
|
# this class. it simply provides the dir like sequential access
|
375
349
|
# methods on top of an array.
|
376
|
-
# hmm, doesn't throw the IOError's on use of a closed directory...
|
377
350
|
class Dir
|
378
351
|
include Enumerable
|
379
352
|
|
@@ -408,14 +381,12 @@ module Ole # :nodoc:
|
|
408
381
|
raise IOError if @closed
|
409
382
|
@pos = [[0, pos].max, @entries.length].min
|
410
383
|
end
|
384
|
+
alias tell :pos
|
385
|
+
alias seek :pos=
|
411
386
|
|
412
387
|
def rewind
|
413
|
-
|
414
|
-
@pos = 0
|
388
|
+
seek 0
|
415
389
|
end
|
416
|
-
|
417
|
-
alias tell :pos
|
418
|
-
alias seek :pos=
|
419
390
|
end
|
420
391
|
end
|
421
392
|
end
|
data/lib/ole/types/base.rb
CHANGED
@@ -57,8 +57,34 @@ module Ole # :nodoc:
|
|
57
57
|
# for VT_FILETIME
|
58
58
|
class FileTime < DateTime
|
59
59
|
SIZE = 8
|
60
|
+
|
61
|
+
# DateTime.new is slow... faster version for FileTime
|
62
|
+
def self.new year, month, day, hour=0, min=0, sec=0, usec=0
|
63
|
+
# DateTime will remove leap and leap-leap seconds
|
64
|
+
sec = 59 if sec > 59
|
65
|
+
if month <= 2
|
66
|
+
month += 12
|
67
|
+
year -= 1
|
68
|
+
end
|
69
|
+
y = year + 4800
|
70
|
+
m = month - 3
|
71
|
+
jd = day + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 32045
|
72
|
+
fr = hour / 24.0 + min / 1440.0 + sec / 86400.0
|
73
|
+
new! jd + fr - 0.5, 0, ITALY
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.from_time time
|
77
|
+
new(*(time.to_a[0, 6].reverse + [time.usec]))
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.now
|
81
|
+
from_time Time.now
|
82
|
+
end
|
83
|
+
|
60
84
|
EPOCH = new 1601, 1, 1
|
61
85
|
|
86
|
+
#def initialize year, month, day, hour, min, sec
|
87
|
+
|
62
88
|
# Create a +DateTime+ object from a struct +FILETIME+
|
63
89
|
# (http://msdn2.microsoft.com/en-us/library/ms724284.aspx).
|
64
90
|
#
|
@@ -68,27 +94,26 @@ module Ole # :nodoc:
|
|
68
94
|
low, high = str.to_s.unpack 'V2'
|
69
95
|
# we ignore these, without even warning about it
|
70
96
|
return nil if low == 0 and high == 0
|
71
|
-
#
|
72
|
-
|
73
|
-
|
74
|
-
const_get('EPOCH') + Rational(high * (1 << 32) + low, 1e7.to_i * 86400) rescue return
|
75
|
-
# extra sanity check...
|
76
|
-
#unless (1800...2100) === time.year
|
77
|
-
# Log.warn "ignoring unlikely time value #{time.to_s}"
|
78
|
-
# return nil
|
79
|
-
#end
|
80
|
-
#time
|
97
|
+
# the + 0.00001 here stinks a bit...
|
98
|
+
seconds = (high * (1 << 32) + low) / 1e7 + 0.00001
|
99
|
+
EPOCH + seconds / 86400 rescue return
|
81
100
|
end
|
82
|
-
|
101
|
+
|
83
102
|
# +time+ should be able to be either a Time, Date, or DateTime.
|
84
103
|
def self.dump time
|
85
|
-
# i think i'll convert whatever i get to be a datetime, because of
|
86
|
-
# the covered range.
|
87
104
|
return 0.chr * SIZE unless time
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
105
|
+
# convert whatever is given to be a datetime, to handle the large range
|
106
|
+
case time
|
107
|
+
when Date # this includes DateTime & FileTime
|
108
|
+
when Time
|
109
|
+
time = from_time time
|
110
|
+
else
|
111
|
+
raise ArgumentError, 'unknown time argument - %p' % [time]
|
112
|
+
end
|
113
|
+
# round to milliseconds (throwing away nanosecond precision) to
|
114
|
+
# compensate for using Float-based DateTime
|
115
|
+
nanoseconds = ((time - EPOCH).to_f * 864000000).round * 1000
|
116
|
+
high, low = nanoseconds.divmod 1 << 32
|
92
117
|
[low, high].pack 'V2'
|
93
118
|
end
|
94
119
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-ole
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Lowe
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-07-
|
12
|
+
date: 2009-07-20 00:00:00 +10:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|