Module: FSDB::PathUtilities

Included in:
FSDB, Database
Defined in:
lib/fsdb/util.rb

Overview

Extends FSDB:Databases to have methods for validating and normalizing paths, path globbing, directory traversal, making links, …

Defined Under Namespace

Classes: InvalidPathError

Instance Method Summary collapse

Instance Method Details

#canonical(path) ⇒ Object

Attempts to convert a path to a canonical form so that ‘/foo/bar’, ‘foo/bar’, ‘foo//bar’, and ‘foo/zap/../bar’ all result in the same path. The canonical form is the simplest.

Doesn’t remove trailing ‘/’, which indicates directory.

This is not necessary for database access, it’s just for display purposes and for validation.



16
17
18
19
20
21
22
23
# File 'lib/fsdb/util.rb', line 16

def canonical(path)
  path = path.dup
  while path.gsub!(/[^\/]+\/+\.\.(?=\/)/, ""); end
  path.gsub!(/\/\/+/, "/")
  path.gsub!(/\/\.\//, "/")
  path.sub!(/^\/+/, "")
  path
end

#canonical?(path) ⇒ Boolean

Is the path in the simplest, canonical representation?

Returns:

  • (Boolean)


26
27
28
# File 'lib/fsdb/util.rb', line 26

def canonical?(path)
  path == canonical(path)
end

#directory?(path) ⇒ Boolean

Use this to check whether a path yielded by an iterator is a directory.

Returns:

  • (Boolean)


64
65
66
# File 'lib/fsdb/util.rb', line 64

def directory?(path)
  /\/$/ =~ path
end

#glob(str) ⇒ Object

Dir globbing. Excludes ‘.’ and all ‘..*’ files (but includes ‘../’, if included in the match). Returns sorted array of strings to help avoid deadlock when doing nested transactions. Does not yield to block (as Dir.glob does) because #glob operates under Thread.exclusive, because it uses Dir.chdir, which is not threadsafe.

Raises:

  • (ArgumentError)


54
55
56
57
58
59
60
61
# File 'lib/fsdb/util.rb', line 54

def glob(str)
  raise ArgumentError, "Block not supported for #glob" if block_given?
  Thread.exclusive do
    Dir.chdir(@dir) do
      Dir.glob(str).reject { |e| e =~ /(?:^\.$|\.\.[^\/]*$)/ }.sort!
    end
  end
end

#valid?(path) ⇒ Boolean

Does the path refer to an object within the database? This doesn’t check for links.

Returns:

  • (Boolean)


32
33
34
# File 'lib/fsdb/util.rb', line 32

def valid?(path)
  canonical(path) !~ /\.\./
end

#validate(path) ⇒ Object

Raises InvalidPathError if canonical(path) still has embedded ‘..’, which means the path would refer to a file not below the database directory. Returns the canonical path, otherwise.



41
42
43
44
45
46
47
# File 'lib/fsdb/util.rb', line 41

def validate(path)
  path = canonical(path)
  unless valid?(path)
    raise InvalidPathError, "Path #{path} is outside the database."
  end
  path
end