# class GxG::Storage::Volume

### Public Class Methods

new(options={}) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1498
    def initialize(options={})
      # options: :directory => "/path/to/dir", :credential => <UUID>.to_s, :act_as => :owner? || :database => <GxG::Database::Database>, :credential => <UUID>.to_s, :root_uuid => <UUID>.to_s
      @thread_safety = ::Mutex.new
      @credential = GxG::DB[:administrator].to_s
      @database = nil
      @root_uuid = nil
      # Acts As: :owner, :group, :other for File System Volumes
      if [:owner, :group, :other].include?(options[:act_as])
        @act_as = options[:act_as]
      else
        @act_as = nil
      end
      @directory = options[:directory]
      if @directory.to_s.size > 0
        if ::GxG::valid_uuid?(options[:credential].to_s.to_sym)
          unless @act_as
            # set @act_as according to credential Group/Role membership: Administrators=:owner, Developers/Designers=:group, all others=:other
            if GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:administrators], options[:credential].to_s.to_sym)
              @act_as = :owner
            else
              if GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:developers].to_s.to_sym, options[:credential].to_s.to_sym) || GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:designers].to_s.to_sym, options[:credential].to_s.to_sym)
                @act_as = :group
              else
                @act_as = :other
              end
            end
          end
        end
        if ::Dir.exist?(@directory.to_s)
          if ::File.readable_real?(@directory.to_s)
            @directory = ::Dir.new(@directory.to_s)
          else
            raise Exception, "You do not have read permissions to directory #{@directory.inspect}."
          end
        else
          raise Exception, "Directory #{@directory.inspect} does not exist in the filesystem."
        end
        #
      else
        @credential = (options[:credential] || GxG::DB[:administrator]).to_s
        if options[:database].is_a?(::GxG::Database::Database) and @credential.size > 0
          @database = options[:database]
          if @database.setting_keys.include?(:volume_information)
            vol_info = @database[:volume_information]
          else
            if @database.db_permissions()[:write]
              new_root = @database.try_persist([], @credential)
              if new_root
                new_root.wait_for_reservation()
                new_root.set_title("Volume Root")
                vol_info = {:volume_root => new_root.uuid()}
                new_root.deactivate
                @database[:volume_information] = vol_info
              else
                raise Exception, "Unable to initialize volume root"
              end
            else
              raise Exception, "Cannot initialize Volume Information on read-only database."
            end
          end
          # One can specify a sub-array to the volume as this volume's root array.
          if GxG::valid_uuid?(options[:root_uuid].to_s)
              # verify array's existence
              the_persisted_array = @database.retrieve_by_uuid(options[:root_uuid], @credential)
              if the_persisted_array.is_a?(::GxG::Database::PersistedArray)
                  the_persisted_array.deactivate
                  @root_uuid = options[:root_uuid].to_s.to_sym
              else
                  raise Exception, "The root_uuid points to a non-existent or invalid object, or you do not have permissions to read it."
              end
              #
          else
              @root_uuid = vol_info[:volume_root].to_sym
          end
        else
          raise ArgumentError, "You MUST supply a valid credential and a database object.  :credential => #{@credential.inspect}, :database => #{options[:database].inspect}"
        end
      end
      #
    end

### Public Instance Methods

credential() click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1069
    def credential()
      @credential
    end

database() click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1073
    def database()
      @database
    end

db_path(subpath="") click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1089
    def db_path(subpath="")
      result = nil
      unless subpath.to_s[0] == "/"
        subpath = ("/" << subpath.to_s)
      end
      subpath_array = subpath.to_s.split("/")
      if subpath_array.size == 0
        subpath_array << "Volume Root"
      else
        subpath_array[0] = "Volume Root"
      end
      path_array = [{:uuid => @root_uuid, :title => "Volume Root"}]
      subpath_array.each_with_index do |the_entry, indexer|
        parent_uuid = path_array.last[:uuid]
        #
        @database.connector()[:array_elements].filter({:parent_uuid => parent_uuid.to_s}).order(:ordinal).each do |item|
          if [:element_array, :element_hash].include?(item[:element].to_s.to_sym)
            if item[:element].to_s.to_sym == :element_array
              record = @database.connector()[:element_array].filter({:uuid => item[:element_array_uuid].to_s}).first
            else
              record = @database.connector()[:element_hash].filter({:uuid => item[:element_hash_uuid].to_s}).first
            end
            if record
              if record[:title] == subpath_array[(indexer + 1)].to_s
                path_array << {:uuid => record[:uuid].to_sym, :title => record[:title]}
                break
              end
            end
          end
        end
        #
      end
      if path_array.size == subpath_array.size
        result = path_array
      end
      result
    end

directory() click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1077
    def directory()
      @directory
    end

entries(subpath="", as_credential=nil, options={:follow_symlinks => true}) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1579
    def entries(subpath="", as_credential=nil, options={:follow_symlinks => true})
      results = []
      if @directory
        # FS
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        ::Dir::entries(the_path).each do |item|
          unless [".", ".."].include?(item)
            if as_credential
              the_profile = self.profile((subpath + "/" + item), options.merge({:with_credential => as_credential}))
            else
              the_profile = self.profile((subpath + "/" + item), options)
            end
            if the_profile
              the_profile[:title] = item
              results << the_profile
            end
          end
        end
        #
      else
        # DB
        unless subpath.to_s[0] == "/"
          subpath = ("/" << subpath.to_s)
        end
        path_array = self.db_path(subpath.to_s)
        if path_array
          base_profile = self.profile(subpath.to_s, {:with_credential => as_credential})
          if base_profile
            if base_profile[:permissions][:effective][:read]
              if base_profile[:type] == :persisted_array
                object_details = {:uuid => path_array.last[:uuid], :table => :unspecified, :dbid => 0}
                header = @database.connector()[:element_array].filter({:uuid => object_details[:uuid].to_s}).first
                if header
                  object_details[:table] = :element_array
                  object_details[:dbid] = header[:dbid]
                end
                contained_titles = []
                @database.connector()[:array_elements].select(:element_hash_uuid, :element_array_uuid).where({:parent_uuid => path_array.last[:uuid].to_s}).each do |link_record|
                  if link_record[:element_hash_uuid].to_s.size > 0
                    header = @database.connector()[:element_hash].filter({:uuid => link_record[:element_hash_uuid].to_s}).first
                    if header
                      contained_titles << header[:title].to_s
                    end
                  else
                    if link_record[:element_array_uuid].to_s.size > 0
                      header = @database.connector()[:element_array].filter({:uuid => link_record[:element_array_uuid].to_s}).first
                      if header
                        contained_titles << header[:title].to_s
                      end
                    end
                  end
                end
                contained_titles.sort.each do |the_title|
                  if the_title.size > 0
                    results << self.profile((subpath.to_s + "/" + the_title).gsub("//","/"), {:with_credential => as_credential})
                  end
                end
              end
            end
          end
        end
      end
      results
    end

exist?(subpath="") click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1127
    def exist?(subpath="")
      result = false
      if @directory
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        result = ::File::exist?(the_path)
      else
        # DB object exist?
        if self.db_path(subpath)
          result = true
        end
      end
      result
    end

file_system?() click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1081
    def file_system?()
      if self.directory()
        true
      else
        false
      end
    end

get_permissions(subpath="", the_credential=nil) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 2359
    def get_permissions(subpath="", the_credential=nil)
      result = []
      if @directory
        if self.exist?(subpath)
          the_profile = self.profile(subpath)
          if the_profile[:file_id]
            result = GxG::DB[:roles][:vfs].vfs_permission_manifest(the_profile[:file_id], the_credential)
          end
          # ????
          # xxx
          # group_roles = GxG::DB[:authority][:system_credentials]
          # the_record = {:credential => group_roles[:administrators], :permissions => the_profile[:permissions][:owner], :details => {}}
          # role = GxG::DB[:authority].role_fetch({:uuid => the_record[:credential].to_s})
          # group = GxG::DB[:authority].group_fetch({:uuid => role[:group_uuid].to_s})
          # the_record[:details][:role_title] = role[:title]
          # the_record[:details][:group] = group[:uuid].to_s.to_sym
          # the_record[:details][:group_title] = group[:title]
          # result << the_record
          # the_record = {:credential => group_roles[:developers], :permissions => the_profile[:permissions][:group], :details => {}}
          # role = GxG::DB[:authority].role_fetch({:uuid => the_record[:credential].to_s})
          # group = GxG::DB[:authority].group_fetch({:uuid => role[:group_uuid].to_s})
          # the_record[:details][:role_title] = role[:title]
          # the_record[:details][:group] = group[:uuid].to_s.to_sym
          # the_record[:details][:group_title] = group[:title]
          # result << the_record
          # the_record = {:credential => group_roles[:designers], :permissions => the_profile[:permissions][:group], :details => {}}
          # role = GxG::DB[:authority].role_fetch({:uuid => the_record[:credential].to_s})
          # group = GxG::DB[:authority].group_fetch({:uuid => role[:group_uuid].to_s})
          # the_record[:details][:role_title] = role[:title]
          # the_record[:details][:group] = group[:uuid].to_s.to_sym
          # the_record[:details][:group_title] = group[:title]
          # result << the_record
          # the_record = {:credential => :"00000000-0000-4000-0000-000000000000", :permissions => the_profile[:permissions][:other], :details => {}}
          # user = GxG::DB[:authority].user_fetch({:uuid => the_record[:credential].to_s})
          # the_record[:details][:user_title] = user[:user_id]
          # result << the_record
        end
      else
        if self.exist?(subpath)
          the_profile = self.profile(subpath)
          result = @database.element_permissions_by_uuid(the_profile[:uuid])
        end
      end
      result
    end

inspect() click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1065
    def inspect()
      "<Volume: #{(@database || @directory).inspect}>"
    end

mkdir(subpath="", permissions=nil) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 2233
    def mkdir(subpath="", permissions=nil)
      result = false
      if @directory
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        perm = 16384
        if permissions.is_a?(::Hash)
          # Best if you pass the entire :permissions hash from a profile query
          "040000".each_char_with_index do |digit, indexer|
            case indexer
            when 0
            when 1
              # TODO: process other flags
            when 2
            when 3
              if permissions[:owner].is_a?(::Hash)
                if permissions[:owner][:execute]
                  perm += 256
                end
                if permissions[:owner][:write]
                  perm += 128
                end
                if permissions[:owner][:read]
                  perm += 64
                end
              end
            when 4
              if permissions[:group].is_a?(::Hash)
                if permissions[:group][:execute]
                  perm += 32
                end
                if permissions[:group][:write]
                  perm += 16
                end
                if permissions[:group][:read]
                  perm += 8
                end
              end
            when 5
              if permissions[:other].is_a?(::Hash)
                if permissions[:other][:execute]
                  perm += 4
                end
                if permissions[:other][:write]
                  perm += 2
                end
                if permissions[:other][:read]
                  perm += 1
                end
              end
            end
          end
          #
        else
          base_profile = self.profile("/")
          if base_profile.is_a?(::Hash)
            if base_profile[:mode].is_a?(::String)
              perm = base_profile[:mode].to_i(base=8)
            else
              perm = 16877
            end
          else
            perm = 16877
          end
        end
        # FS mkdir
        begin
          parent_profile = self.profile(::File::dirname(subpath.to_s))
          if parent_profile
            if parent_profile[:permissions][:effective][:create]
              if ::File::exist?(the_path)
                result = true
              else
                if ::Dir::mkdir(the_path, perm) == 0
                  # Generate VFS-DB permissions, return result
                  self.profile(subpath)
                  result = true
                end
              end
            else
              raise Exception, "You do not have create permissions here"
            end
          else
            raise Exception, "Invalid path"
          end
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {:path => the_path, :permissions => permissions}})
          #
        end
      else
        # DB dir create
        begin
          parent_profile = self.profile(::File::dirname(subpath.to_s))
          if parent_profile
            if parent_profile[:permissions][:effective][:create] == true
              new_object = @database.try_persist([], @credential)
              new_object.wait_for_reservation
              new_object.set_title(::File::basename(subpath.to_s))
              # ### Fashion a link under the parent uuid.
              new_ordinal = @database.connector()[:array_elements].filter({:parent_uuid => parent_profile[:uuid].to_s}).count
              @database.connector()[:array_elements].insert({:parent_uuid => parent_profile[:uuid].to_s, :version => new_object.version(), :ordinal => new_ordinal, :element => "element_array", :element_array_uuid => new_object.uuid.to_s})
              # ### Wrap up and return new object
              new_object.release_reservation
              result = true
            else
              raise Exception, "You do not have create permissions here"
            end
          else
            raise Exception, "Invalid path"
          end
          #
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {:path => subpath, :permissions => permissions}})
          #
        end
        #
      end
      result
    end

open(subpath="", options={}) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1974
    def open(subpath="", options={})
      result = nil
      if @directory
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        flags = 0
        flag_array = (options[:flags] || [:readwrite])
        flag_array.each do |the_flag|
          case the_flag
          when :append
            flags += ::File::APPEND
          when :binary
            flags += ::File::BINARY
          when :create
            flags += ::File::CREAT
          when :direct
            flags += ::File::DIRECT
          when :dsync
            flags += ::File::DSYNC
          when :duplex
            flags += ::File::DUPLEX
          when :exclusive
            flags += ::File::EXCL
          when :casefold
            flags += ::File::FNM_CASEFOLD
          when :dotmatch
            flags += ::File::FNM_DOTMATCH
          when :no_escape
            flags += ::File::FNM_NOESCAPE
          when :pathname
            flags += ::File::FNM_PATHNAME
          when :system_case
            flags += ::File::FNM_SYSCASE
          when :lock_ex
            flags += ::File::LOCK_EX
          when :lock_nb
            flags += ::File::LOCK_NB
          when :lock_sh
            flags += ::File::LOCK_SH
          when :lock_un
            flags += ::File::LOCK_UN
          when :no_atime
            flags += ::File::NOATIME
          when :no_ctty
            flags += ::File::NOCTTY
          when :no_follow
            flags += ::File::NOFOLLOW
          when :nonblock
            flags += ::File::NONBLOCK
          when :read
            flags += ::File::RDONLY
          when :rsync
            flags += ::File::RSYNC
          when :seek_cur
            flags += ::File::SEEK_CUR
          when :seek_end
            flags += ::File::SEEK_END
          when :seek_set
            flags += ::File::SEEK_SET
          when :setenc_by_bom
            flags += ::File::SETENC_BY_BOM
          when :sync
            flags += ::File::SYNC
          when :text
            flags += ::File::TEXT
          when :truncate
            flags += ::File::TRUNC
          when :tty
            flags += ::File::TTY
          when :write
            flags += ::File::WRONLY
          when :readwrite
            flags += ::File::RDWR
          when :wsplit
            flags += ::File::WSPLIT
          when :wsplit_initialized
            flags += ::File::WSPLIT_INITIALIZED
          end
        end
        perm = 16384
        permissions = options[:permissions]
        if permissions.is_a?(::Hash)
          # Best if you pass the entire :permissions hash from a profile query
          "040000".each_char_with_index do |digit, indexer|
            case indexer
            when 0
            when 1
              # TODO: process other flags
            when 2
            when 3
              if permissions[:owner].is_a?(::Hash)
                if permissions[:owner][:execute]
                  perm += 256
                end
                if permissions[:owner][:write]
                  perm += 128
                end
                if permissions[:owner][:read]
                  perm += 64
                end
              end
            when 4
              if permissions[:group].is_a?(::Hash)
                if permissions[:group][:execute]
                  perm += 32
                end
                if permissions[:group][:write]
                  perm += 16
                end
                if permissions[:group][:read]
                  perm += 8
                end
              end
            when 5
              if permissions[:other].is_a?(::Hash)
                if permissions[:other][:execute]
                  perm += 4
                end
                if permissions[:other][:write]
                  perm += 2
                end
                if permissions[:other][:read]
                  perm += 1
                end
              end
            end
          end
          #
        else
          base_profile = self.profile("/")
          if base_profile.is_a?(::Hash)
            if base_profile[:mode].is_a?(::String)
              perm = (base_profile[:mode][0..2].to_s + "644").to_i(base=8)
            else
              perm = 16804
            end
          else
            perm = 16804
          end
        end
        # FS
        begin
          parent_profile = self.profile(::File::dirname(subpath.to_s))
          if parent_profile
            if ::File::exist?(the_path)
              if ::File::directory?(the_path)
                result = ::Dir::new(the_path)
              else
                if flag_array.include?(:read)
                  unless parent_profile[:permissions][:effective][:read]
                    raise Exception, "You do not have read permissions here."
                  end
                end
                if flag_array.include?(:write)
                  unless parent_profile[:permissions][:effective][:write]
                    raise Exception, "You do not have write permissions here."
                  end
                end
                if flag_array.include?(:readwrite)
                  unless parent_profile[:permissions][:effective][:read]
                    raise Exception, "You do not have read permissions here."
                  end
                  unless parent_profile[:permissions][:effective][:write]
                    raise Exception, "You do not have write permissions here."
                  end
                end
                if ::GxG::Engine::available_file_descriptors() > 0
                  result = ::File::open(the_path, flags)
                else
                  raise Exception, "Maximum File Descriptor count exceeded. Aborting"
                end
              end
            else
              if parent_profile[:permissions][:effective][:create]
                if ::GxG::Engine::available_file_descriptors() > 0
                  ::File::new(the_path, "w", perm).close
                  result = ::File::open(the_path, flags)
                  # Generate VFS-DB permissions, return result
                  self.profile(subpath)
                else
                  raise Exception, "Maximum File Descriptor count exceeded. Aborting"
                end
              else
                raise Exception, "You do not have create permissions here"
              end
            end
          else
            raise Exception, "Invalid path"
          end
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
          #
        end
      else
        # DB open/create :persisted_hash
        begin
          path_array = self.db_path(subpath.to_s)
          if path_array
            profile = self.profile(subpath.to_s)
            if profile[:permissions][:effective][:read]
              result = @database.retrieve_by_uuid(path_array.last[:uuid], @credential)
            else
              # Review : keep? this breaks the 'if you don't have privs you can't see it - no errors, security through obscurity' idea.
              raise Exception, "You do not have read permissions on this object"
            end
          else
            parent_profile = self.profile(::File::dirname(subpath.to_s))
            if parent_profile
              if parent_profile[:permissions][:effective][:create] == true
                if options[:format]
                  if GxG::valid_uuid?(options[:format])
                    new_object = @database.new_structure_from_format(@credential,{:uuid => options[:format]})
                  else
                    new_object = @database.new_structure_from_format(@credential,{:ufs => options[:format]})
                  end
                else
                  if options[:ufs]
                    new_object = @database.new_structure_from_format(@credential,{:ufs => options[:ufs]})
                  else
                    new_object = @database.try_persist({}, @credential)
                  end
                end
                # ### allow to create the object with a specific UUID.
                if ::GxG::valid_uuid?(options[:with_uuid])
                  address = new_object.db_address()
                  new_object.deactivate
                  @database.connector()[(address[:table])].filter({:dbid => address[:dbid]}).first.update({:uuid => options[:with_uuid].to_s})
                  new_object = @database.retrieve_by_uuid(options[:with_uuid].to_s.to_sym, @credential)
                end
                #
                new_object.wait_for_reservation
                new_object.set_title(::File::basename(subpath.to_s))
                # ### Fashion a link under the parent uuid.
                new_ordinal = @database.connector()[:array_elements].filter({:parent_uuid => parent_profile[:uuid].to_s}).count
                @database.connector()[:array_elements].insert({:parent_uuid => parent_profile[:uuid].to_s, :version => new_object.version(), :ordinal => new_ordinal, :element => "element_hash", :element_hash_uuid => new_object.uuid.to_s})
                # ### Wrap up and return new object
                new_object.release_reservation
                result = new_object
              else
                raise Exception, "You do not have create permissions here"
              end
              #
            else
              raise Exception, "Invalid path"
            end
          end
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
        end
      end
      result
    end

profile(subpath="",params={:follow_symlinks => true}) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1148
    def profile(subpath="",params={:follow_symlinks => true})
      unless params.is_a?(::Hash)
        params = {:follow_symlinks => true}
      end
      unless params[:follow_symlinks]
        unless params.keys.include?(:follow_symlinks)
          params[:follow_symlinks] = true
        end
      end
      platform_details = GxG::SYSTEM.platform()
      result = {:title => "", :type => :unspecified, :owner_type => :unspecified, :uuid => nil, :version => 0.0, :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 => false, :rename => false, :move => false, :destroy => false, :create => false, :write => false, :read=>false}}, :mode=>nil, :mime => nil}
      if @directory
        # return FS object profile
        result[:title] = (subpath.split("/").last.to_s)
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        if params[:follow_symlinks]
          raw_stat = ::File::stat(the_path.to_s)
        else
          raw_stat = ::File::lstat(the_path.to_s)
        end
        raw_mode = raw_stat.mode.to_s(base=8)
        # puts "Got: #{raw_mode}"
        if raw_mode.size < 6
          raw_mode = ("0" << raw_mode)
        end
        # puts "Then Got: #{raw_mode}"
        set_user_id = false
        set_group_id = false
        set_sticky_bit = false
        if (raw_mode[2].to_i & 4) == 4
          set_user_id = true
        end
        if (raw_mode[2].to_i & 2) == 2
          set_group_id = true
        end
        if (raw_mode[2].to_i & 1) ==  1
          set_sticky_bit = true
        end
        raw_permission = { :execute => false, :rename => false, :move => false, :destroy => false, :create => false, :write => false, :read => false }
        case raw_stat.ftype.to_s.downcase.to_sym
        when :link
          # are .lnk files handled properly on win32 for this?
          result[:type] =  :symlink
        when :file
           the_extension = ::File::basename(the_path.to_s).split(".")[-1].to_s.downcase
           if the_extension == "lnk"
             result[:type] =  :symlink
           else
             if ["so","la","a","dylib","dll","class"].include?(the_extension)
               result[:type] =  :library
             else
               if (["out","exe","misc","java","jar", "sh", "rb", "py", "pyc"].include?(the_extension) || raw_stat.executable_real?)
                 result[:type] =  :application
               else
                 # TODO: find a way to externally sense if a tty
                 result[:type] = :file
               end
             end
           end
         when :fifo
           result[:type] =  :fifo
         when :characterspecial
           result[:type] =  :character_device
         when :blockspecial
           result[:type] =  :block_device
         when :socket
           result[:type] =  :socket
         when :directory
           result[:type] =  :directory
         when :unknown
           result[:type] =  :unknown
           if raw_stat.pipe?
             result[:type] =  :pipe
           end
        else
           if raw_stat.pipe?
             result[:type] =  :pipe
           end
        end
        #
        result[:owner_type] = result[:type]
        result[:on_device] = raw_stat.dev.to_s(base=10).to_i
        if result[:on_device]
          result[:on_device_major] = raw_stat.dev_major
          result[:on_device_minor] = raw_stat.dev_minor
        end
        result[:is_device] = raw_stat.rdev
        if result[:is_device]
          result[:is_device_major] = raw_stat.rdev_major
          result[:is_device_minor] = raw_stat.rdev_minor
        end
        result[:inode] = raw_stat.ino.to_i
        # ### :file_id
        result[:file_id] = "#{(result[:on_device] || 0).to_s}-#{(result[:on_device_major] || 0).to_s}-#{(result[:on_device_minor] || 0).to_s}-#{(result[:inode] || 0).to_s}"
        result[:flags] = []
        if ::File::writable_real?(the_path.to_s)
          result[:flags] << :write
        end
        if ::File::readable_real?(the_path.to_s)
          result[:flags] << :read
        end
        #
        result[:hardlinks_to] = raw_stat.nlink.to_i
        result[:user_id] = raw_stat.uid.to_i
        result[:group_id] = raw_stat.gid.to_i
        result[:size] = raw_stat.size
        result[:block_size] = raw_stat.blksize
        result[:blocks] = raw_stat.blocks
        result[:version] = raw_stat.mtime.to_f
        result[:accessed] = DateTime::parse(raw_stat.atime.to_s)
        result[:modified] = DateTime::parse(raw_stat.mtime.to_s)
        result[:status_modified] = DateTime::parse(raw_stat.ctime.to_s)
        # File permissions work in an ACL style, even if based only upon Unix-style permissions.
        #
        result[:permissions] = {:effective => raw_permission.clone, :owner => raw_permission.clone, :group => raw_permission.clone, :other => raw_permission.clone}
        if set_user_id
          result[:flags] << :user_id_on_execute
        end
        if set_group_id
          result[:flags] << :group_id_on_execute
        end
        if set_sticky_bit
          result[:flags] << :sticky_bit
        end
        #
        # owner permissions
        if (raw_mode[3].to_i & 4) == 4
          result[:permissions][:owner][:read] = true
        end
        if (raw_mode[3].to_i & 2) == 2
          result[:permissions][:owner][:write] = true
          if platform_details[:platform] == :windows
            # :windows way of reading :rename, :move, and :destroy permission for file/directory.
          else
            result[:permissions][:owner][:rename] = true
            result[:permissions][:owner][:move] = true
            result[:permissions][:owner][:destroy] = true
            result[:permissions][:owner][:create] = true
          end
        end
        if (raw_mode[3].to_i & 1) == 1
          result[:permissions][:owner][:execute] = true
        end
        # group permissions
        if (raw_mode[4].to_i & 4) == 4
           result[:permissions][:group][:read] = true
        end
        if (raw_mode[4].to_i & 2) == 2
          result[:permissions][:group][:write] = true
          if platform_details[:platform] == :windows
            # :windows way of reading :rename, :move, and :destroy permission for file/directory.
          else
            result[:permissions][:group][:rename] = true
            result[:permissions][:group][:move] = true
            result[:permissions][:group][:destroy] = true
            result[:permissions][:group][:create] = true
          end
        end
        if (raw_mode[4].to_i & 1) == 1
          result[:permissions][:group][:execute] = true
        end
        # other permissions
        if (raw_mode[5].to_i & 4) == 4
          result[:permissions][:other][:read] = true
        end
        if (raw_mode[5].to_i & 2) == 2
          result[:permissions][:other][:write] = true
          if platform_details[:platform] == :windows
            # :windows way of reading :rename, :move, and :destroy permission for file/directory.
          else
            result[:permissions][:other][:rename] = true
            result[:permissions][:other][:move] = true
            result[:permissions][:other][:destroy] = true
            result[:permissions][:other][:create] = true
          end
        end
        if (raw_mode[5].to_i & 1) == 1
          result[:permissions][:other][:execute] = true
        end
        # effective (this user) permissions (while opened, supercedes normal effective file system permissions)
        if result[:flags].index(:read)
          result[:permissions][:effective][:read] = true
          #
        end
        # ### db-based virtualized permission system keyed by :file_id
        # ### on non-linux systems - make sure to support the :file_id format subsystem, and map to local-arch-platform equivilents.
        # search_database(credential, {:ufs => "the.ufs.code", :properties => [{:the_property => {:equals => value}}]})
        if ::GxG::valid_uuid?(params[:with_credential] || @credential)
          acts_as = :group
          current_roles = GxG::DB[:authority].user_roles(params[:with_credential] || @credential)
          current_roles.each do |role_record|
            unless GxG::DB[:roles][:vfs].vfs_permission_exist?(result[:file_id], role_record[:credential])
              if role_record[:credential] == GxG::DB[:authority][:system_credentials][:designers] || role_record[:credential] == GxG::DB[:authority][:system_credentials][:developers] || role_record[:credential] == GxG::DB[:authority][:system_credentials][:administrators]
                GxG::DB[:roles][:vfs].create_vfs_permission(result[:file_id], role_record[:credential], result[:permissions][:owner])
                acts_as = :owner
              else
                GxG::DB[:roles][:vfs].create_vfs_permission(result[:file_id], role_record[:credential], result[:permissions][:group])
              end
              #
            end
          end
          #
          unless GxG::DB[:roles][:vfs].vfs_permission_exist?(result[:file_id], :"00000000-0000-4000-0000-000000000000")
            GxG::DB[:roles][:vfs].create_vfs_permission(result[:file_id], :"00000000-0000-4000-0000-000000000000", result[:permissions][:other])
          end
          # ### Review : should I support individual permissions at all, or rather confine it to roles and the public id?
          # unless GxG::DB[:roles][:vfs].vfs_permission_exist?(result[:file_id], (params[:with_credential] || @credential))
          #   if acts_as == :owner
          #     GxG::DB[:roles][:vfs].create_vfs_permission(result[:file_id], (params[:with_credential] || @credential), result[:permissions][:owner])
          #   else
          #     GxG::DB[:roles][:vfs].create_vfs_permission(result[:file_id], (params[:with_credential] || @credential), result[:permissions][:group])
          #   end
          # end
          #
          result[:permissions][:effective] = GxG::DB[:roles][:vfs].effective_vfs_permission(result[:file_id], (params[:with_credential] || @credential))
          #
        else
          log_error({:error => Exception.new("Invalid credential: #{params[:with_credential] || @credential}")})
        end
        result[:permissions].delete(:owner)
        result[:permissions].delete(:group)
        result[:permissions].delete(:other)
        #
        #
        # if @act_as.is_a?(::Symbol) || params[:with_credential]
        #   if ::GxG::valid_uuid?(params[:with_credential])
        #     if GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:administrators], params[:with_credential].to_s.to_sym)
        #       now_act_as = :owner
        #     else
        #       if GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:developers].to_s.to_sym, params[:with_credential].to_s.to_sym) || GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:designers].to_s.to_sym, params[:with_credential].to_s.to_sym)
        #         now_act_as = :group
        #       else
        #         now_act_as = :other
        #       end
        #     end
        #     result[:permissions][:effective] = result[:permissions][(now_act_as)].clone
        #   else
        #     result[:permissions][:effective] = result[:permissions][(@act_as)].clone
        #   end
        # else
        #   if result[:flags].index(:write)
        #     result[:permissions][:effective][:write] = true
        #     if platform_details[:platform] == :windows
        #       # :windows way of reading :rename, :move, and :destroy permission for file/directory.
        #     else
        #       result[:permissions][:effective][:rename] = true
        #       result[:permissions][:effective][:move] = true
        #       result[:permissions][:effective][:destroy] = true
        #       result[:permissions][:effective][:create] = true
        #     end
        #   end
        #   if raw_stat.executable?
        #     result[:permissions][:effective][:execute] = true
        #   end
        # end
        #
        result[:mode] = raw_mode
        # Mime type identification:
        if File.directory?(the_path)
          mime_type = "inode/directory"
        else
          mime_type = MimeMagic.by_extension(File.extname(result[:title]))
          unless mime_type
              mime_type = MimeMagic.by_path(the_path)
          end
          unless mime_type
            handle = ::File.open(the_path,"rb")
            handle.rewind
            mime_type = ::MimeMagic.by_magic(handle)
            handle.close
          end
          if mime_type
              mime_type = mime_type.type()
          else
              mime_type = "application/octet-stream"
          end
        end
        result[:mime] = mime_type
        #
        #
      else
        # return DB object profile
        unless subpath.to_s[0] == "/"
          subpath = ("/" << subpath.to_s)
        end
        #
        path_array = self.db_path(subpath.to_s)
        if path_array
          object_details = {:uuid => path_array.last[:uuid], :table => :unspecified, :dbid => 0}
          header = @database.connector()[:element_hash].filter({:uuid => object_details[:uuid].to_s}).first
          if header
            object_details[:table] = :element_hash
            object_details[:dbid] = header[:dbid]
          else
            header = @database.connector()[:element_array].filter({:uuid => object_details[:uuid].to_s}).first
            if header
              object_details[:table] = :element_array
              object_details[:dbid] = header[:dbid]
            end
          end
          #
          result = {:title => path_array.last[:title], :type => :virtual_directory, :owner_type => :virtual_directory, :uuid => path_array.last[:uuid], :version => header[:version], :on_device => nil, :on_device_major => nil, :on_device_minor => nil, :is_device => nil, :is_device_major => nil, :is_device_minor => nil, :inode => nil, :file_id => 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, :mime => nil}
          if object_details[:table] == :element_array
            result[:type] = :persisted_array
            result[:owner_type] = :persisted_array
          else
            result[:type] = :persisted_hash
            result[:owner_type] = :persisted_hash
          end
          if ::GxG::valid_uuid?(params[:with_credential])
            result[:permissions][:effective] = @database.effective_uuid_permission(object_details[:uuid], params[:with_credential])
          else
            result[:permissions][:effective] = @database.effective_uuid_permission(object_details[:uuid], @credential)
          end
          # Object Size in DB:
          if result[:type] == :persisted_hash
            # Review : DB overhaul - ensure @database.byte_size_by_uuid supports new arch.
            # result[:size] = @database.byte_size_by_uuid(object_details[:uuid])
          else
            # result[:size] = 0
          end
          # Pseudo-mime for objects:
          mime_type = nil
          if header[:format].to_s.size > 0
            the_format = @database.format_list({:uuid => header[:format]})[0]
            if the_format
              mime_type = "vnd.gxg/#{the_format[:ufs].to_s.gsub('_','-')}"
            else
              mime_type = "vnd.gxg/org.gxg.hash.persisted"
            end
          else
            if object_details[:table] == :element_array
              mime_type = "vnd.gxg/org.gxg.array.persisted"
            end
          end
          result[:mime] = mime_type
        else
          # raise Exception, "Invalid path"
        end
      end
      result
    end

rename(subpath="", new_name="", options={}) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1905
    def rename(subpath="", new_name="", options={})
      result = false
      if @directory
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        # FS
        begin
          if options[:with_credential]
            item_profile = self.profile(subpath.to_s,options.merge({:follow_symlinks => true}))
          else
            item_profile = self.profile(subpath.to_s)
          end
          if item_profile.is_a?(::Hash)
            if item_profile[:permissions][:effective][:rename] == true
              ::File.rename(the_path,(File.dirname(the_path) + "/" + new_name))
              # Review : check for file_id changes and update the VFS-DB permission records.
              result = true
            else
              raise Exception, "You do not have rename permissions here"
            end
          else
            raise Exception, "Invalid path"
          end
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
          #
        end
      else
        # DB open/create :persisted_hash or open :persisted_array
        begin
          path_array = self.db_path(subpath.to_s)
          if path_array
            if options[:with_credential]
              profile = self.profile(subpath.to_s, options)
            else
              profile = self.profile(subpath.to_s)
            end
            profile = self.profile(subpath.to_s)
            if profile[:permissions][:effective][:rename] == true
              if profile[:type] == :persisted_hash
                @database.connector()[:element_hash].filter({:uuid => profile[:uuid].to_s}).update({:title => new_name})
                result = true
              else
                if profile[:type] == :persisted_array
                  @database.connector()[:element_array].filter({:uuid => profile[:uuid].to_s}).update({:title => new_name})
                  result = true
                end
              end
              #
            else
              raise Exception, "You do not have rename permissions here"
            end
            #
          else
            raise Exception, "Invalid path"
          end
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {:path => the_path, :options => options}})
        end
      end
      result
    end

revoke_permissions(subpath="", the_credential=nil) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 2405
    def revoke_permissions(subpath="", the_credential=nil)
      # revoke_element_permissions(table=:unspecified, dbid=0, credential=nil)
      result = false
      if @directory
        # Review - all I need is the :file_id : make more efficient
        profile = self.profile(subpath)
        if profile[:file_id]
          result = GxG::DB[:roles][:vfs].destroy_vfs_permission(profile[:file_id], the_credential)
        end
      else
        if self.exist?(subpath)
          the_profile = self.profile(subpath)
          result = @database.revoke_permissions_by_uuid(the_profile[:uuid], the_credential)
        end
      end
      result
    end

rmdir(subpath="") click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1651
    def rmdir(subpath="")
      result = false
      if @directory
        # FS rmdir
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        #
        if ::File::exist?(the_path)
          begin
            the_profile = self.profile(subpath.to_s)
            if the_profile
              if the_profile[:permissions][:effective][:destroy]
                # Recursively delete any content files and subdirs first
                file_list = []
                dir_list = []
                vfs_list = [ (the_profile[:file_id]) ]
                # Gather up all VFS-DB :file_id entries:
                search_queue = [(subpath)]
                while search_queue.size > 0 do
                  entry = search_queue.shift
                  self.entries(entry).each do |the_subitem_profile|
                    if the_subitem_profile[:file_id].to_s.size > 0
                      vfs_list << the_subitem_profile[:file_id]
                    end
                    if [:virtual_directory, :persisted_array, :directory].include?(the_subitem_profile[:type])
                      search_queue << (entry + "/" + the_subitem_profile[:title])
                    end
                  end
                end
                # Do the FS work:
                search_queue = [(the_path)]
                while search_queue.size > 0 do
                  entry = search_queue.shift
                  if entry
                    Dir.entries(entry).each do |the_item_name|
                      unless [".",".."].include?(the_item_name)
                        if File.directory?(entry + "/" + the_item_name)
                          dir_list << (entry + "/" + the_item_name)
                          search_queue << (entry + "/" + the_item_name)
                        else
                          file_list << (entry + "/" + the_item_name)
                        end
                      end
                    end
                  end
                end
                file_list.each do |the_file_path|
                  File.delete(the_file_path)
                end
                dir_list.each do |the_dir_path|
                  ::Dir::rmdir(the_dir_path)
                end
                if ::Dir::rmdir(the_path) == 0
                  vfs_list.each do |the_file_id|
                    GxG::DB[:roles][:vfs].destroy_vfs_permission(the_file_id)
                  end
                  result = true
                end
              else
                raise Exception, "You do not have destroy permissions to do this"
              end
            else
              raise Exception, "Inavalid path"
            end
          rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:path => the_path}})
          end
        else
          begin
            raise Exception, "Invaid path"
          rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:path => the_path}})
          end
        end
        #
      else
        # DB rmdir
        unless subpath.to_s[0] == "/"
          subpath = ("/" << subpath.to_s)
        end
        path_array = self.db_path(subpath.to_s)
        if path_array
          if path_array.size > 1
            the_profile = self.profile(subpath.to_s)
            if the_profile
              if the_profile[:permissions][:effective][:destroy]
                parent_uuid = (path_array[-2] || {})[:uuid]
                link_uuids = []
                found_link = nil
                if parent_uuid
                  @database.connector()[:array_elements].filter({:parent_uuid => parent_uuid.to_s}).order(:ordinal).each do |link_record|
                    header = nil
                    if link_record[:element_array_uuid].to_s.size > 0
                      header = @database.connector()[:element_array].filter({:uuid => link_record[:element_array_uuid].to_s}).first
                    end
                    if header
                      if header[:uuid] == path_array.last[:uuid] && header[:title] == path_array.last[:title]
                        found_link = {:uuid => header[:uuid], :linkid => link_record[:dbid]}
                      else
                        link_uuids << {:uuid => header[:uuid], :linkid => link_record[:dbid]}
                      end
                    end
                  end
                  if found_link
                    # Review : how to deal with lots of users deleting objects at once??
                    if @database.destroy_by_uuid(@credential, found_link[:uuid].to_sym) == true
                      # ### Delete array_elements link of id ...
                      @database.connector()[:array_elements].filter({:dbid => found_link[:linkid]}).delete
                      # ### Reset ordinals of array_elements links. (Even though VFS.entries sorts results)
                      link_uuids.each_with_index do |link_record, ordinal|
                        @database.connector()[:array_elements].filter({:dbid => found_link[:linkid]}).update({:ordinal => ordinal})
                      end
                    end
                  end
                end
              else
                begin
                  raise Exception, "You do not have permissions to destroy this object"
                rescue Exception => the_error
                  log_error({:error => the_error, :parameters => {:path => subpath}})
                end
              end
            else
              begin
                raise Exception, "Invalid path"
              rescue Exception => the_error
                log_error({:error => the_error, :parameters => {:path => subpath}})
              end
            end
          else
            begin
              raise Exception, "You do not have permissions to destroy this object"
            rescue Exception => the_error
              log_error({:error => the_error, :parameters => {:path => subpath}})
            end
          end
        else
          begin
            raise Exception, "Invalid path"
          rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:path => subpath}})
          end
        end
      end
      result
    end

rmfile(subpath="") click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 1804
    def rmfile(subpath="")
      result = false
      if @directory
        # FS rmfile
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        #
        if ::File::exist?(the_path)
          begin
            the_profile = self.profile(subpath.to_s)
            if the_profile
              if the_profile[:permissions][:effective][:destroy]
                if ::File::delete(the_path)
                  GxG::DB[:roles][:vfs].destroy_vfs_permission(the_profile[:file_id])
                  result = true
                end
              else
                raise Exception, "You do not have destroy permissions to do this"
              end
            else
              raise Exception, "Inavalid path"
            end
          rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:path => the_path}})
          end
        else
          begin
            raise Exception, "Invaid path"
          rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:path => the_path}})
          end
        end
        #
      else
        # DB rmfile
        path_array = self.db_path(subpath.to_s)
        if path_array
          the_profile = self.profile(subpath.to_s)
          if the_profile
            if the_profile[:permissions][:effective][:destroy]
              parent_uuid = (path_array[-2] || {})[:uuid]
              link_uuids = []
              found_link = nil
              if parent_uuid
                @database.connector()[:array_elements].filter({:parent_uuid => parent_uuid.to_s}).order(:ordinal).each do |link_record|
                  header = nil
                  if link_record[:element_hash_uuid].to_s.size > 0
                    header = @database.connector()[:element_hash].filter({:uuid => link_record[:element_hash_uuid].to_s}).first
                  end
                  if header
                    if header[:uuid] == path_array.last[:uuid] && header[:title] == path_array.last[:title]
                      found_link = {:uuid => header[:uuid], :linkid => link_record[:dbid]}
                    else
                      link_uuids << {:uuid => header[:uuid], :linkid => link_record[:dbid]}
                    end
                  end
                end
                if found_link
                  # Review : how to deal with lots of users deleting objects at once??
                  if @database.destroy_by_uuid(@credential, found_link[:uuid].to_sym) == true
                    # ### Delete array_elements link of id ...
                    @database.connector()[:array_elements].filter({:dbid => found_link[:linkid]}).delete
                    # ### Reset ordinals of array_elements links. (Even though VFS.entries sorts results)
                    link_uuids.each_with_index do |link_record, ordinal|
                      @database.connector()[:array_elements].filter({:dbid => found_link[:linkid]}).update({:ordinal => ordinal})
                    end
                  end
                end
              end
              #
            else
              begin
                raise Exception, "You do not have destroy permissions to do this"
              rescue Exception => the_error
                log_error({:error => the_error, :parameters => {:path => subpath.to_s}})
              end
            end
          else
            begin
              raise Exception, "Invaid path"
            rescue Exception => the_error
              log_error({:error => the_error, :parameters => {:path => subpath.to_s}})
            end
          end
        else
          begin
            raise Exception, "Invaid path"
          rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:path => subpath.to_s}})
          end
        end
      end
      result
    end

set_permissions(subpath="", the_credential=nil, the_permissions={}) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 2423
    def set_permissions(subpath="", the_credential=nil, the_permissions={})
      result = false
      if @directory
        if subpath.to_s == "" or subpath.to_s == "/"
          the_path = (@directory.path)
        else
          unless subpath.to_s[0] == "/"
            subpath = ("/" << subpath.to_s)
          end
          the_path = (@directory.path + subpath.to_s).gsub("//", "/")
        end
        if ::File::exist?(the_path)
          # Review - all I need is the :file_id : make more efficient
          profile = self.profile(subpath, the_credential)
          the_credentials = []
          owner_roles = [(GxG::DB[:authority][:system_credentials][:administrators]), (GxG::DB[:authority][:system_credentials][:developers]), (GxG::DB[:authority][:system_credentials][:designers])].flatten!
          user_roles = GxG::DB[:authority].user_roles(the_credential).collect {|record| record[:credential]}
          the_role = :other
          user_roles.each do |the_role_credential|
            if owner_roles.include?(the_role_credential)
              the_role = :owner
              the_credentials = owner_roles
              break
            end
          end
          unless the_role == :owner
            if the_credential.to_s == "00000000-0000-4000-0000-000000000000"
              the_role = :other
              the_credentials = [ :"00000000-0000-4000-0000-000000000000" ]
            else
              the_role = :group
              the_credentials = user_roles
            end
          end
          # translate to unix permissions
          old_permission = ::File.stat(the_path).mode.to_s(base=2)
          x = nil
          if ::File.directory?(the_path)
            x = 1
          else
            if the_permissions.keys.include?(:execute)
              if the_permissions[:execute] == true
                x = 1
              else
                x = 0
              end
            end
          end
          w = nil
          if the_permissions.keys.include?(:write)
            if the_permissions[:write] == true
              w = 1
            else
              w = 0
            end
          else
            [:rename, :move, :destroy, :create].each do |the_action|
              if the_permissions.keys.include?(the_action)
                if the_permissions[(the_action)] == true
                  w = 1
                  break
                end
              end
            end
          end
          if the_permissions.keys.include?(:read)
            if the_permissions[:read] == true
              r = 1
            else
              r = 0
            end
          else
            r = nil
          end
          case the_role
          when :owner
            if x
              old_permission[-7] = x.to_s
            end
            if w
              old_permission[-8] = w.to_s
            end
            if r
              old_permission[-9] = r.to_s
            end
          when :group
            if x
              old_permission[-4] = x.to_s
            end
            if w
              old_permission[-5] = w.to_s
            end
            if r
              old_permission[-6] = r.to_s
            end
          when :other
            if x
              old_permission[-1] = x.to_s
            end
            if w
              old_permission[-2] = w.to_s
            end
            if r
              old_permission[-3] = r.to_s
            end
          end
          ::File.chmod(old_permission.to_i(2), the_path)
          if profile[:file_id]
            the_credentials.each do |credential_uuid|
              GxG::DB[:roles][:vfs].update_vfs_permission(profile[:file_id], credential_uuid, the_permissions)
            end
          end
          result = true
        end
      else
        # DB object exist?
        path_array = self.db_path(subpath.to_s)
        if path_array
          object_details = {:uuid => path_array.last[:uuid], :table => :unspecified, :dbid => 0}
          header = @database.connector()[:element_hash].filter({:uuid => object_details[:uuid].to_s}).first
          if header
            object_details[:table] = :element_hash
            object_details[:dbid] = header[:dbid]
          else
            header = @database.connector()[:element_array].filter({:uuid => object_details[:uuid].to_s}).first
            if header
              object_details[:table] = :element_array
              object_details[:dbid] = header[:dbid]
            end
          end
          if object_details[:uuid].to_s.size > 0
            if object_details[:table] = :element_array
              manifest = [{:table => object_details[:table], :dbid => object_details[:dbid]}]
            else
              # Note: for an element_hash - ensure all sub-objects are extended this permission.
              manifest = []
              structures = [{:table => object_details[:table], :dbid => object_details[:dbid]}]
              while structures.size > 0 do
                entry = structures[0]
                @database.element_manifest(entry[:table],entry[:dbid]).each do |record|
                  if [:element_hash, :element_array].include?(record[:table])
                    unless structures.include?(record)
                      structures << record
                    end
                  end
                end
                manifest << structures.shift
              end
            end
            #
            manifest.each do |record|
              @database.assign_element_permission(record[:table], record[:dbid], credential, the_permissions)
            end
            result = true
          end
        end
      end
      result
    end

set_permissions_recursive(subpath="", the_credential=nil, the_permissions={}) click to toggle source

    # File lib/gxg/gxg_dbfs.rb, line 2583
    def set_permissions_recursive(subpath="", the_credential=nil, the_permissions={})
      the_profile = self.profile((File.expand_path(subpath)).to_s)
      if the_profile
        if [:virtual_directory, :directory, :persisted_array].include?(the_profile[:type])
          paths = [(File.expand_path(subpath))]
          while paths.size > 0 do
            the_path = paths.shift
            the_path_profile = self.profile(the_path.to_s)
            if [:virtual_directory, :directory, :persisted_array].include?(the_path_profile[:type])
              self.entries(the_path, the_credential).each do |a_profile|
                paths << File.expand_path(the_path + "/" + a_profile[:title].to_s)
              end
              self.set_permissions(the_path, the_credential, the_permissions)
            else
              self.set_permissions(the_path, the_credential, the_permissions)
            end
          end
        else
          self.set_permissions(subpath, the_credential, the_permissions)
        end
      end
      true
    end