class GxG::Storage::FileSpace

Public Class Methods

new() click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 6
def initialize()
  @thread_safety = ::Mutex.new
  @mounted = []
end

Public Instance Methods

copy(source_path=nil,destination_path=nil, options={}) click to toggle source

Copying support:

# File lib/gxg/gxg_dbfs.rb, line 483
def copy(source_path=nil,destination_path=nil, options={})
  # Four scenarios: FS_to_FS, DB_to_DB, FS_to_DB, DB_to_FS
  # Objective: handle both file/object and directory/persisted_array in one method!
  # Does OVERWRITE copy onto existing files/folders of same name.
  result = false
  error = false
  if source_path == destination_path
    error = true
  end
  #
  source = {:enclosure => nil, :profile => nil, :record => nil, :permissions => nil}
  if self.valid_path?(source_path.to_s)
    if source_path.to_s == "/"
      source[:record] = nil
    else
      source[:record] = self.volume_of_path(source_path.to_s)
    end
    if source[:record]
      source[:profile] = self.profile(source_path,options.merge({:follow_symlinks => true}))
      source[:enclosure] = self.profile(File.dirname(source_path),options.merge({:follow_symlinks => true}))
      source[:permissions] = self.get_permissions(source_path)
    else
      error = true
      log_error({:error => Exception.new("You do not have sufficient priviledges."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
    end
  else
    error = true
    log_error({:error => Exception.new("Invalid source path"), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
  end
  # Note: if destination is not full path, but path to its future enclosure, append the filename to fully qualify the destination_path
  if File.basename(source_path) != File.basename(destination_path)
    destination_path = File.expand_path(destination_path + "/" + File.basename(source_path))
  end
  #
  destination = {:enclosure => self.profile(File.dirname(destination_path),options.merge({:follow_symlinks => true})), :profile => nil, :record => nil, :permissions => source[:permissions].clone}
  if self.valid_path?(destination_path.to_s)
    if destination_path.to_s == "/"
      destination[:record] = nil
    else
      destination[:record] = self.volume_of_path(destination_path.to_s)
    end
    if destination[:record]
      destination[:profile] = self.profile(destination_path,options.merge({:follow_symlinks => true}))
    else
      error = true
      log_error({:error => Exception.new("You do not have sufficient permissions."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
    end
  else
    if destination[:enclosure].is_a?(::Hash)
      unless destination[:enclosure][:permissions][:effective][:create] == true
        error = true
        log_error({:error => Exception.new("You do not have sufficient permissions to create at destination."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
      end
      unless error == true
        destination[:record] = self.volume_of_path(File.dirname(destination_path))
        if destination[:record].is_a?(::Hash)
          # Note: this won't exist yet, but is here for future reference.
          destination[:record][:subpath] = (destination[:record][:subpath] + "/" + File.basename(destination_path))
        end
      end
    else
      error = true
      log_error({:error => Exception.new("Invalid destination path"), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
    end
  end
  unless error == true
    if source[:profile]
      # determine permissions
      if source[:profile][:permissions][:effective][:read] == true
        # Does destination already exist? --> overwrite permissions?
        if destination[:profile]
          unless destination[:profile][:permissions][:effective][:write] == true
            error = true
            log_error({:error => Exception.new("You do not have sufficient permissions at destination."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})      
          end
        end
        unless error == true
          # determine copying scenario: FS_to_FS, DB_to_DB, FS_to_DB, DB_to_FS
          if source[:record][:volume].file_system?()
            if destination[:enclosure][:uuid].to_s.size > 0
              scenario = :FS_to_DB
            else
              scenario = :FS_to_FS
            end
          else
            if destination[:enclosure][:uuid].to_s.size > 0
              scenario = :DB_to_DB
            else
              scenario = :DB_to_FS
            end
          end
          # create source/destination path pairings:
          file_list = []
          dir_list = []
          if ["persisted_array","directory","virtual_directory"].include?(source[:profile][:type].to_s)
            # directory / collection
            search_queue = [{:source => (source_path), :destination => (destination_path)}]
            while search_queue.size > 0 do
              entry = search_queue.shift
              if entry
                self.entries(entry[:source]).each do |the_profile|
                  new_record = {:source => (entry[:source] + "/" + the_profile[:title]), :destination => (entry[:destination] + "/" + the_profile[:title]), :mode => the_profile[:mode], :mime => the_profile[:mime]}
                  if ["persisted_array","directory","virtual_directory"].include?(the_profile[:type].to_s)
                    dir_list << new_record
                    search_queue << new_record
                  else
                    file_list << new_record
                  end
                end
              end
            end
          else
            # single object
            file_list << {:source => (source_path), :destination => (destination_path)}
          end
          # lay down dir structure
          dir_list.each do |the_record|
            self.mkpath(the_record[:destination])
          end
          #
          case scenario
          when :FS_to_FS
            # copy files one at a time.
            file_list.each do |the_record|
              if self.exist?(the_record[:destination])
                self.rmfile(the_record[:destination])
              end
              # FIXME: find a way to preserve :mode (via REAL FS path) on new file.
              begin
                source_file = self.open(the_record[:source])
                destination_file = self.mkfile(the_record[:destination])
                if source_file && destination_file
                  GxG::apportioned_ranges(source_file.size,65536).each do |the_range|
                    source_file.seek(the_range.first)
                    destination_file.write(GxG::ByteArray.new(source_file.read(the_range.size)).to_s)
                  end
                  destination_file.close
                  source_file.close
                else
                  raise Exception, "Error opening source or destination files."
                end
              rescue Exception => the_error
                log_error({:error => the_error, :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})      
                error = true
                break
              end
            end
            unless error == true
              destination[:permissions].each do |the_entry|
                self.set_permissions(destination_path, the_entry[:credential], the_entry[:permissions])
              end
              result = true
            end
          when :FS_to_DB
            file_list.each do |the_record|
              begin
                # Question: should I support an object import format from a text file ??
                if File.extname(the_record[:source]) == ".gxg_export" && (the_record[:mime] == "application/octet-stream" || the_record[:mime] == "application/json")
                  source_file = self.open(the_record[:source])
                  #
                  import_record = source_file.read()
                  source_file.close
                  if import_record.to_s.json?
                    import_record = ::JSON::parse(import_record,{:symbolize_names => true})
                  end
                  if import_record.is_a?(::Hash)
                    database = nil
                    if destination[:record].is_a?(::Hash)
                      if destination[:record][:volume].is_a?(GxG::Storage::Volume)
                        database = destination[:record][:volume].database()
                      end
                    end
                    if database
                      enclosure_uuid = self.profile(File.dirname(the_record[:destination]))[:uuid].to_s.to_sym
                      destination_uuid = import_record[:record][:uuid].to_s.to_sym
                      # Import Formats first
                      if import_record[:formats].is_a?(::Hash)
                        op_frame = {:operation => :merge_format, :data => []}
                        import_record[:formats].keys.each do |the_format_key|
                          op_frame[:data] << import_record[:formats][(the_format_key)]
                        end
                        if op_frame[:data].size > 0
                          database.synchronize_records([(op_frame)],destination[:record][:volume].credential())
                        end
                      end
                      #
                      database.synchronize_records([{:operation => :merge, :data => [(import_record[:record])]}],destination[:record][:volume].credential())
                      #
                      unless self.exist?(the_record[:destination])
                        the_enclosure = database.retrieve_by_uuid(enclosure_uuid, destination[:record][:volume].credential())
                        the_enclosure.wait_for_reservation
                        destination_object = database.retrieve_by_uuid(destination_uuid, destination[:record][:volume].credential())
                        the_enclosure << destination_object
                        destination_object.deactivate
                        the_enclosure.release_reservation
                        the_enclosure.deactivate
                      end
                      #
                    else
                      raise Exception, "Error aquiring destination database."
                    end
                  else
                    raise Exception, "Error importing source file."
                  end
                else
                  # Import the FS file into the DB as a org.gxg.file object
                  source_file = self.open(the_record[:source])
                  destination_object = self.open(the_record[:destination],{:format => "org.gxg.file"})
                  if source_file && destination_object
                    destination_object.wait_for_reservation
                    destination_object[:mime] = the_record[:mime]
                    if destination_object[:file_segments].size > 0
                      (0..(destination_object[:file_segments].size - 1)).to_a.reverse.each do |the_segment_index|
                        destination_object[:file_segments].delete_at(the_segment_index).destroy
                      end
                    end
                    GxG::apportioned_ranges(source_file.size,65536).each do |the_range|
                      source_file.seek(the_range.first)
                      destination_object[:file_segments] << GxG::ByteArray.new(source_file.read(the_range.size))
                      destination_object[:file_segments].save
                      destination_object[:file_segments].unload(destination_object[:file_segments].size - 1)
                    end
                    destination_object.release_reservation
                    destination_object.deactivate
                    source_file.close
                  else
                    if source_file
                      source_file.close
                      raise Exception, "Error opening destination object."
                    else
                      raise Exception, "Error opening source file & destination object."
                    end
                  end
                end
              rescue Exception => the_error
                log_error({:error => the_error, :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})      
                error = true
                break
              end
            end
            unless error == true
              destination[:permissions].each do |the_entry|
                self.set_permissions(destination_path, the_entry[:credential], the_entry[:permissions])
              end
              result = true
            end
          when :DB_to_FS
            file_list.each do |the_record|
              begin
                # Unless the object format is org.gxg.file --> export as .gxg_export object (formats + record)
                source_object = self.open(the_record[:source])
                database = source_object.db_address[:database]
                # check if it is an org.gxg.file for export
                current_format = nil
                if source_object.format().to_s.size > 0
                  the_format = database.format_load({:uuid => source_object.format().to_s.to_sym})
                  if the_format[:ufs].to_s == "org.gxg.file"
                    current_format = the_format[:ufs].to_s
                  end
                end
                if current_format.to_s == "org.gxg.file"
                  destination_file = self.open(the_record[:destination])
                  source_object[:file_segments].each_with_index do |the_segment, segment_index|
                    destination_file.write(the_segment.to_s)
                    source_object[:file_segments].unload(segment_index)
                    # Field no longer exists: the_segment.unload
                  end
                  source_object.release_reservation
                  source_object.deactivate
                  destination_file.close
                else
                  # Review: replace with <db>.sync_export(<uuid-array>).to_json
                  format_records = {}
                  object_record = source_object.export
                  object_record.search do |item,selector,container|
                      if selector == :format || selector == :constraint
                          if item.to_s.size > 0
                              format_uuid = item
                              unless format_records[(item.to_s.to_sym)].is_a?(::Hash)
                                  format_sample = database.format_load({:uuid => format_uuid.to_s.to_sym})
                                  format_sample[:content] = format_sample[:content].gxg_export()
                                  format_records[(format_uuid.to_s.to_sym)] = format_sample
                              end
                          end
                      end
                  end
                  buffer = GxG::ByteArray.new({:formats => format_records, :record => object_record}.to_json)
                  #
                  unless File.extname(the_record[:destination]) == ".gxg_export"
                    the_record[:destination] = (File.dirname(the_record[:destination]) + "/" + File.basename(the_record[:destination]) + ".gxg_export")
                  end
                  if self.exist?(the_record[:destination])
                    self.rmfile(the_record[:destination])
                  end
                  destination_file = self.open(the_record[:destination])
                  destination_file.write(buffer.to_s)
                  destination_file.close
                end
                #
              rescue Exception => the_error
                log_error({:error => the_error, :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})      
                error = true
                break
              end
            end
            unless error == true
              destination[:permissions].each do |the_entry|
                self.set_permissions(destination_path, the_entry[:credential], the_entry[:permissions])
              end
              result = true
            end
          when :DB_to_DB
            source_database = source[:record][:volume].database()
            destination_database = destination[:record][:volume].database()
            if source_database && destination_database
              file_list.each do |the_record|
                source_object = self.open(the_record[:source])
                current_format = nil
                if source_object.format().to_s.size > 0
                  the_format = source_database.format_load({:uuid => source_object.format().to_s.to_sym})
                  if the_format[:ufs].to_s == "org.gxg.file"
                    current_format = the_format[:ufs].to_s
                  end
                end
                #
                if source_database == destination_database
                  if current_format.to_s == "org.gxg.file"
                    import_record = {:formats => {}, :record => source_object.export({:clone => true, :exclude_file_segments => true})}
                  else
                    import_record = {:formats => {}, :record => source_object.export({:clone => true})}
                  end
                else
                  if current_format.to_s == "org.gxg.file"
                    import_record = {:formats => {}, :record => source_object.export({:exclude_file_segments => true})}
                  else
                    import_record = {:formats => {}, :record => source_object.export()}
                  end
                end
                # Gather format records for the object.
                import_record.search do |item,selector,container|
                    if selector == :format || selector == :constraint
                        if item.to_s.size > 0
                            format_uuid = item
                            unless format_records[(item.to_s.to_sym)].is_a?(::Hash)
                                format_sample = source_database.format_load({:uuid => format_uuid.to_s.to_sym})
                                format_sample[:content] = format_sample[:content].gxg_export()
                                format_records[(format_uuid.to_s.to_sym)] = format_sample
                            end
                        end
                    end
                end
                #
                enclosure_uuid = self.profile(File.dirname(the_record[:destination]))[:uuid].to_s.to_sym
                destination_uuid = import_record[:record][:uuid].to_s.to_sym
                if source_database != destination_database
                  # Import Formats first
                  if import_record[:formats].is_a?(::Hash)
                    op_frame = {:operation => :merge_format, :data => []}
                    import_record[:formats].keys.each do |the_format_key|
                      op_frame[:data] << import_record[:formats][(the_format_key)]
                    end
                    if op_frame[:data].size > 0
                      destination_database.synchronize_records([(op_frame)],destination[:record][:volume].credential())
                    end
                  end
                  #
                end
                #
                if self.exist?(the_record[:destination])
                  # Why? Because an object of the same NAME, but differing format/content may be present (unacceptable)
                  self.rmfile(the_record[:destination])
                  # Risky, but avoids situation where: diff.db, same.uuid, gets deleted, then imported to deleted object (doh!)
                  destination_database.empty_trash
                end
                #
                destination_database.synchronize_records([{:operation => :merge, :data => [(import_record[:record])]}],destination[:record][:volume].credential())
                #
                unless self.exist?(the_record[:destination])
                  the_enclosure = destination_database.retrieve_by_uuid(enclosure_uuid, destination[:record][:volume].credential())
                  the_enclosure.wait_for_reservation
                  destination_object = destination_database.retrieve_by_uuid(destination_uuid, destination[:record][:volume].credential())
                  if current_format.to_s == "org.gxg.file"
                    # copy file segments
                    destination_object.wait_for_reservation
                    source_object[:file_segments].each_with_index do |the_segment, segment_index|
                      destination_object[:file_segments] << ByteArray.new(the_segment.to_s)
                      destination_object[:file_segments].save
                      destination_object[:file_segments].unload(destination_object[:file_segments].size - 1)
                      # destination_object[:file_segments][(destination_object[:file_segments].size - 1)].save
                      # destination_object[:file_segments][(destination_object[:file_segments].size - 1)].unload
                      source_object[:file_segments].unload(segment_index)
                      # Field no longer exists : the_segment.unload
                    end
                    destination_object.release_reservation
                  end
                  the_enclosure << destination_object
                  destination_object.deactivate
                  the_enclosure.release_reservation
                  the_enclosure.deactivate
                end
                #
              end
              unless error == true
                destination[:permissions].each do |the_entry|
                  self.set_permissions(destination_path, the_entry[:credential], the_entry[:permissions])
                end
                result = true
              end
            else
              log_error({:error => Exception.new("Error aquiring source or destination database."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})      
              error = true
            end
          end
          #
        end
      else
        error = true
        log_error({:error => Exception.new("You do not have sufficient permissions."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
      end
    end
  end
  result
end
entries(the_path="", as_credential=nil) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 191
def entries(the_path="", as_credential=nil)
  result = []
  if self.valid_path?(the_path.to_s)
    if the_path.to_s == "/"
      volume_record = nil
    else
      volume_record = self.volume_of_path(the_path.to_s)
    end
    #
    if volume_record
      result = volume_record[:volume].entries(volume_record[:subpath].to_s, as_credential)
      @mounted.each do |volume_entry|
        if (volume_entry[:path].to_s).include?(the_path) && volume_entry[:path].to_s != the_path
          result << self.profile(volume_entry[:path].to_s)
        end
      end
      result = result.sort {|a,b| a[:title] <=> b[:title]}
    else
      path_table = []
      @thread_safety.synchronize {
        @mounted.reverse.each do |volume_entry|
          path_entry = volume_entry[:path].to_s.split("/")
          unless path_table.include?(path_entry)
            path_table << path_entry
          end
        end
      }
      if the_path == "/"
        offset = 1
      else
        offset = (the_path.to_s.split("/").size - 1)
      end
      #
      already = []
      path_table.each do |subpath|
        if self.path_prefix(the_path.to_s,subpath.join("/").to_s) == the_path.to_s
          if subpath[(offset)].to_s.size > 0
            unless already.include?(subpath[(offset)].to_s)
              the_profile = self.profile((the_path + "/" + subpath[(offset)].to_s).gsub("//","/"), {:with_credential => as_credential})
              if the_profile
                the_profile[:title] = (subpath[(offset)].to_s)
                the_profile[:accessed] = DateTime.now
                result << the_profile
              end
              already << subpath[(offset)].to_s
            end
          end
        end
      end
      result = result.sort {|a,b| a[:title] <=> b[:title]}
      #
    end
    #
  else
    begin
      raise Exception, "Path not found: #{the_path}"
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:path => the_path}})
    end
  end
  result
end
exist?(the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 92
def exist?(the_path="")
  self.valid_path?(the_path)
end
get_permissions(the_path="", the_credential=nil) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 96
def get_permissions(the_path="", the_credential=nil)
  result = []
  if self.valid_path?(the_path.to_s)
    if the_path.to_s == "/"
      volume_record = nil
    else
      volume_record = self.volume_of_path(the_path.to_s)
    end
    if volume_record
      result = volume_record[:volume].get_permissions(volume_record[:subpath].to_s, the_credential)
    end
  end
  result
end
mkdir(the_path="", permissions=nil) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 336
def mkdir(the_path="", permissions=nil)
  result = false
  if self.valid_path?(the_path.to_s)
    result = true
  else
    if self.valid_path?(::File::dirname(the_path.to_s))
      if the_path.to_s == "/"
        volume_record = nil
      else
        volume_record = self.volume_of_path(the_path.to_s)
      end
      if volume_record
        result = volume_record[:volume].mkdir(volume_record[:subpath].to_s, permissions)
      else
        begin
          raise Exception, "You do not have sufficient priviledges to create here.  See the mount method."
        rescue Exception => the_error
          result = false
          log_error({:error => the_error, :parameters => {:path => the_path}})
        end
      end
    else
      begin
        raise Exception, "Invalid path to new directory"
      rescue Exception => the_error
        result = false
        log_error({:error => the_error, :parameters => {:path => the_path}})
      end
    end
  end
  result
end
mkfile(the_path="", options={}) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 452
def mkfile(the_path="", options={})
  result = nil
  if self.valid_path?(the_path.to_s)
    result = self.open(the_path,options)
  else
    if self.valid_path?(::File::dirname(the_path.to_s))
      if the_path.to_s == "/"
        volume_record = nil
      else
        volume_record = self.volume_of_path(the_path.to_s)
      end
      if volume_record
        result = volume_record[:volume].open(volume_record[:subpath].to_s, options)
      else
        begin
          raise Exception, "You do not have sufficient priviledges to create here."
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
        end
      end
    else
      begin
        raise Exception, "Invalid path to new :file"
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
      end
    end
  end
  result
end
mkpath(the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 369
def mkpath(the_path="")
  result = false
  if the_path.to_s == ""
    the_path = "/"
  end
  if self.valid_path?(the_path.to_s)
    result = true
  else
    error_flag = false
    path_array = the_path.to_s.split("/")
    (0..(path_array.size - 1)).each do |indexer|
      temp_path = path_array[(0..(indexer))].join("/")
      if temp_path == ""
        temp_path = "/"
      end
      unless self.valid_path?(temp_path)
        unless self.mkdir(temp_path)
          error_flag = true
          break
        end
      end
    end
    unless error_flag
      result = true
    end
  end
  result
end
mount(the_volume = nil, the_path = "") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 1019
def mount(the_volume = nil, the_path = "")
  # Allow for a path to be mounted over the top of another - design choice
  if the_volume.is_a?(::GxG::Storage::Volume)
    @thread_safety.synchronize { @mounted << {:volume => the_volume, :path => ::Pathname.new(the_path.to_s)} }
    true
  else
    @mounted
  end
end
mounted?(the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 1029
def mounted?(the_path="")
  result = false
  @thread_safety.synchronize {
    @mounted.reverse.each do |entry|
      if entry[:path] == the_path
        result = true
        break
      end
    end
  }
  result
end
move(source_path=nil, destination_path=nil, options={}) click to toggle source

Moving support

# File lib/gxg/gxg_dbfs.rb, line 907
def move(source_path=nil, destination_path=nil, options={})
  result = false
  error = false
  if source_path == destination_path
    error = true
  end
  #
  source = {:enclosure => nil, :profile => nil, :record => nil}
  if self.valid_path?(source_path.to_s)
    if source_path.to_s == "/"
      source[:record] = nil
    else
      source[:record] = self.volume_of_path(source_path.to_s)
    end
    if source[:record]
      source[:profile] = self.profile(source_path,options.merge({:follow_symlinks => true}))
      source[:enclosure] = self.profile(File.dirname(source_path),options.merge({:follow_symlinks => true}))
    else
      error = true
      log_error({:error => Exception.new("You do not have sufficient priviledges."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
    end
  else
    error = true
    log_error({:error => Exception.new("Invalid source path"), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
  end
  # Note: if destination is not full path, but path to its future enclosure, append the filename to fully qualify the destination_path
  if File.basename(source_path) != File.basename(destination_path)
    destination_path = File.expand_path(destination_path + "/" + File.basename(source_path))
  end
  #
  destination = {:enclosure => self.profile(File.dirname(destination_path),options.merge({:follow_symlinks => true})), :profile => nil, :record => nil}
  if self.valid_path?(destination_path.to_s)
    if destination_path.to_s == "/"
      destination[:record] = nil
    else
      destination[:record] = self.volume_of_path(destination_path.to_s)
    end
    if destination[:record]
      destination[:profile] = self.profile(destination_path,options.merge({:follow_symlinks => true}))
    else
      error = true
      log_error({:error => Exception.new("You do not have sufficient permissions."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
    end
  else
    if destination[:enclosure].is_a?(::Hash)
      unless destination[:enclosure][:permissions][:effective][:create] == true
        error = true
        log_error({:error => Exception.new("You do not have sufficient permissions to create at destination."), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
      end
      unless error == true
        destination[:record] = self.volume_of_path(File.dirname(destination_path))
        if destination[:record].is_a?(::Hash)
          # Note: this won't exist yet, but is here for future reference.
          destination[:record][:subpath] = (destination[:record][:subpath] + "/" + File.basename(destination_path))
        end
      end
    else
      error = true
      log_error({:error => Exception.new("Invalid destination path"), :parameters => {:source_path => source_path, :destination_path => destination_path, :options => options}})
    end
  end
  #
  unless error == true
    if source[:record][:volume].file_system?()
      if destination[:enclosure][:uuid].to_s.size > 0
        scenario = :FS_to_DB
      else
        scenario = :FS_to_FS
      end
    else
      if destination[:enclosure][:uuid].to_s.size > 0
        scenario = :DB_to_DB
      else
        scenario = :DB_to_FS
      end
    end
    if scenario == :DB_to_DB && (source[:record][:volume].database() == destination[:record][:volume].database())
      database = source[:record][:volume].database()
      source_enclosure = database.retrieve_by_uuid(source[:enclosure][:uuid].to_s.to_sym, source[:record][:volume].credential())
      source_enclosure.wait_for_reservation
      destination_enclosure = database.retrieve_by_uuid(destination[:enclosure][:uuid].to_s.to_sym, source[:record][:volume].credential())
      destination_enclosure.wait_for_reservation
      #
      source_enclosure.each_index do |the_index|
        if source_enclosure[(the_index)].uuid().to_s.to_sym == source[:profile][:uuid].to_s.to_sym
          destination_enclosure << source_enclosure.delete_at(the_index)
          break
        else
          source_enclosure[(the_index)].deactivate
        end
      end
      source_enclosure.release_reservation
      destination_enclosure.release_reservation
      source_enclosure.deactivate
      destination_enclosure.deactivate
      result = true
    else
      # copy to destination_path
      if self.copy(source_path, destination_path, options) == true
        # delete source_path object
        if ["directory","persisted_array"].include?(source[:profile][:type].to_s)
          result = self.rmdir(source_path)
        else
          result = self.rmfile(source_path)
        end
      end
    end
  end
  #
  result
end
open(the_path="", options={}) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 398
def open(the_path="", options={})
  result = nil
  if self.valid_path?(the_path.to_s)
    if the_path.to_s == "/"
      volume_record = nil
    else
      volume_record = self.volume_of_path(the_path.to_s)
    end
    if volume_record
      result = volume_record[:volume].open(volume_record[:subpath].to_s, options)
    else
      begin
        raise Exception, "You do not have sufficient priviledges to open here."
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
      end
    end
  else
    begin
      raise Exception, "Invalid path"
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
    end
  end
  result
end
path_prefix(src_path="", the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 24
def path_prefix(src_path="", the_path="")
  result = ""
  src_path.each_char do |the_char|
    if the_char == the_path[0]
      the_path = the_path[(1..-1)]
      result << the_char
    else
      break
    end
  end
  result
end
profile(the_path="",params=nil) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 142
def profile(the_path="",params=nil)
  result = nil
  if self.valid_path?(the_path.to_s)
    if the_path.to_s == "/"
      volume_record = nil
    else
      volume_record = self.volume_of_path(the_path.to_s)
    end
    if volume_record
      if volume_record[:subpath].to_s.size > 0
        if params
            result = volume_record[:volume].profile(volume_record[:subpath].to_s,params)
        else
            result = volume_record[:volume].profile(volume_record[:subpath].to_s)
        end
        result[:title] = (the_path.split("/").last.to_s)
      else
        # VFS
        if params
            base_profile = volume_record[:volume].profile(volume_record[:subpath].to_s,params)
        else
            base_profile = volume_record[:volume].profile(volume_record[:subpath].to_s)
        end
        if base_profile
          result = {:title => "", :type => :virtual_directory, :owner_type => :virtual_directory, :uuid => nil, :on_device => nil, :on_device_major => nil, :on_device_minor => nil, :is_device => nil, :is_device_major => nil, :is_device_minor => nil, :inode => nil, :flags => [:read], :hardlinks_to => 0, :user_id => nil, :group_id => nil, :size => 0, :block_size => 0, :blocks => 0, :accessed => nil, :modified => nil, :status_modified => nil, :permissions => {:effective => {:execute => true, :rename => false, :move => false, :destroy => false, :create => false, :write => false, :read=>true}}, :mode=>nil}
          result[:title] = (the_path.split("/").last.to_s)
          result[:accessed] = DateTime.now
          if base_profile[:permissions][:effective][:write]
            result[:permissions][:effective][:write] = true
            result[:permissions][:effective][:create] = true
          end
        end
      end
    else
      # VFS Other
      result = {:title => "", :type => :virtual_directory, :owner_type => :virtual_directory, :uuid => nil, :on_device => nil, :on_device_major => nil, :on_device_minor => nil, :is_device => nil, :is_device_major => nil, :is_device_minor => nil, :inode => nil, :flags => [:read], :hardlinks_to => 0, :user_id => nil, :group_id => nil, :size => 0, :block_size => 0, :blocks => 0, :accessed => nil, :modified => nil, :status_modified => nil, :permissions => {:effective => {:execute => true, :rename => false, :move => false, :destroy => false, :create => false, :write => false, :read=>true}}, :mode=>nil}
      result[:title] = (the_path.split("/").last.to_s)
      result[:accessed] = DateTime.now
    end
  else
    begin
      raise Exception, "Path not found: #{the_path}"
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:path => the_path}})
    end         
  end
  result
end
rename(the_path="", new_name="", options={}) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 425
def rename(the_path="", new_name="", options={})
  result = false
  if self.valid_path?(the_path.to_s)
    if the_path.to_s == "/"
      volume_record = nil
    else
      volume_record = self.volume_of_path(the_path.to_s)
    end
    if volume_record
      result = volume_record[:volume].rename(volume_record[:subpath].to_s, new_name, options)
    else
      begin
        raise Exception, "You do not have sufficient priviledges to rename here."
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
      end
    end
  else
    begin
      raise Exception, "Invalid path"
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
    end
  end
  result
end
revoke_permissions(the_path="", the_credential=nil) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 111
def revoke_permissions(the_path="", the_credential=nil)
  result = false
  if self.valid_path?(the_path.to_s)
    if the_path.to_s == "/"
      volume_record = nil
    else
      volume_record = self.volume_of_path(the_path.to_s)
    end
    if volume_record
      result = volume_record[:volume].revoke_permissions(volume_record[:subpath].to_s, the_credential)
    end
  end
  result
end
rmdir(the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 254
def rmdir(the_path="")
  result = false
  if self.valid_path?(the_path.to_s)
    begin
      if the_path.to_s == "/"
        raise Exception, "You do not have destroy permissions here"
      else
        volume_record = self.volume_of_path(the_path.to_s)
      end
      if volume_record
        the_profile = self.profile(the_path.to_s)
        if the_profile
          if the_profile[:permissions][:effective][:destroy]
            if [:virtual_directory, :directory, :persisted_array].include?(the_profile[:type])
              result = volume_record[:volume].rmdir(volume_record[:subpath].to_s)
            else
              raise Exception, "Not a directory"
            end
          else
            raise Exception, "You do not have destroy permissions here. See unmount method."
          end
        else
          raise Exception, "Invalid path"
        end
        #
      else
        raise Exception, "Invalid path"
      end
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:path => the_path}})
    end
  else
    begin
      raise Exception, "Invalid path"
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:path => the_path}})
    end
  end
  result
end
rmfile(the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 295
def rmfile(the_path="")
  result = false
  if self.valid_path?(the_path.to_s)
    begin
      if the_path.to_s == "/"
        raise Exception, "You do not have destroy permissions here"
      else
        volume_record = self.volume_of_path(the_path.to_s)
      end
      if volume_record
        the_profile = self.profile(the_path.to_s)
        if the_profile
          if the_profile[:permissions][:effective][:destroy]
            if [:virtual_directory, :directory, :persisted_array].include?(the_profile[:type])
              raise Exception, "Not a valid :file or :persisted_hash"
            else
              result = volume_record[:volume].rmfile(volume_record[:subpath].to_s)
            end
          else
            raise Exception, "You do not have destroy permissions here. See unmount method."
          end
        else
          raise Exception, "Invalid path"
        end
        #
      else
        raise Exception, "Invalid path"
      end
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:path => the_path}})
    end
  else
    begin
      raise Exception, "Invalid path"
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:path => the_path}})
    end
  end
  result
end
set_permissions(the_path="", the_credential=nil, the_permissions={}) click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 127
def set_permissions(the_path="", the_credential=nil, the_permissions={})
    result = false
    if self.valid_path?(the_path.to_s)
      if the_path.to_s == "/"
        volume_record = nil
      else
        volume_record = self.volume_of_path(the_path.to_s)
      end
      if volume_record
        result = volume_record[:volume].set_permissions(volume_record[:subpath].to_s, the_credential, the_permissions)
      end
    end
    result
end
subpath(src_path="", the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 11
def subpath(src_path="", the_path="")
  if src_path == "/"
    the_path
  else
    src_path.each_char do |the_char|
      if the_char == the_path[0]
        the_path = the_path[(1..-1)]
      end
    end
    the_path
  end
end
unmount(the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 1042
def unmount(the_path="")
  # Allow for a path to be mounted over the top of another - design choice
  result = nil
  @thread_safety.synchronize {
    if @mounted.size > 0
      (0..(@mounted.size - 1)).to_a.reverse.each do |indexer|
        if the_path.to_s == (@mounted[(indexer)][:path].to_s)
          result = @mounted[(indexer)][:volume]
          @mounted.delete_at(indexer)
          break
        end
      end
    end
  }
  # returns the volume object for proper closing
  result
end
valid_path?(the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 50
def valid_path?(the_path="")
  result = false
  if the_path.to_s == "/"
    result = true
  else
    # VFS check
    path_table = []
    @thread_safety.synchronize {
        @mounted.reverse.each do |volume_entry|
        path_entry = volume_entry[:path].to_s.split("/")
        unless path_table.include?(path_entry)
          path_table << path_entry
        end
      end
    }
    path_array = the_path.to_s.split("/")
    vfs_check = false
    path_table.each do |entry|
      (0..(path_array.size - 1)).each do |indexer|
        if entry == (path_array[(0..(indexer))])
          vfs_check = true
          break
        end
      end
      if vfs_check
        break
      end
    end
    # volume check
    if vfs_check
      volume_record = self.volume_of_path(the_path.to_s)
      if volume_record
        result = volume_record[:volume].exist?(volume_record[:subpath].to_s)
      else
        result = true
      end
    end
    #
  end
  result
end
volume_of_path(the_path="") click to toggle source
# File lib/gxg/gxg_dbfs.rb, line 37
def volume_of_path(the_path="")
  result = nil
  @thread_safety.synchronize {
    @mounted.reverse.each do |volume_entry|
      if self.path_prefix(volume_entry[:path].to_s,the_path.to_s) == (volume_entry[:path].to_s)
        result = {:volume => volume_entry[:volume], :subpath => self.subpath(volume_entry[:path].to_s, the_path.to_s) }
        break
      end
    end
  }
  result
end