Class: S3sync::LocalNode

Inherits:
Node
  • Object
show all
Defined in:
lib/s3sync/s3sync.rb

Overview

———- LocalNode ———- #

Instance Attribute Summary

Attributes inherited from Node

#name, #size, #tag

Instance Method Summary collapse

Methods inherited from Node

#directory?

Constructor Details

#initialize(prefix, partialPath) ⇒ LocalNode

Returns a new instance of LocalNode.



533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
# File 'lib/s3sync/s3sync.rb', line 533

def initialize(prefix, partialPath)
  slash = prefix.empty? ? "" : "/"
  @path = prefix + slash + partialPath
  # slash isn't at the front of this any more @name = (partialPath.slice(1..partialPath.length) or '')
  @name = partialPath or ''
  if FileTest.symlink?(@path)
    # this could use the 'file' case below, but why create an extra temp file
    linkData = File.readlink(@path)
    $stderr.puts "link to: #{linkData}" if $S3syncOptions['--debug']
    @size = linkData.length
    md5 = Digest::MD5.new()
    md5 << linkData
    @tag = md5.hexdigest
  elsif FileTest.file?(@path)
    @size = FileTest.size(@path)
    data = nil
    begin
      data = self.stream
      md5 = Digest::MD5.new()
      while !data.eof?
        md5 << data.read(2048) # stream so it's not taking all memory
      end
      data.close
      @tag = md5.hexdigest
    rescue SystemCallError
      # well we're not going to have an md5 that's for sure
      @tag = nil
    end
  elsif FileTest.directory?(@path)
    # all s3 directories are dummy nodes contain the same directory string
    # so for easy comparison, set our size and tag thusly
    @size = $S3syncDirString.length
    @tag = $S3syncDirTag
  end
  debug("local node object init. Name:#{@name} Path:#{@path} Size:#{@size} Tag:#{@tag}")
end

Instance Method Details

#deleteObject



686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
# File 'lib/s3sync/s3sync.rb', line 686

def delete
       # don't try to delete the restore root dir
       # this is a quick fix to deal with the fact that the tree recurse has to visit the root node
       return unless @name != ''
  return unless FileTest.exist?(@path)
  begin
    if FileTest.directory?(@path)
      Dir.rmdir(@path)
    else
      File.unlink(@path)
    end
  rescue SystemCallError
    $stderr.puts "Could not delete #{@path}: #{$!}"
  end
end

#exist?Boolean

Returns:

  • (Boolean)


595
596
597
# File 'lib/s3sync/s3sync.rb', line 595

def exist?
  FileTest.exist?(@path) or FileTest.symlink?(@path)
end

#groupObject



601
602
603
# File 'lib/s3sync/s3sync.rb', line 601

def group
  self.exist? ? self.stat().gid : 0
end

#ownerObject



598
599
600
# File 'lib/s3sync/s3sync.rb', line 598

def owner
  self.exist? ? self.stat().uid : 0
end

#permissionsObject



604
605
606
# File 'lib/s3sync/s3sync.rb', line 604

def permissions
  self.exist? ? self.stat().mode : 600
end

#statObject



592
593
594
# File 'lib/s3sync/s3sync.rb', line 592

def stat
  FileTest.symlink?(@path) ? File.lstat(@path) : File.stat(@path)
end

#streamObject

return a stream that will read the contents of the local item local gets pulled by the S3Node update fn, due to how http streaming is implemented



571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'lib/s3sync/s3sync.rb', line 571

def stream
  begin
    # 1.0.8 switch order of these tests because a symlinked file will say yes to 'file?'
    if FileTest.symlink?(@path) or FileTest.directory?(@path)
      tf = Tempfile.new('s3sync')
      if FileTest.symlink?(@path)
        tf.printf('%s', File.readlink(@path))
      elsif FileTest.directory?(@path)
        tf.printf('%s', $S3syncDirString)
      end
      tf.close
      tf.open
      tf
    elsif FileTest.file?(@path)
      File.open(@path, 'rb')
    end
  rescue SystemCallError
    $stderr.puts "Could not read #{@path}: #{$!}"
    raise
  end
end

#symlink?Boolean

Returns:

  • (Boolean)


683
684
685
# File 'lib/s3sync/s3sync.rb', line 683

def symlink?()
  FileTest.symlink?(@path)
end

#updateFrom(fromNode) ⇒ Object



607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
# File 'lib/s3sync/s3sync.rb', line 607

def updateFrom(fromNode)
  if fromNode.respond_to?(:to_stream)
    fName = @path + '.s3syncTemp'
          # handle the case where the user wants us to create dirs that don't exist in S3
          if $S3syncOptions['--make-dirs']
             # ensure target's path exists
             dirs = @path.split('/')
             # but the last one is a file name
             dirs.pop()
             current = ''
             dirs.each do |dir|
                current << dir << '/'
                begin
                   Dir.mkdir(current) unless FileTest.exist?(current)
                rescue SystemCallError
                   $stderr.puts "Could not mkdir #{current}: #{$!}"
                end
             end
          end
    unless fromNode.directory?
      f = File.open(fName, 'wb')
      f = ProgressStream.new(f, fromNode.size) if $S3syncOptions['--progress']

      fromNode.to_stream(f) 
      f.close
    end
    # get original item out of the way
    File.unlink(@path) if File.exist?(@path)
    if fromNode.symlink? 
      linkTo = ''
      File.open(fName, 'rb'){|f| linkTo = f.read}
      debug("#{@path} will be a symlink to #{linkTo}")
      begin
        File.symlink(linkTo, @path)
      rescue NotImplementedError
        # windows doesn't do symlinks, for example
        # just bail
        File.unlink(fName) if File.exist?(fName)
        return
      rescue SystemCallError
        $stderr.puts "Could not write symlink #{@path}: #{$!}"
      end
    elsif fromNode.directory?
      # only get here when the dir doesn't exist.  else they'd compare ==
      debug(@path)
      begin
        Dir.mkdir(@path) unless FileTest.exist?(@path)
      rescue SystemCallError
        $stderr.puts "Could not mkdir #{@path}: #{$!}"
      end
      
    else
      begin
        File.rename(fName, @path)
      rescue SystemCallError
        $stderr.puts "Could not write (rename) #{@path}: #{$!}"
      end
        
    end
    # clean up if the temp file is still there (as for links)
    File.unlink(fName) if File.exist?(fName)
    
    # update permissions
    linkCommand = fromNode.symlink? ? 'l' : ''
    begin
      File.send(linkCommand + 'chown', fromNode.owner, fromNode.group, @path)
      File.send(linkCommand + 'chmod', fromNode.permissions, @path)
    rescue NotImplementedError
      # no one has lchmod, but who really cares
    rescue SystemCallError
      $stderr.puts "Could not change owner/permissions on #{@path}: #{$!}"
    end
  else
    raise "Node provided as update source doesn't support :to_stream"
  end
end