FSRules

FSRules is a tiny DSL, widely-used in XYZCommander for describing filesystem objects.

Each rule produces a predicate, that is passing a VFS object as an argument, rule yields either True or False depending if described attributes match the actual ones of passed object.

FSRules grammar (BNF)

rule      ::=  expr $
               expr op rule
expr      ::=  expr_body
               "not" expr_body
               "(" rule ")"
expr_body ::=  ftype "{" ARG "}"
op        ::=  "and"
               "or"
ftype     ::=  "type"
               "perm"
               "owner"
               "name"
               "iname"
               "size
               "link_type"
               "link_perm"
               "link_owner"
               "link_name"
               "link_iname"
               "link_exists"
               "link_size"

Rule consists of one or more expressions combined with logical operators. Expression has the following format: <type>{<arg>}. Available expressions are:

link_type, link_perm, link_owner, link_name, link_iname, link_size are the same expressions as corresponding above, but they’re applied only for symbolic links targets.

Expression can be negated by prepending operator not in front of it.

Expressions in a rule are combined using logical operators and and or.

type

type expression is used to match object based on its type. Available arguments:

file
Regular file
dir
Directory
block
Block device
char
Char device
link
Symbolic link
fifo
FIFO
socket
Socket

So, to match all regular files and directories use: "type{file} or type{dir}"

perm

perm expression is used to match objects by permission bits. An argument is specified as [+]dddd. Where dddd is an octal number. If number is preceeded by ‘+’ this will match objects with any of mode bits set. Otherwise it will match only objects with exactly the same mode as given.

Examples:

# This will match any set-uid object
"perm{+4000}"

# Objects with execution bits set
"perm{+0111}"

# Match only objects with exactly set mode - 755
"perm{0755}"

owner

owner expression is used to match file object based on its owner and/or group.

Argument can be specified as [uid][:gid]. uid and gid both can be either symbolic or numeric:

# Files owned by root and group wheel
"type{file} and owner{root:wheel}"

# Directories owned by username
"type{dir} and owner{username}"

# Sockets owned by group operator
"type{socket} and owner{:operator}"

# Objects owner by user with uid 1050
"owner{1050}"

name

name expressions rules use names of object as match criteria.

An argument is an arbitrary regular-expression string:

# *.core files
name{".*\\.core$"}

# Hidden files
name{"^\\.{1}[^.]"}

iname

iname expression is the same as the name above but it is case-insensitive.

size

size expressions are used to match objects based on their size.

General argument format is: [[<>]=]<size>[BbKkMmGgTt]. Where the only required part is <size>. An operator can be preprended to size, one of: >, <, >=, <=, =. If operator is omitted, = is assumed. Also a modifier can be appended:

[bB] - The size in bytes (default)
[kK] - The size in kilobytes
[mM] - The size in megabytes
[gG] - The size in gigabytes
[tT] - The size in terabytes

If no modifier is used, the size is assumed to be in bytes.

Some examples:

# Objects larger or equal to 100 megabytes
size{">=100M"}

# Exactly 700 bytes, also can be written as size{"=700B"}
size{700}

Logical operators

Expressions can be combined using logical operators and and or. Expression are calculated in a short-circuit scheme, that is second argument is only evaluated if the first argument does not suffice to determine the value of the expression.

Extended expressions (DEV)

In addition to standard built-in expressions, FSRule parser has an ability to extend its functionality by adding new expression types.

Extending is done using extend() classmethod of FSRule class, that is new expressions are applied to class and thus are immediately available to all FSRule instances.

Let’s say we’re writing a plugin which adds a new FSRule expression, say: inode{inode} whose purpose is to match objects with provided inode. Not very useful in fact, but good as example.

So we need to prepare a transformation function and a match function.

Transformation function takes a string which was passed as an argument and returns whatever is neccessary to match on later. In our case an argument is an inode, so it would be enough to make sure it is number:

transform = lambda arg: int(arg)

Next we need a match function wich will be called when match() method is invoked on FSRule instance.

Match function takes two variables: VFSObject instance and a transformed value returned by our transformation function above:

match = lambda obj, arg: obj.inode is not None and obj.inode == arg

Note that match functions are required to return either True or False or raise an exception in case of error.

Now we’ve got everything we need to extend FSRule. In prepare() method of our plugin we add:

import libxyz.core.FSRule

def prepare(self):
   transform = lambda arg: int(arg)
   match = lambda obj, arg: obj.inode is not None and obj.inode == arg

   libxyz.core.FSRule.extend("inode", transform, match)

And in finalize() remove extended expression:

def finalize(self):
   libxyz.core.FSRule.unextend("inode")

That’s pretty much it. After XYZCommander loads our plugin, we can start using inode{} in our FSRule expressions.

Table Of Contents

Previous topic

Configuration files

Next topic

Skins

This Page