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