# 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