rubyzip 0.9.9 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubyzip might be problematic. Click here for more details.

Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/NEWS +9 -5
  3. data/README.md +79 -21
  4. data/Rakefile +1 -1
  5. data/lib/zip.rb +52 -0
  6. data/lib/zip/central_directory.rb +135 -0
  7. data/lib/zip/constants.rb +57 -7
  8. data/lib/zip/decompressor.rb +2 -2
  9. data/lib/zip/deflater.rb +11 -12
  10. data/lib/zip/dos_time.rb +9 -9
  11. data/lib/zip/entry.rb +609 -0
  12. data/lib/zip/entry_set.rb +86 -0
  13. data/lib/zip/errors.rb +8 -0
  14. data/lib/zip/extra_field.rb +90 -0
  15. data/lib/zip/extra_field/generic.rb +43 -0
  16. data/lib/zip/extra_field/universal_time.rb +47 -0
  17. data/lib/zip/extra_field/unix.rb +39 -0
  18. data/lib/zip/{zip_file.rb → file.rb} +140 -61
  19. data/lib/zip/{zipfilesystem.rb → filesystem.rb} +12 -12
  20. data/lib/zip/inflater.rb +24 -24
  21. data/lib/zip/{zip_input_stream.rb → input_stream.rb} +11 -10
  22. data/lib/zip/ioextras.rb +145 -123
  23. data/lib/zip/null_compressor.rb +1 -1
  24. data/lib/zip/null_decompressor.rb +5 -3
  25. data/lib/zip/null_input_stream.rb +2 -2
  26. data/lib/zip/{zip_output_stream.rb → output_stream.rb} +43 -41
  27. data/lib/zip/pass_thru_compressor.rb +2 -2
  28. data/lib/zip/pass_thru_decompressor.rb +17 -16
  29. data/lib/zip/{zip_streamable_directory.rb → streamable_directory.rb} +1 -1
  30. data/lib/zip/{zip_streamable_stream.rb → streamable_stream.rb} +2 -2
  31. data/lib/zip/version.rb +3 -0
  32. data/samples/example.rb +27 -5
  33. data/samples/example_filesystem.rb +2 -2
  34. data/samples/example_recursive.rb +1 -1
  35. data/samples/gtkRubyzip.rb +1 -1
  36. data/samples/qtzip.rb +2 -2
  37. data/samples/write_simple.rb +1 -1
  38. data/samples/zipfind.rb +1 -1
  39. metadata +29 -27
  40. data/lib/zip/settings.rb +0 -10
  41. data/lib/zip/tempfile_bugfixed.rb +0 -195
  42. data/lib/zip/zip.rb +0 -56
  43. data/lib/zip/zip_central_directory.rb +0 -135
  44. data/lib/zip/zip_entry.rb +0 -638
  45. data/lib/zip/zip_entry_set.rb +0 -77
  46. data/lib/zip/zip_extra_field.rb +0 -213
@@ -1,638 +0,0 @@
1
- module Zip
2
- class ZipEntry
3
- STORED = 0
4
- DEFLATED = 8
5
-
6
- FSTYPE_FAT = 0
7
- FSTYPE_AMIGA = 1
8
- FSTYPE_VMS = 2
9
- FSTYPE_UNIX = 3
10
- FSTYPE_VM_CMS = 4
11
- FSTYPE_ATARI = 5
12
- FSTYPE_HPFS = 6
13
- FSTYPE_MAC = 7
14
- FSTYPE_Z_SYSTEM = 8
15
- FSTYPE_CPM = 9
16
- FSTYPE_TOPS20 = 10
17
- FSTYPE_NTFS = 11
18
- FSTYPE_QDOS = 12
19
- FSTYPE_ACORN = 13
20
- FSTYPE_VFAT = 14
21
- FSTYPE_MVS = 15
22
- FSTYPE_BEOS = 16
23
- FSTYPE_TANDEM = 17
24
- FSTYPE_THEOS = 18
25
- FSTYPE_MAC_OSX = 19
26
- FSTYPE_ATHEOS = 30
27
-
28
- FSTYPES = {
29
- FSTYPE_FAT => 'FAT'.freeze,
30
- FSTYPE_AMIGA => 'Amiga'.freeze,
31
- FSTYPE_VMS => 'VMS (Vax or Alpha AXP)'.freeze,
32
- FSTYPE_UNIX => 'Unix'.freeze,
33
- FSTYPE_VM_CMS => 'VM/CMS'.freeze,
34
- FSTYPE_ATARI => 'Atari ST'.freeze,
35
- FSTYPE_HPFS => 'OS/2 or NT HPFS'.freeze,
36
- FSTYPE_MAC => 'Macintosh'.freeze,
37
- FSTYPE_Z_SYSTEM => 'Z-System'.freeze,
38
- FSTYPE_CPM => 'CP/M'.freeze,
39
- FSTYPE_TOPS20 => 'TOPS-20'.freeze,
40
- FSTYPE_NTFS => 'NTFS'.freeze,
41
- FSTYPE_QDOS => 'SMS/QDOS'.freeze,
42
- FSTYPE_ACORN => 'Acorn RISC OS'.freeze,
43
- FSTYPE_VFAT => 'Win32 VFAT'.freeze,
44
- FSTYPE_MVS => 'MVS'.freeze,
45
- FSTYPE_BEOS => 'BeOS'.freeze,
46
- FSTYPE_TANDEM => 'Tandem NSK'.freeze,
47
- FSTYPE_THEOS => 'Theos'.freeze,
48
- FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'.freeze,
49
- FSTYPE_ATHEOS => 'AtheOS'.freeze,
50
- }.freeze
51
-
52
- attr_accessor :comment, :compressed_size, :crc, :extra, :compression_method,
53
- :name, :size, :localHeaderOffset, :zipfile, :fstype, :externalFileAttributes, :gp_flags, :header_signature
54
-
55
- attr_accessor :follow_symlinks
56
- attr_accessor :restore_times, :restore_permissions, :restore_ownership
57
- attr_accessor :unix_uid, :unix_gid, :unix_perms
58
- attr_accessor :dirty
59
- attr_reader :ftype, :filepath # :nodoc:
60
-
61
- def initialize(zipfile = "", name = "", comment = "", extra = "",
62
- compressed_size = 0, crc = 0,
63
- compression_method = ZipEntry::DEFLATED, size = 0,
64
- time = DOSTime.now)
65
- super()
66
- if name.start_with?("/")
67
- raise ZipEntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
68
- end
69
- @localHeaderOffset = 0
70
- @local_header_size = 0
71
- @internalFileAttributes = 1
72
- @externalFileAttributes = 0
73
- @header_signature = CENTRAL_DIRECTORY_ENTRY_SIGNATURE
74
- @versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT
75
- @version = 52 # this library's version
76
- @ftype = nil # unspecified or unknown
77
- @filepath = nil
78
- if Zip::RUNNING_ON_WINDOWS
79
- @fstype = FSTYPE_FAT
80
- else
81
- @fstype = FSTYPE_UNIX
82
- end
83
- @zipfile = zipfile
84
- @comment = comment
85
- @compressed_size = compressed_size
86
- @crc = crc
87
- @extra = extra
88
- @compression_method = compression_method
89
- @name = name
90
- @size = size
91
- @time = time
92
- @gp_flags = 0
93
-
94
- @follow_symlinks = false
95
-
96
- @restore_times = true
97
- @restore_permissions = false
98
- @restore_ownership = false
99
-
100
- # BUG: need an extra field to support uid/gid's
101
- @unix_uid = nil
102
- @unix_gid = nil
103
- @unix_perms = nil
104
- # @posix_acl = nil
105
- # @ntfs_acl = nil
106
-
107
- if name_is_directory?
108
- @ftype = :directory
109
- else
110
- @ftype = :file
111
- end
112
-
113
- unless ZipExtraField === @extra
114
- @extra = ZipExtraField.new(@extra.to_s)
115
- end
116
-
117
- @dirty = false
118
- end
119
-
120
- def time
121
- if @extra["UniversalTime"]
122
- @extra["UniversalTime"].mtime
123
- else
124
- # Standard time field in central directory has local time
125
- # under archive creator. Then, we can't get timezone.
126
- @time
127
- end
128
- end
129
- alias :mtime :time
130
-
131
- def time=(aTime)
132
- unless @extra.member?("UniversalTime")
133
- @extra.create("UniversalTime")
134
- end
135
- @extra["UniversalTime"].mtime = aTime
136
- @time = aTime
137
- end
138
-
139
- # Returns +true+ if the entry is a directory.
140
- def directory?
141
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
142
- @ftype == :directory
143
- end
144
- alias :is_directory :directory?
145
-
146
- # Returns +true+ if the entry is a file.
147
- def file?
148
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
149
- @ftype == :file
150
- end
151
-
152
- # Returns +true+ if the entry is a symlink.
153
- def symlink?
154
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
155
- @ftype == :symlink
156
- end
157
-
158
- def name_is_directory? #:nodoc:all
159
- (%r{\/$} =~ @name) != nil
160
- end
161
-
162
- def local_entry_offset #:nodoc:all
163
- localHeaderOffset + @local_header_size
164
- end
165
-
166
- def calculate_local_header_size #:nodoc:all
167
- LOCAL_ENTRY_STATIC_HEADER_LENGTH + (@name ? @name.bytesize : 0) + (@extra ? @extra.local_size : 0)
168
- end
169
-
170
- def cdir_header_size #:nodoc:all
171
- CDIR_ENTRY_STATIC_HEADER_LENGTH + (@name ? @name.bytesize : 0) +
172
- (@extra ? @extra.c_dir_size : 0) + (@comment ? @comment.bytesize : 0)
173
- end
174
-
175
- def next_header_offset #:nodoc:all
176
- local_entry_offset + self.compressed_size
177
- end
178
-
179
- # Extracts entry to file destPath (defaults to @name).
180
- def extract(destPath = @name, &onExistsProc)
181
- onExistsProc ||= proc { Zip.options[:on_exists_proc] }
182
-
183
- if directory?
184
- create_directory(destPath, &onExistsProc)
185
- elsif file?
186
- write_file(destPath, &onExistsProc)
187
- elsif symlink?
188
- create_symlink(destPath, &onExistsProc)
189
- else
190
- raise RuntimeError, "unknown file type #{self.inspect}"
191
- end
192
-
193
- self
194
- end
195
-
196
- def to_s
197
- @name
198
- end
199
-
200
- protected
201
-
202
- class << self
203
- def read_zip_short(io) # :nodoc:
204
- io.read(2).unpack('v')[0]
205
- end
206
-
207
- def read_zip_long(io) # :nodoc:
208
- io.read(4).unpack('V')[0]
209
- end
210
-
211
- def read_c_dir_entry(io) #:nodoc:all
212
- entry = new(io.path)
213
- entry.read_c_dir_entry(io)
214
- entry
215
- rescue ZipError
216
- nil
217
- end
218
-
219
- def read_local_entry(io)
220
- entry = new(io.path)
221
- entry.read_local_entry(io)
222
- entry
223
- rescue ZipError
224
- nil
225
- end
226
-
227
- end
228
-
229
- public
230
-
231
- LOCAL_ENTRY_SIGNATURE = 0x04034b50
232
- LOCAL_ENTRY_STATIC_HEADER_LENGTH = 30
233
- LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4+4+4
234
- VERSION_NEEDED_TO_EXTRACT = 20
235
-
236
- def read_local_entry(io) #:nodoc:all
237
- @localHeaderOffset = io.tell
238
- staticSizedFieldsBuf = io.read(LOCAL_ENTRY_STATIC_HEADER_LENGTH)
239
- unless (staticSizedFieldsBuf.size == LOCAL_ENTRY_STATIC_HEADER_LENGTH)
240
- raise ZipError, "Premature end of file. Not enough data for zip entry local header"
241
- end
242
-
243
- @header_signature ,
244
- @version ,
245
- @fstype ,
246
- @gp_flags ,
247
- @compression_method,
248
- lastModTime ,
249
- lastModDate ,
250
- @crc ,
251
- @compressed_size ,
252
- @size ,
253
- nameLength ,
254
- extraLength = staticSizedFieldsBuf.unpack('VCCvvvvVVVvv')
255
-
256
- unless (@header_signature == LOCAL_ENTRY_SIGNATURE)
257
- raise ZipError, "Zip local header magic not found at location '#{localHeaderOffset}'"
258
- end
259
- set_time(lastModDate, lastModTime)
260
-
261
- @name = io.read(nameLength)
262
- extra = io.read(extraLength)
263
- until @name.sub!('\\', '/') == nil do end # some zip files use backslashes instead of slashes as path separators
264
- if (extra && extra.bytesize != extraLength)
265
- raise ZipError, "Truncated local zip entry header"
266
- else
267
- if ZipExtraField === @extra
268
- @extra.merge(extra)
269
- else
270
- @extra = ZipExtraField.new(extra)
271
- end
272
- end
273
- @local_header_size = calculate_local_header_size
274
- end
275
-
276
-
277
-
278
- def write_local_entry(io) #:nodoc:all
279
- @localHeaderOffset = io.tell
280
-
281
- io <<
282
- [LOCAL_ENTRY_SIGNATURE ,
283
- @versionNeededToExtract , # version needed to extract
284
- @gp_flags , # @gp_flags ,
285
- @compression_method ,
286
- @time.to_binary_dos_time , # @lastModTime ,
287
- @time.to_binary_dos_date , # @lastModDate ,
288
- @crc ,
289
- @compressed_size ,
290
- @size ,
291
- @name ? @name.bytesize : 0,
292
- @extra? @extra.local_length : 0 ].pack('VvvvvvVVVvv')
293
- io << @name
294
- io << (@extra ? @extra.to_local_bin : "")
295
- end
296
-
297
- CENTRAL_DIRECTORY_ENTRY_SIGNATURE = 0x02014b50
298
- CDIR_ENTRY_STATIC_HEADER_LENGTH = 46
299
-
300
- def read_c_dir_entry(io) #:nodoc:all
301
- staticSizedFieldsBuf = io.read(CDIR_ENTRY_STATIC_HEADER_LENGTH)
302
- unless (staticSizedFieldsBuf.bytesize == CDIR_ENTRY_STATIC_HEADER_LENGTH)
303
- raise ZipError, "Premature end of file. Not enough data for zip cdir entry header"
304
- end
305
-
306
-
307
- @header_signature ,
308
- @version , # version of encoding software
309
- @fstype , # filesystem type
310
- @versionNeededToExtract ,
311
- @gp_flags ,
312
- @compression_method ,
313
- lastModTime ,
314
- lastModDate ,
315
- @crc ,
316
- @compressed_size ,
317
- @size ,
318
- nameLength ,
319
- extraLength ,
320
- commentLength ,
321
- diskNumberStart ,
322
- @internalFileAttributes ,
323
- @externalFileAttributes ,
324
- @localHeaderOffset ,
325
- @name ,
326
- @extra ,
327
- @comment = staticSizedFieldsBuf.unpack('VCCvvvvvVVVvvvvvVV')
328
-
329
- unless (@header_signature == CENTRAL_DIRECTORY_ENTRY_SIGNATURE)
330
- raise ZipError, "Zip local header magic not found at location '#{localHeaderOffset}'"
331
- end
332
- set_time(lastModDate, lastModTime)
333
-
334
- @name = io.read(nameLength)
335
- until @name.sub!('\\', '/') == nil do end # some zip files use backslashes instead of slashes as path separators
336
- if ZipExtraField === @extra
337
- @extra.merge(io.read(extraLength))
338
- else
339
- @extra = ZipExtraField.new(io.read(extraLength))
340
- end
341
- @comment = io.read(commentLength)
342
- unless (@comment && @comment.bytesize == commentLength)
343
- raise ZipError, "Truncated cdir zip entry header"
344
- end
345
-
346
- case @fstype
347
- when FSTYPE_UNIX
348
- @unix_perms = (@externalFileAttributes >> 16) & 07777
349
-
350
- case (@externalFileAttributes >> 28)
351
- when 04
352
- @ftype = :directory
353
- when 010
354
- @ftype = :file
355
- when 012
356
- @ftype = :symlink
357
- else
358
- #best case guess for whether it is a file or not
359
- #Otherwise this would be set to unknown and that entry would never be able to extracted
360
- if name_is_directory?
361
- @ftype = :directory
362
- else
363
- @ftype = :file
364
- end
365
- end
366
- else
367
- if name_is_directory?
368
- @ftype = :directory
369
- else
370
- @ftype = :file
371
- end
372
- end
373
- @local_header_size = calculate_local_header_size
374
- end
375
-
376
-
377
-
378
- def file_stat(path) # :nodoc:
379
- if @follow_symlinks
380
- return File::stat(path)
381
- else
382
- return File::lstat(path)
383
- end
384
- end
385
-
386
- def get_extra_attributes_from_path(path) # :nodoc:
387
- unless Zip::RUNNING_ON_WINDOWS
388
- stat = file_stat(path)
389
- @unix_uid = stat.uid
390
- @unix_gid = stat.gid
391
- @unix_perms = stat.mode & 07777
392
- end
393
- end
394
-
395
- def set_extra_attributes_on_path(destPath) # :nodoc:
396
- return unless (file? or directory?)
397
-
398
- case @fstype
399
- when FSTYPE_UNIX
400
- # BUG: does not update timestamps into account
401
- # ignore setuid/setgid bits by default. honor if @restore_ownership
402
- unix_perms_mask = 01777
403
- unix_perms_mask = 07777 if (@restore_ownership)
404
- FileUtils::chmod(@unix_perms & unix_perms_mask, destPath) if (@restore_permissions && @unix_perms)
405
- FileUtils::chown(@unix_uid, @unix_gid, destPath) if (@restore_ownership && @unix_uid && @unix_gid && Process::egid == 0)
406
- # File::utimes()
407
- end
408
- end
409
-
410
- def write_c_dir_entry(io) #:nodoc:all
411
- case @fstype
412
- when FSTYPE_UNIX
413
- ft = nil
414
- case @ftype
415
- when :file
416
- ft = 010
417
- @unix_perms ||= 0644
418
- when :directory
419
- ft = 004
420
- @unix_perms ||= 0755
421
- when :symlink
422
- ft = 012
423
- @unix_perms ||= 0755
424
- end
425
-
426
- if (!ft.nil?)
427
- @externalFileAttributes = (ft << 12 | (@unix_perms & 07777)) << 16
428
- end
429
- end
430
-
431
- tmp = [
432
- @header_signature,
433
- @version , # version of encoding software
434
- @fstype , # filesystem type
435
- @versionNeededToExtract , # @versionNeededToExtract ,
436
- @gp_flags , # @gp_flags ,
437
- @compression_method ,
438
- @time.to_binary_dos_time , # @lastModTime ,
439
- @time.to_binary_dos_date , # @lastModDate ,
440
- @crc ,
441
- @compressed_size ,
442
- @size ,
443
- @name ? @name.bytesize : 0 ,
444
- @extra ? @extra.c_dir_length : 0 ,
445
- @comment ? @comment.bytesize : 0 ,
446
- 0 , # disk number start
447
- @internalFileAttributes , # file type (binary=0, text=1)
448
- @externalFileAttributes , # native filesystem attributes
449
- @localHeaderOffset ,
450
- @name ,
451
- @extra ,
452
- @comment
453
- ]
454
-
455
- io << tmp.pack('VCCvvvvvVVVvvvvvVV')
456
-
457
- io << @name
458
- io << (@extra ? @extra.to_c_dir_bin : "")
459
- io << @comment
460
- end
461
-
462
- def == (other)
463
- return false unless other.class == self.class
464
- # Compares contents of local entry and exposed fields
465
- (@compression_method == other.compression_method &&
466
- @crc == other.crc &&
467
- @compressed_size == other.compressed_size &&
468
- @size == other.size &&
469
- @name == other.name &&
470
- @extra == other.extra &&
471
- @filepath == other.filepath &&
472
- self.time.dos_equals(other.time))
473
- end
474
-
475
- def <=> (other)
476
- return to_s <=> other.to_s
477
- end
478
-
479
- # Returns an IO like object for the given ZipEntry.
480
- # Warning: may behave weird with symlinks.
481
- def get_input_stream(&aProc)
482
- if @ftype == :directory
483
- return yield(NullInputStream.instance) if block_given?
484
- return NullInputStream.instance
485
- elsif @filepath
486
- case @ftype
487
- when :file
488
- return ::File.open(@filepath, "rb", &aProc)
489
- when :symlink
490
- linkpath = ::File::readlink(@filepath)
491
- stringio = StringIO.new(linkpath)
492
- return yield(stringio) if block_given?
493
- return stringio
494
- else
495
- raise "unknown @ftype #{@ftype}"
496
- end
497
- else
498
- zis = ZipInputStream.new(@zipfile, localHeaderOffset)
499
- zis.get_next_entry
500
- if block_given?
501
- begin
502
- return yield(zis)
503
- ensure
504
- zis.close
505
- end
506
- else
507
- return zis
508
- end
509
- end
510
- end
511
-
512
- def gather_fileinfo_from_srcpath(srcPath) # :nodoc:
513
- stat = file_stat(srcPath)
514
- case stat.ftype
515
- when 'file'
516
- if name_is_directory?
517
- raise ArgumentError,
518
- "entry name '#{newEntry}' indicates directory entry, but "+
519
- "'#{srcPath}' is not a directory"
520
- end
521
- @ftype = :file
522
- when 'directory'
523
- if ! name_is_directory?
524
- @name += "/"
525
- end
526
- @ftype = :directory
527
- when 'link'
528
- if name_is_directory?
529
- raise ArgumentError,
530
- "entry name '#{newEntry}' indicates directory entry, but "+
531
- "'#{srcPath}' is not a directory"
532
- end
533
- @ftype = :symlink
534
- else
535
- raise RuntimeError, "unknown file type: #{srcPath.inspect} #{stat.inspect}"
536
- end
537
-
538
- @filepath = srcPath
539
- get_extra_attributes_from_path(@filepath)
540
- end
541
-
542
- def write_to_zip_output_stream(aZipOutputStream) #:nodoc:all
543
- if @ftype == :directory
544
- aZipOutputStream.put_next_entry(self)
545
- elsif @filepath
546
- aZipOutputStream.put_next_entry(self)
547
- get_input_stream { |is| IOExtras.copy_stream(aZipOutputStream, is) }
548
- else
549
- aZipOutputStream.copy_raw_entry(self)
550
- end
551
- end
552
-
553
- def parent_as_string
554
- entry_name = name.chomp("/")
555
- slash_index = entry_name.rindex("/")
556
- slash_index ? entry_name.slice(0, slash_index+1) : nil
557
- end
558
-
559
- def get_raw_input_stream(&aProc)
560
- ::File.open(@zipfile, "rb", &aProc)
561
- end
562
-
563
- private
564
-
565
- def set_time(binaryDosDate, binaryDosTime)
566
- @time = DOSTime.parse_binary_dos_format(binaryDosDate, binaryDosTime)
567
- rescue ArgumentError
568
- puts "Invalid date/time in zip entry"
569
- end
570
-
571
- def write_file(destPath, continueOnExistsProc = proc { Zip.options[:continue_on_exists_proc] })
572
- if ::File.exists?(destPath) && ! yield(self, destPath)
573
- raise ZipDestinationFileExistsError,
574
- "Destination '#{destPath}' already exists"
575
- end
576
- ::File.open(destPath, "wb") do |os|
577
- get_input_stream do |is|
578
- set_extra_attributes_on_path(destPath)
579
-
580
- buf = ''
581
- while buf = is.sysread(Decompressor::CHUNK_SIZE, buf)
582
- os << buf
583
- end
584
- end
585
- end
586
- end
587
-
588
- def create_directory(destPath)
589
- if ::File.directory?(destPath)
590
- return
591
- elsif ::File.exists?(destPath)
592
- if block_given? && yield(self, destPath)
593
- FileUtils::rm_f destPath
594
- else
595
- raise ZipDestinationFileExistsError,
596
- "Cannot create directory '#{destPath}'. "+
597
- "A file already exists with that name"
598
- end
599
- end
600
- Dir.mkdir destPath
601
- set_extra_attributes_on_path(destPath)
602
- end
603
-
604
- # BUG: create_symlink() does not use &onExistsProc
605
- def create_symlink(destPath)
606
- stat = nil
607
- begin
608
- stat = ::File::lstat(destPath)
609
- rescue Errno::ENOENT
610
- end
611
-
612
- io = get_input_stream
613
- linkto = io.read
614
-
615
- if stat
616
- if stat.symlink?
617
- if ::File::readlink(destPath) == linkto
618
- return
619
- else
620
- raise ZipDestinationFileExistsError,
621
- "Cannot create symlink '#{destPath}'. "+
622
- "A symlink already exists with that name"
623
- end
624
- else
625
- raise ZipDestinationFileExistsError,
626
- "Cannot create symlink '#{destPath}'. "+
627
- "A file already exists with that name"
628
- end
629
- end
630
-
631
- ::File::symlink(linkto, destPath)
632
- end
633
- end
634
- end
635
-
636
- # Copyright (C) 2002, 2003 Thomas Sondergaard
637
- # rubyzip is free software; you can redistribute it and/or
638
- # modify it under the terms of the ruby license.