Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
cav-linux / opt / COMODO / driver.tar
Size: Mime:
driver/0000755000076400007640000000000012112622747011707 5ustar  comodocomododriver/redirfs/0000755000076400007640000000000012112622747013345 5ustar  comodocomododriver/redirfs/rfs_file.c0000644000076400007640000001776312112622747015320 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static rfs_kmem_cache_t *rfs_file_cache = NULL;

struct file_operations rfs_file_ops = {
	.open = rfs_open
};

static struct rfs_file *rfs_file_alloc(struct file *file)
{
	struct rfs_file *rfile;

	rfile = kmem_cache_zalloc(rfs_file_cache, GFP_KERNEL);
	if (!rfile)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rfile->rdentry_list);
	INIT_LIST_HEAD(&rfile->data);
	rfile->file = file;
	spin_lock_init(&rfile->lock);
	atomic_set(&rfile->count, 1);
	rfile->op_old = fops_get(file->f_op);

	if (rfile->op_old)
		memcpy(&rfile->op_new, rfile->op_old,
				sizeof(struct file_operations));

	rfile->op_new.open = rfs_open;

	return rfile;
}

struct rfs_file *rfs_file_get(struct rfs_file *rfile)
{
	if (!rfile || IS_ERR(rfile))
		return NULL;

	BUG_ON(!atomic_read(&rfile->count));
	atomic_inc(&rfile->count);

	return rfile;
}

void rfs_file_put(struct rfs_file *rfile)
{
	if (!rfile || IS_ERR(rfile))
		return;

	BUG_ON(!atomic_read(&rfile->count));
	if (!atomic_dec_and_test(&rfile->count))
		return;

	rfs_dentry_put(rfile->rdentry);
	fops_put(rfile->op_old);

	rfs_data_remove(&rfile->data);
	kmem_cache_free(rfs_file_cache, rfile);
}

static struct rfs_file *rfs_file_add(struct file *file)
{
	struct rfs_file *rfile;

	rfile = rfs_file_alloc(file);
	if (IS_ERR(rfile))
		return rfile;

	rfile->rdentry = rfs_dentry_find(file->f_dentry);
	rfs_dentry_add_rfile(rfile->rdentry, rfile);
	fops_put(file->f_op);
	file->f_op = &rfile->op_new;
	rfs_file_get(rfile);
	spin_lock(&rfile->rdentry->lock);
	rfs_file_set_ops(rfile);
	spin_unlock(&rfile->rdentry->lock);

	return rfile;
}

static void rfs_file_del(struct rfs_file *rfile)
{
	rfs_dentry_rem_rfile(rfile);
	rfile->file->f_op = fops_get(rfile->op_old);
	rfs_file_put(rfile);
}

int rfs_file_cache_create(void)
{
	rfs_file_cache = rfs_kmem_cache_create("rfs_file_cache",
			sizeof(struct rfs_file));

	if (!rfs_file_cache)
		return -ENOMEM;

	return 0;
}

void rfs_file_cache_destory(void)
{
	kmem_cache_destroy(rfs_file_cache);
}

int rfs_open(struct inode *inode, struct file *file)
{
	struct rfs_file *rfile;
	struct rfs_dentry *rdentry;
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(inode);
	fops_put(file->f_op);
	file->f_op = fops_get(rinode->fop_old);

	rdentry = rfs_dentry_find(file->f_dentry);
	if (!rdentry) {
		rfs_inode_put(rinode);
		if (file->f_op && file->f_op->open)
			return file->f_op->open(inode, file);

		return 0;
	}

	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_dentry_put(rdentry);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_FOP_OPEN;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_FOP_OPEN;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_FOP_OPEN;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_FOP_OPEN;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_FOP_OPEN;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_FOP_OPEN;

	rargs.args.f_open.inode = inode;
	rargs.args.f_open.file = file;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->fop_old && rinode->fop_old->open)
			rargs.rv.rv_int = rinode->fop_old->open(
					rargs.args.f_open.inode,
					rargs.args.f_open.file);
		else
			rargs.rv.rv_int = 0;
	}

	if (!rargs.rv.rv_int) {
		rfile = rfs_file_add(file);
		if (IS_ERR(rfile))
			BUG();
		rfs_file_put(rfile);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_release(struct inode *inode, struct file *file)
{
	struct rfs_file *rfile;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rfile = rfs_file_find(file);
	rinfo = rfs_dentry_get_rinfo(rfile->rdentry);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_FOP_RELEASE;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_FOP_RELEASE;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_FOP_RELEASE;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_FOP_RELEASE;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_FOP_RELEASE;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_FOP_RELEASE;

	rargs.args.f_release.inode = inode;
	rargs.args.f_release.file = file;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rfile->op_old && rfile->op_old->release)
			rargs.rv.rv_int = rfile->op_old->release(
					rargs.args.f_release.inode,
					rargs.args.f_release.file);
		else
			rargs.rv.rv_int = 0;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_file_del(rfile);
	rfs_file_put(rfile);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
	LIST_HEAD(sibs);
	struct rfs_dcache_entry *sib;
	struct rfs_file *rfile;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct rfs_dentry *rdentry;
	struct redirfs_args rargs;

	rfile = rfs_file_find(file);
	rinfo = rfs_dentry_get_rinfo(rfile->rdentry);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(file->f_dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_DIR_FOP_READDIR;

	rargs.args.f_readdir.file = file;
	rargs.args.f_readdir.dirent = dirent;
	rargs.args.f_readdir.filldir = filldir;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rfile->op_old && rfile->op_old->readdir) 
			rargs.rv.rv_int = rfile->op_old->readdir(
					rargs.args.f_readdir.file,
					rargs.args.f_readdir.dirent,
					rargs.args.f_readdir.filldir);
		else
			rargs.rv.rv_int = -ENOTDIR;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (rargs.rv.rv_int)
		goto exit;

	if (rfs_dcache_get_subs(file->f_dentry, &sibs)) {
		BUG();
		goto exit;
	}

	list_for_each_entry(sib, &sibs, list) {
		rdentry = rfs_dentry_find(sib->dentry);
		if (rdentry) {
			rfs_dentry_put(rdentry);
			continue;
		}

		if (!rinfo->rops) {
			if (!sib->dentry->d_inode)
				continue;

			if (!S_ISDIR(sib->dentry->d_inode->i_mode))
				continue;
		}

		if (rfs_dcache_rdentry_add(sib->dentry, rinfo)) {
			BUG();
			goto exit;
		}
	}

exit:
	rfs_dcache_entry_free_list(&sibs);
	rfs_file_put(rfile);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static void rfs_file_set_ops_reg(struct rfs_file *rfile)
{
}

static void rfs_file_set_ops_dir(struct rfs_file *rfile)
{
	rfile->op_new.readdir = rfs_readdir;
}

static void rfs_file_set_ops_lnk(struct rfs_file *rfile)
{
}

static void rfs_file_set_ops_chr(struct rfs_file *rfile)
{
}

static void rfs_file_set_ops_blk(struct rfs_file *rfile)
{
}

static void rfs_file_set_ops_fifo(struct rfs_file *rfile)
{
}

void rfs_file_set_ops(struct rfs_file *rfile)
{
	umode_t mode;

	if (!rfile->rdentry->rinode)
		return;

	mode = rfile->rdentry->rinode->inode->i_mode;

	if (S_ISREG(mode))
		rfs_file_set_ops_reg(rfile);

	else if (S_ISDIR(mode))
		rfs_file_set_ops_dir(rfile);

	else if (S_ISLNK(mode))
		rfs_file_set_ops_lnk(rfile);

	else if (S_ISCHR(mode))
		rfs_file_set_ops_chr(rfile);

	else if (S_ISBLK(mode))
		rfs_file_set_ops_blk(rfile);

	else if (S_ISFIFO(mode))
		rfs_file_set_ops_fifo(rfile);

	rfile->op_new.release = rfs_release;
}

driver/redirfs/README0000644000076400007640000000234112112622747014225 0ustar  comodocomodo		================================
		RedirFS - Redirecting FileSystem
			    README
		================================

This software is distributed under the GNU General Public License Version 3.

1. Introduction

	Redirecting FileSystem or RedirFS project aims to be general, fast,
	flexible and open source framework allowing to redirect native 
	filesystem calls in the VFS layer. It is implemented as a 
	LKM(Linux Kernel Module) and provides well defined interface for other
	LKMs which are called Filters. Filters can set pre and post call-back 
	functions for selected filesystem operations(e.g. permission, open). 
	Filters can also select for which file system paths will be their
	call-back functions called and even which file system paths will be
	excluded. Each Filter is specified by a name and unique number which
	represents Filter's priority. RedirFS manages all registered Filters and
	calls their call-back functions in specific order defined by their
	priorities.

	For an overview of the RedirFS project, visit 

		http://www.redirfs.org

2. Installation

	See the INSTALL file.

3. Documentation

	http://www.redirfs.org/tiki-index.php?page=redirfs_doc

4. Problems & Bugs
	
	http://www.redirfs.org/cgi-bin/bugzilla/index.cgi
driver/redirfs/.svnignore0000644000076400007640000000005512112622747015360 0ustar  comodocomodo*.o.cmd
*.ko.cmd
*.mod.c
.tmp_versions
*.ko

driver/redirfs/COPYING0000644000076400007640000010451312112622747014404 0ustar  comodocomodo                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
driver/redirfs/rfs_ops.c0000644000076400007640000000305212112622747015164 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

struct rfs_ops *rfs_ops_alloc(void)
{
	struct rfs_ops *rops;
	char *arr;

	rops = kzalloc(sizeof(struct rfs_ops), GFP_KERNEL);
	arr = kzalloc(sizeof(char) * REDIRFS_OP_END, GFP_KERNEL);

	if (!rops || !arr) {
		kfree(rops);
		kfree(arr);
		return ERR_PTR(-ENOMEM);
	}

	rops->arr = arr;
	atomic_set(&rops->count, 1);

	return rops;
}

struct rfs_ops *rfs_ops_get(struct rfs_ops *rops)
{
	if (!rops || IS_ERR(rops))
		return NULL;

	BUG_ON(!atomic_read(&rops->count));
	atomic_inc(&rops->count);
	return rops;
}

void rfs_ops_put(struct rfs_ops *rops)
{
	if (!rops || IS_ERR(rops))
		return;

	BUG_ON(!atomic_read(&rops->count));
	if (!atomic_dec_and_test(&rops->count))
		return;

	kfree(rops->arr);
	kfree(rops);
}

driver/redirfs/rfs_path.c0000644000076400007640000004462512112622747015332 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static LIST_HEAD(rfs_path_list);
RFS_DEFINE_MUTEX(rfs_path_mutex);

static struct rfs_path *rfs_path_alloc(struct vfsmount *mnt,
		struct dentry *dentry)
{
	struct rfs_path *rpath;

	rpath = kzalloc(sizeof(struct rfs_path), GFP_KERNEL);
	if (!rpath)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rpath->list);
	INIT_LIST_HEAD(&rpath->rroot_list);
	rpath->mnt = mntget(mnt);
	rpath->dentry = dget(dentry);
	atomic_set(&rpath->count, 1);

	return rpath;
}

struct rfs_path *rfs_path_get(struct rfs_path *rpath)
{
	if (!rpath || IS_ERR(rpath))
		return NULL;

	BUG_ON(!atomic_read(&rpath->count));
	atomic_inc(&rpath->count);

	return rpath;
}

void rfs_path_put(struct rfs_path *rpath)
{
	if (!rpath || IS_ERR(rpath))
		return;

	BUG_ON(!atomic_read(&rpath->count));
	if (!atomic_dec_and_test(&rpath->count))
		return;

	dput(rpath->dentry);
	mntput(rpath->mnt);
	kfree(rpath);
}

static struct rfs_path *rfs_path_find(struct vfsmount *mnt,
		struct dentry *dentry)
{
	struct rfs_path *rpath = NULL;
	struct rfs_path *found = NULL;

	list_for_each_entry(rpath, &rfs_path_list, list) {
		if (rpath->mnt != mnt) 
			continue;

		if (rpath->dentry != dentry)
			continue;

		found = rfs_path_get(rpath);
		break;
	}

	return found;
}

struct rfs_path *rfs_path_find_id(int id)
{
	struct rfs_path *rpath = NULL;
	struct rfs_path *found = NULL;

	list_for_each_entry(rpath, &rfs_path_list, list) {
		if (rpath->id != id)
			continue;

		found = rfs_path_get(rpath);
		break;
	}

	return found;
}

static int rfs_path_add_rroot(struct rfs_path *rpath)
{
	struct rfs_root *rroot;

	rroot = rfs_root_add(rpath->dentry);
	if (IS_ERR(rroot))
		return PTR_ERR(rroot);
	
	rfs_root_add_rpath(rroot, rpath);
	rpath->rroot = rroot;

	return 0;
}

static void rfs_path_rem_rroot(struct rfs_path *rpath)
{
	rfs_root_rem_rpath(rpath->rroot, rpath);
	rfs_root_put(rpath->rroot);
	rpath->rroot = NULL;
}

static void rfs_path_list_add(struct rfs_path *rpath)
{
	list_add_tail(&rpath->list, &rfs_path_list);
	rfs_path_get(rpath);
}

static void rfs_path_list_rem(struct rfs_path *rpath)
{
	list_del_init(&rpath->list);
	rfs_path_put(rpath);
}

static int rfs_path_get_id(void)
{
	struct rfs_path *rpath = NULL;
	int i = 0;

mainloop:
	while (i < INT_MAX) {
		list_for_each_entry(rpath, &rfs_path_list, list) {
			if (rpath->id == i) {
				i++;
				goto mainloop;
			}
		}
		return i;
	}

	return -1;
}

static struct rfs_path *rfs_path_add(struct vfsmount *mnt,
		struct dentry *dentry)
{
	struct rfs_path *rpath;
	int id;
	int rv;

	rpath = rfs_path_find(mnt, dentry);
	if (rpath)
		return rpath;

	id = rfs_path_get_id();
	if (id < 0)
		return ERR_PTR(-EBUSY);

	rpath = rfs_path_alloc(mnt, dentry);
	if (IS_ERR(rpath))
		return rpath;

	rpath->id = id;

	rv = rfs_path_add_rroot(rpath);
	if (rv) {
		rfs_path_put(rpath);
		return ERR_PTR(rv);
	}

	rfs_path_list_add(rpath);

	return rpath;
}

static void rfs_path_rem(struct rfs_path *rpath)
{
	if (rpath->rinch || rpath->rexch)
		return;

	rfs_path_rem_rroot(rpath);
	rfs_path_list_rem(rpath);
}

static int rfs_path_add_dirs(struct dentry *dentry)
{
	struct rfs_inode *rinode;

	rinode = rfs_inode_find(dentry->d_inode);
	if (rinode) {
		rfs_inode_put(rinode);
		return 0;
	}

	return rfs_dcache_walk(dentry, rfs_dcache_add_dir, NULL);
}

static int rfs_path_check_fs(struct file_system_type *type)
{
	if (!strcmp("cifs", type->name))
		goto notsup;

	return 0;
notsup:
	printk(KERN_ERR "redirfs does not support '%s' file system\n",
			type->name);
	return -1;
}

static int rfs_path_add_include(struct rfs_path *rpath, struct rfs_flt *rflt)
{
	struct rfs_chain *rinch;
	int rv;

	if (rfs_chain_find(rpath->rinch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rpath->rexch, rflt) != -1)
		return -EEXIST;

	rv = rfs_path_add_dirs(rpath->dentry->d_sb->s_root);
	if (rv)
		return rv;

	rinch = rfs_chain_add(rpath->rinch, rflt);
	if (IS_ERR(rinch))
		return PTR_ERR(rinch);

	rv = rfs_root_add_include(rpath->rroot, rflt);
	if (rv) {
		rfs_chain_put(rinch);
		return rv;
	}

	rfs_chain_put(rpath->rinch);
	rpath->rinch = rinch;
	rflt->paths_nr++;

	return 0;
}
	
static int rfs_path_add_exclude(struct rfs_path *rpath, struct rfs_flt *rflt)
{
	struct rfs_chain *rexch;
	int rv;

	if (rfs_chain_find(rpath->rexch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rpath->rinch, rflt) != -1)
		return -EEXIST;

	rexch = rfs_chain_add(rpath->rexch, rflt);
	if (IS_ERR(rexch))
		return PTR_ERR(rexch);

	rv = rfs_root_add_exclude(rpath->rroot, rflt);
	if (rv) {
		rfs_chain_put(rexch);
		return rv;
	}

	rfs_chain_put(rpath->rexch);
	rpath->rexch = rexch;
	rflt->paths_nr++;

	return 0;
}

static int rfs_path_rem_include(struct rfs_path *rpath, struct rfs_flt *rflt)
{
	struct rfs_chain *rinch;
	int rv;

	if (rfs_chain_find(rpath->rinch, rflt) == -1)
		return 0;

	rinch = rfs_chain_rem(rpath->rinch, rflt);
	if (IS_ERR(rinch))
		return PTR_ERR(rinch);

	rv = rfs_root_rem_include(rpath->rroot, rflt);
	if (rv) {
		rfs_chain_put(rinch);
		return rv;
	}

	rfs_chain_put(rpath->rinch);
	rpath->rinch = rinch;
	rflt->paths_nr--;

	return 0;
}

static int rfs_path_rem_exclude(struct rfs_path *rpath, struct rfs_flt *rflt)
{
	struct rfs_chain *rexch;
	int rv;

	if (rfs_chain_find(rpath->rexch, rflt) == -1)
		return 0;

	rexch = rfs_chain_rem(rpath->rexch, rflt);
	if (IS_ERR(rexch))
		return PTR_ERR(rexch);

	rv = rfs_root_rem_exclude(rpath->rroot, rflt);
	if (rv) {
		rfs_chain_put(rexch);
		return rv;
	}

	rfs_chain_put(rpath->rexch);
	rpath->rexch = rexch;
	rflt->paths_nr--;

	return 0;
}

redirfs_path redirfs_add_path(redirfs_filter filter,
		struct redirfs_path_info *info)
{
	struct rfs_path *rpath;
	int rv;

	might_sleep();

	if (!filter || IS_ERR(filter) || !info)
		return ERR_PTR(-EINVAL);

	if (!info->mnt || !info->dentry || !info->flags)
		return ERR_PTR(-EINVAL);

	if (rfs_path_check_fs(info->dentry->d_inode->i_sb->s_type))
		return ERR_PTR(-EPERM);

	rfs_rename_lock(info->dentry->d_inode->i_sb);
	rfs_mutex_lock(&rfs_path_mutex);

	rpath = rfs_path_add(info->mnt, info->dentry);
	if (IS_ERR(rpath))
		goto exit;

	if (info->flags == REDIRFS_PATH_INCLUDE)
		rv = rfs_path_add_include(rpath, filter);

	else if (info->flags == REDIRFS_PATH_EXCLUDE)
		rv = rfs_path_add_exclude(rpath, filter);

	else
		rv = -EINVAL;

	rfs_path_rem(rpath);

	if (rv) {
		rfs_path_put(rpath);
		rpath = ERR_PTR(rv);
	}
exit:
	rfs_mutex_unlock(&rfs_path_mutex);
	rfs_rename_unlock(info->dentry->d_inode->i_sb);
	return rpath;
}

int redirfs_rem_path(redirfs_filter filter, redirfs_path path)
{
	struct rfs_path *rpath = (struct rfs_path *)path;
	int rv;

	might_sleep();

	if (!filter || IS_ERR(filter) || !path)
		return -EINVAL;

	rfs_rename_lock(rpath->dentry->d_inode->i_sb);
	rfs_mutex_lock(&rfs_path_mutex);

	if (rfs_chain_find(rpath->rinch, filter) != -1)
		rv = rfs_path_rem_include(path, filter);

	else if (rfs_chain_find(rpath->rexch, filter) != -1)
		rv = rfs_path_rem_exclude(path, filter);

	else
		rv = -EINVAL;

	rfs_path_rem(rpath);

	rfs_mutex_unlock(&rfs_path_mutex);
	rfs_rename_unlock(rpath->dentry->d_inode->i_sb);

	return rv;
}

int redirfs_get_id_path(redirfs_path path)
{
	struct rfs_path *rpath = path;

	if (!path || IS_ERR(path))
		return -EINVAL;

	return rpath->id;
}

redirfs_path redirfs_get_path_id(int id)
{
	struct rfs_path *rpath;

	might_sleep();

	rfs_mutex_lock(&rfs_path_mutex);
	rpath = rfs_path_find_id(id);
	rfs_mutex_unlock(&rfs_path_mutex);

	return rpath;
}

redirfs_path redirfs_get_path(redirfs_path path)
{
	return rfs_path_get(path);
}

void redirfs_put_path(redirfs_path path)
{
	rfs_path_put(path);
}

redirfs_path* redirfs_get_paths_root(redirfs_filter filter, redirfs_root root)
{
	struct rfs_root *rroot = (struct rfs_root *)root;
	struct rfs_path *rpath;
	redirfs_path *paths;
	int i = 0;

	if (!filter || IS_ERR(filter) || !root)
		return ERR_PTR(-EINVAL);

	rfs_mutex_lock(&rfs_path_mutex);
	paths = kzalloc(sizeof(redirfs_path) * (rroot->paths_nr + 1),
			GFP_KERNEL);
	if (!paths) {
		rfs_mutex_unlock(&rfs_path_mutex);
		return ERR_PTR(-ENOMEM);
	}

	list_for_each_entry(rpath, &rroot->rpaths, rroot_list) {
		if (rfs_chain_find(rroot->rinch, filter) != -1)
			paths[i++] = rfs_path_get(rpath);

		else if (rfs_chain_find(rroot->rexch, filter) != -1)
			paths[i++] = rfs_path_get(rpath);

	}

	rfs_mutex_unlock(&rfs_path_mutex);
	paths[i] = NULL;

	return paths;
}

redirfs_path* redirfs_get_paths(redirfs_filter filter)
{
	struct rfs_flt *rflt = filter;
	struct rfs_path *rpath;
	redirfs_path *paths;
	int i = 0;

	might_sleep();

	if (!filter || IS_ERR(filter))
		return ERR_PTR(-EINVAL);

	rfs_mutex_lock(&rfs_path_mutex);

	paths = kzalloc(sizeof(redirfs_path) * (rflt->paths_nr + 1),
			GFP_KERNEL);
	if (!paths) {
		rfs_mutex_unlock(&rfs_path_mutex);
		return ERR_PTR(-ENOMEM);
	}

	list_for_each_entry(rpath, &rfs_path_list, list) {
		if (rfs_chain_find(rpath->rinch, filter) != -1)
			paths[i++] = rfs_path_get(rpath);

		else if (rfs_chain_find(rpath->rexch, filter) != -1)
			paths[i++] = rfs_path_get(rpath);
	}

	rfs_mutex_unlock(&rfs_path_mutex);
	paths[i] = NULL;

	return paths;
}

void redirfs_put_paths(redirfs_path *paths)
{
	int i = 0;

	if (!paths)
		return;

	while (paths[i]) {
		redirfs_put_path(paths[i]);
		i++;
	}

	kfree(paths);
}

struct redirfs_path_info *redirfs_get_path_info(redirfs_filter filter,
		redirfs_path path)
{
	struct rfs_path *rpath = path;
	struct redirfs_path_info *info;

	might_sleep();

	if (!filter || IS_ERR(filter) || !path)
		return ERR_PTR(-EINVAL);

	info = kzalloc(sizeof(struct redirfs_path_info), GFP_KERNEL);
	if (!info)
		return ERR_PTR(-ENOMEM);

	rfs_mutex_lock(&rfs_path_mutex);

	if (rfs_chain_find(rpath->rinch, filter) != -1)
		info->flags = REDIRFS_PATH_INCLUDE;

	else if (rfs_chain_find(rpath->rexch, filter) != -1)
		info->flags = REDIRFS_PATH_EXCLUDE;

	rfs_mutex_unlock(&rfs_path_mutex);

	if (!info->flags) {
		kfree(info);
		return ERR_PTR(-ENODATA);
	}

	info->mnt = mntget(rpath->mnt);
	info->dentry = dget(rpath->dentry);

	return info;
}

void redirfs_put_path_info(struct redirfs_path_info *info)
{
	if (!info)
		return;

	mntput(info->mnt);
	dput(info->dentry);
	kfree(info);
}

int redirfs_rem_paths(redirfs_filter filter)
{
	redirfs_path *paths;
	int rv = 0;
	int i = 0;

	if (!filter || IS_ERR(filter))
		return -EINVAL;

	paths = redirfs_get_paths(filter);
	if (IS_ERR(paths))
		return PTR_ERR(paths);

	while (paths[i]) {
		rv = redirfs_rem_path(filter, paths[i]);
		if (rv)
			break;
		i++;
	}

	redirfs_put_paths(paths);

	return rv;
}

int rfs_path_get_info(struct rfs_flt *rflt, char *buf, int size)
{
	struct rfs_path *rpath;
	char *path;
	char type;
	int len = 0;
	int rv;

	path = kzalloc(sizeof(char) * PAGE_SIZE, GFP_KERNEL);
	if (!path)
		return -ENOMEM;

	rfs_mutex_lock(&rfs_path_mutex);

	list_for_each_entry(rpath, &rfs_path_list, list) {
		if (rfs_chain_find(rpath->rinch, rflt) != -1)
			type = 'i';

		else if (rfs_chain_find(rpath->rexch, rflt) != -1)
			type = 'e';

		else
			continue;

		rv = redirfs_get_filename(rpath->mnt, rpath->dentry, path,
				PAGE_SIZE);

		if (rv) {
			rfs_mutex_unlock(&rfs_path_mutex);
			kfree(path);
			return rv;
		}

		len += snprintf(buf + len, size - len,"%c:%d:%s",
				type, rpath->id, path) + 1;

		if (len >= size) {
			len = size;
			break;
		}
	}

	rfs_mutex_unlock(&rfs_path_mutex);
	kfree(path);

	return len;
}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))

int redirfs_get_filename(struct vfsmount *mnt, struct dentry *dentry, char *buf,
		int size)
{
	char *fn;
	size_t len;

	fn = d_path(dentry, mnt, buf, size);
	if (IS_ERR(fn))
		return PTR_ERR(fn);

	len = strlen(fn);
	memmove(buf, fn, len);
	buf[len] = 0;
	return 0;
}

#else

int redirfs_get_filename(struct vfsmount *mnt, struct dentry *dentry, char *buf,
		int size)
{
	struct path path;
	char *fn;	
	size_t len;

	path.mnt = mnt;
	path.dentry = dentry;
	fn = d_path(&path, buf, size);
	if (IS_ERR(fn))
		return PTR_ERR(fn);

	len = strlen(fn);
	memmove(buf, fn, len);
	buf[len] = 0;
	return 0;
}

#endif

static int rfs_fsrename_rem_rroot(struct rfs_root *rroot,
		struct rfs_chain *rchain)
{
	int rv;
	int i;

	if (!rchain)
		return 0;

	for (i = 0; i < rchain->rflts_nr; i++) {
		rv = rfs_root_rem_flt(rroot, rchain->rflts[i]);
		if (rv)
			return rv;

		rv = rfs_root_walk(rfs_root_rem_flt, rchain->rflts[i]);
		if (rv)
			return rv;
	}

	return 0;
}

static int rfs_fsrename_rem_dentry(struct rfs_root *rroot,
		struct rfs_chain *rchain, struct dentry *dentry)
{
	struct rfs_chain *rchnew = NULL;
	struct rfs_chain *rchrem = NULL;
	struct rfs_info *rinfo = NULL;
	int rv = 0;
	int i;

	if (!rchain)
		return 0;

	rchrem = rfs_chain_get(rroot->rinfo->rchain);

	for (i = 0; i < rchain->rflts_nr; i++) {
		rchnew = rfs_chain_rem(rchrem, rchain->rflts[i]);
		if (IS_ERR(rchnew)) {
			rv = PTR_ERR(rchnew);
			goto exit;
		}

		rfs_chain_put(rchrem);
		rchrem = rchnew;
		rinfo = rfs_info_alloc(rroot, rchnew);
		if (IS_ERR(rinfo)) {
			rv = PTR_ERR(rinfo);
			goto exit;
		}

		rv = rfs_info_rem(dentry, rinfo, rchain->rflts[i]);
		rfs_info_put(rinfo);
		if (rv)
			goto exit;
	}
exit:
	rfs_chain_put(rchrem);
	return rv;
}

static int rfs_fsrename_rem(struct rfs_root *rroot_src,
		struct rfs_root *rroot_dst, struct dentry *dentry)
{
	struct rfs_chain *rchain = NULL;
	int rv;

	if (!rroot_src)
		return 0;

	if (!rroot_dst)
		rchain = rfs_chain_get(rroot_src->rinfo->rchain);
	else
		rchain = rfs_chain_diff(rroot_src->rinfo->rchain,
				rroot_dst->rinfo->rchain);

	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	if (rroot_src->dentry == dentry) 
		rv = rfs_fsrename_rem_rroot(rroot_src, rchain);
	else
		rv = rfs_fsrename_rem_dentry(rroot_src, rchain, dentry);

	rfs_chain_put(rchain);
	return rv;
}

static int rfs_fsrename_add_rroot(struct rfs_root *rroot,
		struct rfs_chain *rchain)
{
	int rv;
	int i;

	if (!rchain)
		return 0;

	for (i = 0; i < rchain->rflts_nr; i++) {
		rv = rfs_root_add_flt(rroot, rchain->rflts[i]);
		if (rv)
			return rv;

		rv = rfs_root_walk(rfs_root_add_flt, rchain->rflts[i]);
		if (rv)
			return rv;
	}

	return 0;
}

static int rfs_fsrename_add_dentry(struct rfs_root *rroot,
		struct rfs_chain *rchain, struct dentry *dentry)
{
	struct rfs_chain *rchnew = NULL;
	struct rfs_chain *rchadd = NULL;
	struct rfs_dentry *rdentry = NULL;
	struct rfs_info *rinfo = NULL;
	int rv = 0;
	int i;

	if (!rchain)
		return rfs_info_reset(dentry, rroot->rinfo);

	rdentry = rfs_dentry_find(dentry);
	if (rdentry)
		rchadd = rfs_chain_get(rdentry->rinfo->rchain);

	for (i = 0; i < rchain->rflts_nr; i++) {
		rchnew = rfs_chain_add(rchadd, rchain->rflts[i]);
		if (IS_ERR(rchnew)) {
			rv = PTR_ERR(rchnew);
			goto exit;
		}

		rfs_chain_put(rchadd);
		rchadd = rchnew;
		rinfo = rfs_info_alloc(rroot, rchnew);
		if (IS_ERR(rinfo)) {
			rv = PTR_ERR(rinfo);
			goto exit;
		}

		rv = rfs_info_add(dentry, rinfo, rchain->rflts[i]);
		rfs_info_put(rinfo);
		if (rv)
			goto exit;
	}

	rv = rfs_info_reset(dentry, rroot->rinfo);
exit:
	rfs_dentry_put(rdentry);
	rfs_chain_put(rchadd);
	return rv;
}

static int rfs_fsrename_add(struct rfs_root *rroot_src,
		struct rfs_root *rroot_dst, struct dentry *dentry)
{
	struct rfs_chain *rchain = NULL;
	int rv;

	if (!rroot_dst)
		return 0;

	if (!rroot_src)
		rchain = rfs_chain_get(rroot_dst->rinfo->rchain);
	else
		rchain = rfs_chain_diff(rroot_dst->rinfo->rchain,
				rroot_src->rinfo->rchain);

	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	if (rroot_src && rroot_src->dentry == dentry) 
		rv = rfs_fsrename_add_rroot(rroot_src, rchain);
	else
		rv = rfs_fsrename_add_dentry(rroot_dst, rchain, dentry);

	rfs_chain_put(rchain);
	return rv;
}

static int rfs_fsrename_set(struct rfs_root *rroot_src,
		struct rfs_root *rroot_dst, struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct rfs_chain *rchain_src;
	struct rfs_chain *rchain_dst;
	struct rfs_info *rinfo;
	int rv = 0;
	int i;

	if (!rroot_src || !rroot_dst)
		return 0;

	if (rroot_src->dentry == dentry) 
		return 0;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return 0;

	rchain_src = rdentry->rinfo->rchain;
	rchain_dst = rroot_dst->rinfo->rchain;

	for (i = 0; i < rchain_src->rflts_nr; i++) {
		if (rfs_chain_find(rchain_dst, rchain_src->rflts[i]) == -1)
			continue;

		rinfo = rfs_info_alloc(rroot_dst, rchain_src);
		if (IS_ERR(rinfo)) {
			rv = PTR_ERR(rinfo);
			goto exit;
		}

		rv = rfs_info_set(dentry, rinfo, rchain_src->rflts[i]);
		rfs_info_put(rinfo);
		if (rv)
			goto exit;
	}
exit:
	rfs_dentry_put(rdentry);
	return rv;
}

int rfs_fsrename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
	struct rfs_root *rroot_src = NULL;
	struct rfs_root *rroot_dst = NULL;
	struct rfs_inode *rinode = NULL;
	struct rfs_dentry *rdentry = NULL;
	int rv = 0;

	if (old_dir == new_dir)
		return 0;

	rfs_mutex_lock(&rfs_path_mutex);

	rinode = rfs_inode_find(new_dir);
	rdentry = rfs_dentry_find(old_dentry);

	if (rinode->rinfo->rchain)
		rroot_dst = rfs_root_get(rinode->rinfo->rroot);

	if (rdentry && rdentry->rinfo->rchain)
		rroot_src = rfs_root_get(rdentry->rinfo->rroot);

	if (rroot_src == rroot_dst) 
		goto exit;

	rv = rfs_fsrename_rem(rroot_src, rroot_dst, old_dentry);
	if (rv)
		goto exit;

	rv = rfs_fsrename_set(rroot_src, rroot_dst, old_dentry);
	if (rv)
		goto exit;

	rv = rfs_fsrename_add(rroot_src, rroot_dst, old_dentry);
exit:
	rfs_mutex_unlock(&rfs_path_mutex);
	rfs_root_put(rroot_src);
	rfs_root_put(rroot_dst);
	rfs_inode_put(rinode);
	rfs_dentry_put(rdentry);
	return rv;
}

EXPORT_SYMBOL(redirfs_get_path);
EXPORT_SYMBOL(redirfs_put_path);
EXPORT_SYMBOL(redirfs_get_paths);
EXPORT_SYMBOL(redirfs_get_paths_root);
EXPORT_SYMBOL(redirfs_put_paths);
EXPORT_SYMBOL(redirfs_get_path_info);
EXPORT_SYMBOL(redirfs_put_path_info);
EXPORT_SYMBOL(redirfs_add_path);
EXPORT_SYMBOL(redirfs_rem_path);
EXPORT_SYMBOL(redirfs_rem_paths);
EXPORT_SYMBOL(redirfs_get_filename);
EXPORT_SYMBOL(redirfs_get_id_path);
EXPORT_SYMBOL(redirfs_get_path_id);

driver/redirfs/rfs_root.c0000644000076400007640000002560412112622747015355 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

LIST_HEAD(rfs_root_list);
LIST_HEAD(rfs_root_walk_list);

static struct rfs_root *rfs_root_alloc(struct dentry *dentry)
{
	struct rfs_root *rroot;

	rroot = kzalloc(sizeof(struct rfs_root), GFP_KERNEL);
	if (!rroot)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rroot->list);
	INIT_LIST_HEAD(&rroot->walk_list);
	INIT_LIST_HEAD(&rroot->rpaths);
	INIT_LIST_HEAD(&rroot->data);
	rroot->dentry = dentry;
	rroot->paths_nr = 0;
	spin_lock_init(&rroot->lock);
	atomic_set(&rroot->count, 1);

	return rroot;
}

struct rfs_root *rfs_root_get(struct rfs_root *rroot)
{
	if (!rroot || IS_ERR(rroot))
		return NULL;

	BUG_ON(!atomic_read(&rroot->count));
	atomic_inc(&rroot->count);

	return rroot;
}

void rfs_root_put(struct rfs_root *rroot)
{
	if (!rroot || IS_ERR(rroot))
		return;

	BUG_ON(!atomic_read(&rroot->count));
	if (!atomic_dec_and_test(&rroot->count))
		return;

	rfs_chain_put(rroot->rinch);
	rfs_chain_put(rroot->rexch);
	rfs_data_remove(&rroot->data);
	kfree(rroot);
}

static struct rfs_root *rfs_root_find(struct dentry *dentry)
{
	struct rfs_root *rroot = NULL;
	struct rfs_root *found = NULL;

	list_for_each_entry(rroot, &rfs_root_list, list) {
		if (rroot->dentry != dentry)
			continue;

		found = rfs_root_get(rroot);
		break;
	}

	return found;
}

static void rfs_root_list_add(struct rfs_root *rroot)
{
	list_add_tail(&rroot->list, &rfs_root_list);
	rfs_root_get(rroot);
}

static void rfs_root_list_rem(struct rfs_root *rroot)
{
	list_del_init(&rroot->list);
	rfs_root_put(rroot);
}

void rfs_root_add_rpath(struct rfs_root *rroot, struct rfs_path *rpath)
{
	rroot->paths_nr++;
	list_add_tail(&rpath->rroot_list, &rroot->rpaths);
	rfs_path_get(rpath);
}

void rfs_root_rem_rpath(struct rfs_root *rroot, struct rfs_path *rpath)
{
	rroot->paths_nr--;
	list_del_init(&rpath->rroot_list);

	if (!list_empty(&rroot->rpaths)) {
		rfs_path_put(rpath);
		return;
	}

	rfs_path_put(rpath);
	rfs_root_list_rem(rroot);
}

struct rfs_root *rfs_root_add(struct dentry *dentry)
{
	struct rfs_root *rroot;

	rroot = rfs_root_find(dentry);
	if (rroot)
		return rroot;

	rroot = rfs_root_alloc(dentry);
	if (IS_ERR(rroot))
		return rroot;

	rfs_root_list_add(rroot);

	return rroot;
}

static int rfs_root_flt_num(struct rfs_root *rroot, struct rfs_flt *rflt,
		int type)
{
	struct rfs_chain *rchain;
	struct rfs_path *rpath;
	int num = 0;

	list_for_each_entry(rpath, &rroot->rpaths, rroot_list) {
		if (type & REDIRFS_PATH_INCLUDE)
			rchain = rpath->rinch;
		else
			rchain = rpath->rexch;

		if (rfs_chain_find(rchain, rflt) != -1)
			num++;
	}

	return num;
}

int rfs_root_add_include(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_chain *rinch;
	int rv;

	if (rfs_chain_find(rroot->rinch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rexch, rflt) != -1)
		return -EEXIST;

	rinch = rfs_chain_add(rroot->rinch, rflt);
	if (IS_ERR(rinch))
		return PTR_ERR(rinch);

	rv = rfs_info_add_include(rroot, rflt);
	if (rv) {
		rfs_chain_put(rinch);
		return rv;
	}

	spin_lock(&rroot->lock);
	rfs_chain_put(rroot->rinch);
	rroot->rinch = rinch;
	spin_unlock(&rroot->lock);
	return 0;
}

int rfs_root_add_exclude(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_chain *rexch ;
	int rv;

	if (rfs_chain_find(rroot->rexch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rinch, rflt) != -1)
		return -EEXIST;

	rexch = rfs_chain_add(rroot->rexch, rflt);
	if (IS_ERR(rexch))
		return PTR_ERR(rexch);

	rv = rfs_info_add_exclude(rroot, rflt);
	if (rv) {
		rfs_chain_put(rexch);
		return rv;
	}

	spin_lock(&rroot->lock);
	rfs_chain_put(rroot->rexch);
	rroot->rexch = rexch;
	spin_unlock(&rroot->lock);
	return 0;
}

int rfs_root_rem_include(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_chain *rinch;
	struct redirfs_data *data;
	int rv;

	if (rfs_root_flt_num(rroot, rflt, REDIRFS_PATH_INCLUDE) > 1)
		return 0;

	rinch = rfs_chain_rem(rroot->rinch, rflt);
	if (IS_ERR(rinch))
		return PTR_ERR(rinch);

	rv = rfs_info_rem_include(rroot, rflt);
	if (rv) {
		rfs_chain_put(rinch);
		return rv;
	}

	spin_lock(&rroot->lock);
	rfs_chain_put(rroot->rinch);
	rroot->rinch = rinch;
	spin_unlock(&rroot->lock);
	data = redirfs_detach_data_root(rflt, rroot);
	if (data && data->detach)
		data->detach(data);
	redirfs_put_data(data);
	return 0;
}

int rfs_root_rem_exclude(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_chain *rexch;
	struct redirfs_data *data;
	int rv;

	if (rfs_root_flt_num(rroot, rflt, REDIRFS_PATH_EXCLUDE) > 1)
		return 0;

	rexch = rfs_chain_rem(rroot->rexch, rflt);
	if (IS_ERR(rexch))
		return PTR_ERR(rexch);

	rv = rfs_info_rem_exclude(rroot, rflt);
	if (rv) {
		rfs_chain_put(rexch);
		return rv;
	}

	spin_lock(&rroot->lock);
	rfs_chain_put(rroot->rexch);
	rroot->rexch = rexch;
	spin_unlock(&rroot->lock);
	data = redirfs_detach_data_root(rflt, rroot);
	if (data && data->detach)
		data->detach(data);
	redirfs_put_data(data);
	return 0;
}

int rfs_root_add_flt(struct rfs_root *rroot, void *data)
{
	struct rfs_chain *rchain = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_dcache_data *rdata = NULL;
	struct rfs_flt *rflt = (struct rfs_flt *)data;
	int rv = 0;

	if (rfs_chain_find(rroot->rinch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rexch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rinfo->rchain, rflt) != -1)
		return 0;

	rchain = rfs_chain_add(rroot->rinfo->rchain, rflt);
	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	rdata = rfs_dcache_data_alloc(rroot->dentry, rinfo, rflt);
	if (IS_ERR(rdata)) {
		rv = PTR_ERR(rdata);
		goto exit;
	}

	rv = rfs_dcache_walk(rroot->dentry, rfs_dcache_add, rdata);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_dcache_data_free(rdata);
	rfs_chain_put(rchain);
	rfs_info_put(rinfo);
	return rv;
}

int rfs_root_rem_flt(struct rfs_root *rroot, void *data)
{
	struct rfs_chain *rchain = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_dcache_data *rdata = NULL;
	struct rfs_flt *rflt = (struct rfs_flt *)data;
	int rv = 0;

	if (rfs_chain_find(rroot->rinch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rexch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rinfo->rchain, rflt) == -1)
		return 0;

	rchain = rfs_chain_rem(rroot->rinfo->rchain, rflt);
	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	rdata = rfs_dcache_data_alloc(rroot->dentry, rinfo, rflt);
	if (IS_ERR(rdata)) {
		rv = PTR_ERR(rdata);
		goto exit;
	}

	rv = rfs_dcache_walk(rroot->dentry, rfs_dcache_rem, rdata);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_dcache_data_free(rdata);
	rfs_chain_put(rchain);
	rfs_info_put(rinfo);
	return rv;
}

int rfs_root_walk(int (*cb)(struct rfs_root *, void *), void *data)
{
	struct rfs_root *rroot;
	struct rfs_root *tmp;
	int rv = 0;

	while (!list_empty(&rfs_root_walk_list)) {
		rroot = list_entry(rfs_root_walk_list.next, struct rfs_root,
				walk_list);
		rv = cb(rroot, data);
		if (rv)
			break;

		list_del_init(&rroot->walk_list);
	}

	list_for_each_entry_safe(rroot, tmp, &rfs_root_walk_list, walk_list) {
		list_del_init(&rroot->walk_list);
	}

	return rv;
}

void rfs_root_add_walk(struct dentry *dentry)
{
	struct rfs_dentry *rdentry = NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		goto error;

	if (!rdentry->rinfo)
		goto error;

	if (rdentry->rinfo->rroot->dentry != dentry)
		goto error;

	list_add_tail(&rdentry->rinfo->rroot->walk_list, &rfs_root_walk_list);

error:
	rfs_dentry_put(rdentry);
	return;
}

static struct rfs_root *rfs_get_root_flt(struct rfs_flt *rflt,
		struct rfs_info *rinfo_start)
{
	struct rfs_root *rroot = NULL;
	struct rfs_info *rinfo;

	rinfo = rfs_info_get(rinfo_start);

	while (rinfo) {
		if (rfs_chain_find(rinfo->rchain, rflt) == -1)
			goto exit;

		rroot = rfs_root_get(rinfo->rroot);
		if (!rroot)
			goto exit;

		spin_lock(&rroot->lock);

		if (rfs_chain_find(rroot->rinch, rflt) != -1) {
			spin_unlock(&rroot->lock);
			goto exit;

		}

		spin_unlock(&rroot->lock);

		rfs_info_put(rinfo);
		rinfo = rfs_info_parent(rroot->dentry);
		rfs_root_put(rroot);
		rroot = NULL;
	}

exit:
	rfs_info_put(rinfo);
	return rroot;
}

redirfs_root redirfs_get_root_file(redirfs_filter filter, struct file *file)
{
	struct rfs_root *rroot;
	struct rfs_file *rfile;
	struct rfs_info *rinfo;

	if (!filter || IS_ERR(filter) || !file)
		return NULL;

	rfile = rfs_file_find(file);
	if (!rfile)
		return NULL;

	rinfo = rfs_dentry_get_rinfo(rfile->rdentry);

	rroot = rfs_get_root_flt(filter, rinfo);

	rfs_info_put(rinfo);
	rfs_file_put(rfile);
	return rroot;
}

redirfs_root redirfs_get_root_dentry(redirfs_filter filter,
		struct dentry *dentry)
{
	struct rfs_root *rroot;
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;

	if (!filter || IS_ERR(filter) || !dentry)
		return NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	rinfo = rfs_dentry_get_rinfo(rdentry);

	rroot = rfs_get_root_flt(filter, rinfo);

	rfs_info_put(rinfo);
	rfs_dentry_put(rdentry);
	return rroot;
}

redirfs_root redirfs_get_root_inode(redirfs_filter filter, struct inode *inode)
{
	struct rfs_root *rroot;
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;

	if (!filter || IS_ERR(filter) || !inode)
		return NULL;

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return NULL;

	rinfo = rfs_inode_get_rinfo(rinode);

	rroot = rfs_get_root_flt(filter, rinfo);

	rfs_info_put(rinfo);
	rfs_inode_put(rinode);
	return rroot;
}

redirfs_root redirfs_get_root_path(redirfs_path path)
{
	struct rfs_path *rpath = path;

	if (!path)
		return NULL;

	return rfs_root_get(rpath->rroot);
}

redirfs_root redirfs_get_root(redirfs_root root)
{
	return rfs_root_get(root);
}

void redirfs_put_root(redirfs_root root)
{
	rfs_root_put(root);
}

void rfs_root_set_rinfo(struct rfs_root *rroot, struct rfs_info *rinfo)
{
	rfs_info_put(rroot->rinfo);
	rroot->rinfo = rfs_info_get(rinfo);
}

EXPORT_SYMBOL(redirfs_get_root_file);
EXPORT_SYMBOL(redirfs_get_root_dentry);
EXPORT_SYMBOL(redirfs_get_root_inode);
EXPORT_SYMBOL(redirfs_get_root_path);
EXPORT_SYMBOL(redirfs_get_root);
EXPORT_SYMBOL(redirfs_put_root);

driver/redirfs/CHANGELOG0000644000076400007640000001345512112622747014567 0ustar  comodocomodoversion 0.11 experimental 2011-09-05
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- added pre_rename and post_rename callback to redirfs_filter_operations
		- this can be used by filter to be notified about files moved
		  inside a filter's path within one file system
	- support for 2.6.38+ kernels
	- redirfs_get_filename is now just a simple wrapper around d_path and it
	  returns a filename just for the first mount point.

version 0.10 2010-05-20
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- reflected changes in 2.6.34 kernel
		- include of <linux/slab.h>
		- removeved unnecessary checks in rfs_setattr_default

version 0.9 2010-04-06
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed RHEL 5.4 address_space_operations_ext hang by removing
	  address_space_operations support 
	  thanks to Vasiliy Novikov <vasiliy.novikov@gmail.com>
	- removed rfs_dcache_rdentry_add_check since it causes too many problems
	  when dentry operations were assigned from the root dentry
	  thanks to Vasiliy Novikov <vasiliy.novikov@gmail.com>

version 0.8
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed rfs dentry addition for isofs
	  thanks to Vasiliy Novikov <vasiliy.novikov@gmail.com>
	- support for kernels >= 2.6.12
	  thanks to Vasiliy Novikov <vasiliy.novikov@gmail.com>
	- reflected changes in the follow_up function interface in 2.6.31
	- fixed filter reference counter, kref_get() warning on zero counter 
	
version 0.7
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- used dget_locked instead of direct increase of d_count
          it allows redirfs to run at kernel with openvz patches
	- added callbacks
		REDIRFS_DIR_IOP_UNLINK
		REDIRFS_DIR_IOP_RMDIR
		REDIRFS_REG_IOP_SETATTR
		REDIRFS_DIR_IOP_SETATTR
		REDIRFS_LNK_IOP_SETATTR
		REDIRFS_CHR_IOP_SETATTR
		REDIRFS_BLK_IOP_SETATTR
		REDIRFS_FIFO_IOP_SETATTR
		REDIRFS_SOCK_IOP_SETATTR
		REDIRFS_NONE_DOP_D_REVALIDATE
		REDIRFS_REG_DOP_D_REVALIDATE
		REDIRFS_DIR_DOP_D_REVALIDATE
		REDIRFS_CHR_DOP_D_REVALIDATE
		REDIRFS_BLK_DOP_D_REVALIDATE
		REDIRFS_FIFO_DOP_D_REVALIDATE
		REDIRFS_LNK_DOP_D_REVALIDATE
		REDIRFS_SOCK_DOP_D_REVALIDATE
	- added might_sleep() macro into functions which can sleep
	- fixed locking in redirfs_get_path_id()
	- removed GFP_ATOMIC allocations where possible and added GFP_KERNEL
	  allocation fallbacks otherwise, BUG 14
	- better filter handle check in redirfs API, added IS_ERR check
	- fixed bind mount paths - two paths one root
	- added support for older kernels >= 2.6.16, thanks to Sergey Ivanov
	- fixed open with the O_DIRECTORY flag for non directory file types,
	  thanks to Sergey Ivanov
	- cifs is not supported
	  the -EPERM error is returned when path is to be added within cifs

version 0.6
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed bug 13 - oops BUG at rfs_inode.c:306!

version 0.5
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed NULL pointer dereference in rfs_fsrename_set

version 0.4
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- added support for private data - file, dentry, inode, redirfs root
	- introduced redirfs_root handle representing redirfs root object
	- simplified sysfs interface
	- small changes in the redirfs interface (not compatible with previous
	  versions)
	- redirfs_ctl control callbacks replaced with generic
	  redirfs_filter_operations table
	- fixed rinfo memory leak

version 0.3
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- reflected changes in the permission function interface
	- fixed rdentry NULL dereference in rfs_fsrename
	- rfs_lookup adds only dirs while there are no registered filters

version 0.3-pre4
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- reworked global rename handling
	- makefile cleanup

	* John Ogness <redirfs@ogness.net> 
	- fixed wrong reference usage in rfs_path_get

version 0.3-pre3
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- removed usage of RCU due to CONFIG_PREEMPT_RCU
	- redirfs is now a permanent module which cannot be unloaded
	- fixed dead lock in rfs_dcache_walk and rfs_fsrename
	- redirect readdir instead of d_compare to check newly added vfs objects(NFS)
	- fixed removing of path attached to the file system root
	- cleanup of the redirfs_get_filename function
	- fixed full path name for the file system root
	- added check if filter is active in post calls
	- correct destruction of inode objects in the rfs_d_iput function
	- rinode objects are removed in the rfs_d_iput function
	- rdentry objects are removed in the rfs_d_release function
	- fixed NULL pointer dereferences in the rfs_fsrename functions

version 0.3-pre2
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed removing of rfs_file objects
	- added support for file systems which are adding dentry/inode objects
	  during readdir (e.g. NFS)

version 0.3-pre1
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- rewritten from scratch
	- new path management
	- new sysfs interface
	- new redirfs framework interface
	- supports kernel version 2.6.25 and higher
	- not all features introduced in the 0.2 version implemented yet
		- missing support for filter's private data
		- missing support for address space operations
		- limited set of redirected operations

version 0.2.1
	* never released, experimental support for sub-mounts

	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed bug 09: crash on rdentry_set_ops when changing path
	- fixed bug 10: include subtree after include single path causes crash
	- fixed bug 11: added rename support
	- added support for sub-mounts and sub-unmounts
	- added support for rename
	- changed rfs_get_filename interface, now it requires vfsmount object

	* Paolo Ambrosio <paolo.ambrosio@gmail.com>
	- fixed typo RFS_REG_AOP_COMMINT_WRITE => RFS_REG_AOP_COMMIT_WRITE
	- fixed bug 12: added mmap callback

version 0.2
	* rewritten from scratch

version 0.1
	* first stable version with limited functionality

driver/redirfs/redirfs.h0000644000076400007640000003643712112622747015171 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _REDIRFS_H
#define _REDIRFS_H

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/types.h>
#include <linux/aio.h>
#include <linux/version.h>

#define REDIRFS_VERSION "0.11 EXPERIMENTAL"

#define REDIRFS_PATH_INCLUDE		1
#define REDIRFS_PATH_EXCLUDE		2

#define REDIRFS_FILTER_ATTRIBUTE(__name, __mode, __show, __store) \
	__ATTR(__name, __mode, __show, __store)

enum redirfs_op_id {
	REDIRFS_NONE_DOP_D_REVALIDATE,
	/* REDIRFS_NONE_DOP_D_HASH, */
	REDIRFS_NONE_DOP_D_COMPARE,
	/* REDIRFS_NONE_DOP_D_DELETE, */
	REDIRFS_NONE_DOP_D_RELEASE,
	REDIRFS_NONE_DOP_D_IPUT,
	/* REDIRFS_NODE_DOP_D_NAME, */

	REDIRFS_REG_DOP_D_REVALIDATE,
	/* REDIRFS_REG_DOP_D_HASH, */
	REDIRFS_REG_DOP_D_COMPARE,
	/* REDIRFS_REG_DOP_D_DELETE, */
	REDIRFS_REG_DOP_D_RELEASE,
	REDIRFS_REG_DOP_D_IPUT,
	/* REDIRFS_REG_DOP_D_NAME, */

	REDIRFS_DIR_DOP_D_REVALIDATE,
	/* REDIRFS_DIR_DOP_D_HASH, */
	REDIRFS_DIR_DOP_D_COMPARE,
	/* REDIRFS_DIR_DOP_D_DELETE, */
	REDIRFS_DIR_DOP_D_RELEASE,
	REDIRFS_DIR_DOP_D_IPUT,
	/* REDIRFS_DIR_DOP_D_NAME, */

	REDIRFS_CHR_DOP_D_REVALIDATE,
	/* REDIRFS_CHR_DOP_D_HASH, */
	REDIRFS_CHR_DOP_D_COMPARE,
	/* REDIRFS_CHR_DOP_D_DELETE, */
	REDIRFS_CHR_DOP_D_RELEASE,
	REDIRFS_CHR_DOP_D_IPUT,
	/* REDIRFS_CHR_DOP_D_NAME, */

	REDIRFS_BLK_DOP_D_REVALIDATE,
	/* REDIRFS_BLK_DOP_D_HASH, */
	REDIRFS_BLK_DOP_D_COMPARE,
	/* REDIRFS_BLK_DOP_D_DELETE, */
	REDIRFS_BLK_DOP_D_RELEASE,
	REDIRFS_BLK_DOP_D_IPUT,
	/* REDIRFS_BLK_DOP_D_NAME, */

	REDIRFS_FIFO_DOP_D_REVALIDATE,
	/* REDIRFS_FIFO_DOP_D_HASH, */
	REDIRFS_FIFO_DOP_D_COMPARE,
	/* REDIRFS_FIFO_DOP_D_DELETE, */
	REDIRFS_FIFO_DOP_D_RELEASE,
	REDIRFS_FIFO_DOP_D_IPUT,
	/* REDIRFS_FIFO_DOP_D_NAME, */

	REDIRFS_LNK_DOP_D_REVALIDATE,
	/* REDIRFS_LNK_DOP_D_HASH, */
	REDIRFS_LNK_DOP_D_COMPARE,
	/* REDIRFS_LNK_DOP_D_DELETE, */
	REDIRFS_LNK_DOP_D_RELEASE,
	REDIRFS_LNK_DOP_D_IPUT,
	/* REDIRFS_LNK_DOP_D_NAME, */

	REDIRFS_SOCK_DOP_D_REVALIDATE,
	/* REDIRFS_SOCK_DOP_D_HASH, */
	REDIRFS_SOCK_DOP_D_COMPARE,
	/* REDIRFS_SOCK_DOP_D_DELETE, */
	REDIRFS_SOCK_DOP_D_RELEASE,
	REDIRFS_SOCK_DOP_D_IPUT,
	/* REDIRFS_SOCK_DOP_D_NAME, */

	REDIRFS_REG_IOP_PERMISSION,
	REDIRFS_REG_IOP_SETATTR,

	REDIRFS_DIR_IOP_CREATE,
	REDIRFS_DIR_IOP_LOOKUP,
	REDIRFS_DIR_IOP_LINK,
	REDIRFS_DIR_IOP_UNLINK,
	REDIRFS_DIR_IOP_SYMLINK, 
	REDIRFS_DIR_IOP_MKDIR,
	REDIRFS_DIR_IOP_RMDIR,
	REDIRFS_DIR_IOP_MKNOD,
	REDIRFS_DIR_IOP_RENAME,
	REDIRFS_DIR_IOP_PERMISSION,
	REDIRFS_DIR_IOP_SETATTR,

	REDIRFS_CHR_IOP_PERMISSION,
	REDIRFS_CHR_IOP_SETATTR,

	REDIRFS_BLK_IOP_PERMISSION,
	REDIRFS_BLK_IOP_SETATTR,

	REDIRFS_FIFO_IOP_PERMISSION,
	REDIRFS_FIFO_IOP_SETATTR,

	REDIRFS_LNK_IOP_PERMISSION,
	REDIRFS_LNK_IOP_SETATTR,

	REDIRFS_SOCK_IOP_PERMISSION,
	REDIRFS_SOCK_IOP_SETATTR,

	REDIRFS_REG_FOP_OPEN,
	REDIRFS_REG_FOP_RELEASE,
	/* REDIRFS_REG_FOP_LLSEEK, */
	/* REDIRFS_REG_FOP_READ, */
	/* REDIRFS_REG_FOP_WRITE, */
	/* REDIRFS_REG_FOP_AIO_READ, */
	/* REDIRFS_REG_FOP_AIO_WRITE, */
	/* REDIRFS_REG_FOP_MMAP, */
	/* REDIRFS_REG_FOP_FLUSH, */

	REDIRFS_DIR_FOP_OPEN,
	REDIRFS_DIR_FOP_RELEASE,
	REDIRFS_DIR_FOP_READDIR,
	/* REDIRFS_DIR_FOP_FLUSH, */

	REDIRFS_CHR_FOP_OPEN,
	REDIRFS_CHR_FOP_RELEASE,
	/* REDIRFS_CHR_FOP_LLSEEK, */
	/* REDIRFS_CHR_FOP_READ, */
	/* REDIRFS_CHR_FOP_WRITE, */
	/* REDIRFS_CHR_FOP_AIO_READ, */
	/* REDIRFS_CHR_FOP_AIO_WRITE, */
	/* REDIRFS_CHR_FOP_FLUSH, */

	REDIRFS_BLK_FOP_OPEN,
	REDIRFS_BLK_FOP_RELEASE,
	/* REDIRFS_BLK_FOP_LLSEEK, */
	/* REDIRFS_BLK_FOP_READ, */
	/* REDIRFS_BLK_FOP_WRITE, */
	/* REDIRFS_BLK_FOP_AIO_READ, */
	/* REDIRFS_BLK_FOP_AIO_WRITE, */
	/* REDIRFS_BLK_FOP_FLUSH, */

	REDIRFS_FIFO_FOP_OPEN,
	REDIRFS_FIFO_FOP_RELEASE,
	/* REDIRFS_FIFO_FOP_LLSEEK, */
	/* REDIRFS_FIFO_FOP_READ, */
	/* REDIRFS_FIFO_FOP_WRITE, */
	/* REDIRFS_FIFO_FOP_AIO_READ, */
	/* REDIRFS_FIFO_FOP_AIO_WRITE, */
	/* REDIRFS_FIFO_FOP_FLUSH, */

	REDIRFS_LNK_FOP_OPEN,
	REDIRFS_LNK_FOP_RELEASE,
	/* REDIRFS_LNK_FOP_LLSEEK, */
	/* REDIRFS_LNK_FOP_READ, */
	/* REDIRFS_LNK_FOP_WRITE, */
	/* REDIRFS_LNK_FOP_AIO_READ, */
	/* REDIRFS_LNK_FOP_AIO_WRITE, */
	/* REDIRFS_LNK_FOP_FLUSH, */

	/* REDIRFS_REG_AOP_READPAGE, */
	/* REDIRFS_REG_AOP_WRITEPAGE, */
	/* REDIRFS_REG_AOP_READPAGES, */
	/* REDIRFS_REG_AOP_WRITEPAGES, */
	/* REDIRFS_REG_AOP_SYNC_PAGE, */
	/* REDIRFS_REG_AOP_SET_PAGE_DIRTY, */
	/* REDIRFS_REG_AOP_PREPARE_WRITE, */
	/* REDIRFS_REG_AOP_COMMIT_WRITE, */
	/* REDIRFS_REG_AOP_BMAP, */
	/* REDIRFS_REG_AOP_INVALIDATEPAGE, */
	/* REDIRFS_REG_AOP_RELEASEPAGE, */
	/* REDIRFS_REG_AOP_DIRECT_IO, */
	/* REDIRFS_REG_AOP_GET_XIP_PAGE, */
	/* REDIRFS_REG_AOP_MIGRATEPAGE, */
	/* REDIRFS_REG_AOP_LAUNDER_PAGE, */

	REDIRFS_OP_END
};

enum redirfs_op_call {
	REDIRFS_PRECALL,
	REDIRFS_POSTCALL
};

enum redirfs_rv {
	REDIRFS_STOP,
	REDIRFS_CONTINUE
};

typedef void *redirfs_filter;
typedef void *redirfs_context;
typedef void *redirfs_path;
typedef void *redirfs_root;

union redirfs_op_rv {
	int		rv_int;
	ssize_t		rv_ssize;
	unsigned int	rv_uint;
	unsigned long	rv_ulong;
	loff_t		rv_loff;
	struct dentry	*rv_dentry;
	sector_t	rv_sector;
	struct page	*rv_page;
};

union redirfs_op_args {
	struct {
		struct dentry *dentry;
		struct nameidata *nd;
	} d_revalidate;	

	/*
	struct {
		struct dentry *dentry;
		struct qstr *name;
	} d_hash;
	*/

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
	struct {
		struct dentry *dentry;
		struct qstr *name1;
		struct qstr *name2;
	} d_compare;
#else
	struct {
		const struct dentry *parent;
		const struct inode *inode;
		const struct dentry *dentry;
		const struct inode *d_inode;
		unsigned int tlen;
		const char *tname;
		const struct qstr *name;
	} d_compare;
#endif

	/*
	struct {
		struct dentry *dentry;
	} d_delete;
	*/

	struct {
		struct dentry *dentry;
	} d_release;

	struct {
		struct dentry *dentry;
		struct inode *inode;
	} d_iput;	

	struct {
		struct inode *dir;
		struct dentry *dentry;
		int mode;
		struct nameidata *nd;
	} i_create;

	struct {
		struct inode *dir;
		struct dentry *dentry;
		struct nameidata *nd;
	} i_lookup;

	struct {
		struct dentry *old_dentry;
		struct inode *dir;
		struct dentry *dentry;
	} i_link;

	struct {
		struct inode *dir;
		struct dentry *dentry;
	} i_unlink;

	struct {
		struct inode *dir;
		struct dentry *dentry;
		const char *oldname;
	} i_symlink;

	struct {
		struct inode *dir;
		struct dentry *dentry;
		int mode;
	} i_mkdir;

	struct {
		struct inode *dir;
		struct dentry *dentry;
	} i_rmdir;

	struct {
		struct inode *dir;
		struct dentry *dentry;
		int mode;
		dev_t rdev;
	} i_mknod;

	struct {
		struct inode *old_dir;
		struct dentry *old_dentry;
		struct inode *new_dir;
		struct dentry *new_dentry;
	} i_rename;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
	struct {
		struct inode *inode;
		int mask;
		struct nameidata *nd;
	} i_permission;
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
	struct {
		struct inode *inode;
		int mask;
	} i_permission;
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
	struct {
		struct inode *inode;
		int mask;
		unsigned int flags;
	} i_permission;
#else
	struct {
		struct inode *inode;
		int mask;
	} i_permission;
#endif

	struct {
		struct dentry *dentry;
		struct iattr *iattr;
	} i_setattr;

	struct {
		struct inode *inode;
		struct file *file;
	} f_open;

	struct {
		struct inode *inode;
		struct file *file;
	} f_release;

	/*
	struct {
		struct file *file;
		fl_owner_t id;
	} f_flush;
	*/

	/*
	struct {
		struct file *file;
		struct vm_area_struct *vma;
	} f_mmap;
	*/

	struct {
		struct file *file;
		void *dirent;
		filldir_t filldir;
	} f_readdir;

	/*
	struct {
                struct file *file;
                loff_t offset;
                int origin;
	} f_llseek;
	*/

	/*
	struct {
		struct file *file;
		char __user *buf;
		size_t count;
		loff_t *pos;
	} f_read;
	*/

	/*
	struct {
		struct file *file;
		const char __user *buf;
		size_t count;
		loff_t *pos;
	} f_write;
	*/

	/*
	struct {
		struct kiocb *iocb;
		const struct iovec *iov;
		unsigned long nr_segs;
		loff_t pos;
	} f_aio_read;
	*/

	/*
	struct {
		struct kiocb *iocb;
		const struct iovec *iov;
		unsigned long nr_segs;
		loff_t pos;
	} f_aio_write;
	*/

	/*
	struct {
		struct file *file;
		struct page *page;
	} a_readpage;
	*/

	/*
	struct {
		struct page *page;
		struct writeback_control *wbc;
	} a_writepage;
	*/

	/*
	struct {
		struct file *file;
		struct address_space *mapping;
		struct list_head *pages;
		unsigned nr_pages;
	} a_readpages;
	*/

	/*
	struct {
		struct address_space *mapping;
		struct writeback_control *wbc;
	} a_writepages;
	*/

	/*
	struct {
		struct page *page;
	} a_sync_page;
	*/

	/*
	struct {
		struct page *page;
	} a_set_page_dirty;
	*/

	/*
	struct {
		struct file *file;
		struct page *page;
		unsigned from;
		unsigned to;
	} a_prepare_write;
	*/

	/*
	struct {
		struct file *file;
		struct page *page;
		unsigned from;
		unsigned to;
	} a_commit_write;
	*/

	/*
	struct {
		struct address_space *mapping;
		sector_t block;
	} a_bmap;
	*/

	/*
	struct {
		struct page *page;
		unsigned long offset;
	} a_invalidatepage;
	*/

	/*
	struct {
		struct page *page;
		gfp_t flags;
	} a_releasepage;
	*/

	/*
	struct {
		int rw;
		struct kiocb *iocb;
		const struct iovec *iov;
		loff_t offset;
		unsigned long nr_segs;
	} a_direct_IO;
	*/

	/*
	struct {
		struct address_space *mapping;
		sector_t offset;
		int create;
	} a_get_xip_page;
	*/

	/*
	struct {
		struct address_space *mapping;
		struct page *newpage;
		struct page *page;
	} a_migratepage;
	*/

	/*
	struct {
		struct page *page;
	} a_launder_page;
	*/
};

struct redirfs_op_type {
	enum redirfs_op_id id;
	enum redirfs_op_call call;
};

struct redirfs_args {
	union redirfs_op_args args;
	union redirfs_op_rv rv;
	struct redirfs_op_type type;
};

struct redirfs_path_info {
	struct dentry *dentry;
	struct vfsmount *mnt;
	int flags;
};

struct redirfs_op_info {
	enum redirfs_op_id op_id;
	enum redirfs_rv (*pre_cb)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv (*post_cb)(redirfs_context, struct redirfs_args *);
};

struct redirfs_filter_operations {
	int (*activate)(void);
	int (*deactivate)(void);
	int (*add_path)(struct redirfs_path_info *);
	int (*rem_path)(redirfs_path);
	int (*unregister)(void);
	int (*rem_paths)(void);
	void (*move_begin)(void);
	void (*move_end)(void);
	int (*dentry_moved)(redirfs_root, redirfs_root, struct dentry *);
	int (*inode_moved)(redirfs_root, redirfs_root, struct inode *);
	enum redirfs_rv (*pre_rename)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv (*post_rename)(redirfs_context, struct redirfs_args *);
};

struct redirfs_filter_info {
	struct module *owner;
	const char *name;
	int priority;
	int active;
	struct redirfs_filter_operations *ops;
};

struct redirfs_filter_attribute {
	struct attribute attr;
	ssize_t (*show)(redirfs_filter filter,
			struct redirfs_filter_attribute *attr, char *buf);
	ssize_t (*store)(redirfs_filter filter,
			struct redirfs_filter_attribute *attr, const char *buf,
			size_t count);
};

struct redirfs_data {
	struct list_head list;
	atomic_t cnt;
	redirfs_filter filter;
	void (*free)(struct redirfs_data *);
	void (*detach)(struct redirfs_data *);
};

int redirfs_create_attribute(redirfs_filter filter,
		struct redirfs_filter_attribute *attr);
int redirfs_remove_attribute(redirfs_filter filter,
		struct redirfs_filter_attribute *attr);
struct kobject *redirfs_filter_kobject(redirfs_filter filter);
redirfs_path redirfs_add_path(redirfs_filter filter,
		struct redirfs_path_info *info);
int redirfs_rem_path(redirfs_filter filter, redirfs_path path);
int redirfs_get_id_path(redirfs_path path);
redirfs_path redirfs_get_path_id(int id);
redirfs_path redirfs_get_path(redirfs_path path);
void redirfs_put_path(redirfs_path path);
redirfs_path* redirfs_get_paths_root(redirfs_filter filter, redirfs_root root);
redirfs_path* redirfs_get_paths(redirfs_filter filter);
void redirfs_put_paths(redirfs_path *paths);
struct redirfs_path_info *redirfs_get_path_info(redirfs_filter filter,
		redirfs_path path);
void redirfs_put_path_info(struct redirfs_path_info *info);
int redirfs_rem_paths(redirfs_filter filter);
redirfs_root redirfs_get_root_file(redirfs_filter filter, struct file *file);
redirfs_root redirfs_get_root_dentry(redirfs_filter filter,
		struct dentry *dentry);
redirfs_root redirfs_get_root_inode(redirfs_filter filter, struct inode *inode);
redirfs_root redirfs_get_root_path(redirfs_path path);
redirfs_root redirfs_get_root(redirfs_root root);
void redirfs_put_root(redirfs_root root);
redirfs_filter redirfs_register_filter(struct redirfs_filter_info *info);
int redirfs_unregister_filter(redirfs_filter filter);
void redirfs_delete_filter(redirfs_filter filter);
int redirfs_set_operations(redirfs_filter filter, struct redirfs_op_info ops[]);
int redirfs_activate_filter(redirfs_filter filter);
int redirfs_deactivate_filter(redirfs_filter filter);
int redirfs_get_filename(struct vfsmount *mnt, struct dentry *dentry, char *buf,
		int size);
int redirfs_init_data(struct redirfs_data *data, redirfs_filter filter,
		void (*free)(struct redirfs_data *),
		void (*detach)(struct redirfs_data *));
struct redirfs_data *redirfs_get_data(struct redirfs_data *data);
void redirfs_put_data(struct redirfs_data *data);
struct redirfs_data *redirfs_attach_data_file(redirfs_filter filter,
		struct file *file, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_file(redirfs_filter filter,
		struct file *file);
struct redirfs_data *redirfs_get_data_file(redirfs_filter filter,
		struct file *file);
struct redirfs_data *redirfs_attach_data_dentry(redirfs_filter filter,
		struct dentry *dentry, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_dentry(redirfs_filter filter,
		struct dentry *dentry);
struct redirfs_data *redirfs_get_data_dentry(redirfs_filter filter,
		struct dentry *dentry);
struct redirfs_data *redirfs_attach_data_inode(redirfs_filter filter,
		struct inode *inode, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_inode(redirfs_filter filter,
		struct inode *inode);
struct redirfs_data *redirfs_get_data_inode(redirfs_filter filter,
		struct inode *inode);
struct redirfs_data *redirfs_attach_data_context(redirfs_filter filter,
		redirfs_context context, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_context(redirfs_filter filter,
		redirfs_context context);
struct redirfs_data *redirfs_get_data_context(redirfs_filter filter,
		redirfs_context context);
struct redirfs_data *redirfs_attach_data_root(redirfs_filter filter,
		redirfs_root root, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_root(redirfs_filter filter,
		redirfs_root root);
struct redirfs_data *redirfs_get_data_root(redirfs_filter filter,
		redirfs_root root);
#endif

driver/redirfs/INSTALL0000644000076400007640000000204012112622747014372 0ustar  comodocomodo			======================================
				 Installing RedirFS
			======================================

1. Requirements
	
	* Running Linux kernel version 2.6.16 and higher
	* Source code and configuration for running Linux kernel
	  - at least make scripts and make prepare
	* Linux kernel compiled with modules support

2. Download
	
	* Get the latest stable version at
	  http://www.redirfs.org/packages/redirfs-x.y.tar.gz

3. Compilation
	
	* Unpack package
		$ tar -xvzf redirfs-x.y.tar.gz

	* Change to the redirfs-x.y directory
		$ cd redirfs-x.y

	* Run make command
		$ make -C /lib/modules/`uname -r`/build M=`pwd` modules

4. Inserting module

	* Change user to root
		$ su

	* Install module
		# make -C /lib/modules/`uname -r`/build M=`pwd` modules_install

	* Update module dependencies
		# depmod -a

	* Load redirfs.ko module
		# modprobe redirfs

5. Problems & Bugs

	* RedirFS's bugzilla
	  http://www.redirfs.org/cgi-bin/bugzilla/index.cgi
	
	* RedirFS's mailing lists
	  http://www.redirfs.org/tiki-index.php?page=redirfs_maillists
driver/redirfs/rfs.c0000644000076400007640000000554512112622747014314 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

struct rfs_info *rfs_info_none;

int rfs_precall_flts(struct rfs_chain *rchain, struct rfs_context *rcont,
		struct redirfs_args *rargs)
{
	enum redirfs_rv (*rop)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv rv;

	if (!rchain)
		return 0;

	rargs->type.call = REDIRFS_PRECALL;

	rcont->idx = rcont->idx_start;

	for (; rcont->idx < rchain->rflts_nr; rcont->idx++) {
		if (!atomic_read(&rchain->rflts[rcont->idx]->active))
			continue;

		rop = rchain->rflts[rcont->idx]->cbs[rargs->type.id].pre_cb;
		if (!rop)
			continue;

		rv = rop(rcont, rargs);
		if (rv == REDIRFS_STOP)
			return -1;
	}

	rcont->idx--;

	return 0;
}

void rfs_postcall_flts(struct rfs_chain *rchain, struct rfs_context *rcont,
		struct redirfs_args *rargs)
{
	enum redirfs_rv (*rop)(redirfs_context, struct redirfs_args *);

	if (!rchain)
		return;

	rargs->type.call = REDIRFS_POSTCALL;

	for (; rcont->idx >= rcont->idx_start; rcont->idx--) {
		if (!atomic_read(&rchain->rflts[rcont->idx]->active))
			continue;

		rop = rchain->rflts[rcont->idx]->cbs[rargs->type.id].post_cb;
		if (rop) 
			rop(rcont, rargs);
	}

	rcont->idx++;
}

static int __init rfs_init(void)
{
	int rv;

	rfs_info_none = rfs_info_alloc(NULL, NULL);
	if (IS_ERR(rfs_info_none))
		return PTR_ERR(rfs_info_none);

	rv = rfs_dentry_cache_create();
	if (rv)
		goto err_dentry_cache;

	rv = rfs_inode_cache_create();
	if (rv)
		goto err_inode_cache;

	rv = rfs_file_cache_create();
	if (rv)
		goto err_file_cache;

	rv = rfs_sysfs_create();
	if (rv)
		goto err_sysfs;

	printk(KERN_INFO "Redirecting File System Framework Version "
			REDIRFS_VERSION " <www.redirfs.org>\n");

	return 0;

err_sysfs:
	rfs_file_cache_destory();
err_file_cache:
	rfs_inode_cache_destroy();
err_inode_cache:
	rfs_dentry_cache_destory();
err_dentry_cache:
	rfs_info_put(rfs_info_none);
	return rv;
}

module_init(rfs_init);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Frantisek Hrbata <frantisek.hrbata@redirfs.org>");
MODULE_DESCRIPTION("Redirecting File System Framework Version "
		REDIRFS_VERSION " <www.redirfs.org>");

driver/redirfs/rfs_dcache.c0000644000076400007640000002163312112622747015577 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

struct rfs_dcache_data *rfs_dcache_data_alloc(struct dentry *dentry,
		struct rfs_info *rinfo, struct rfs_flt *rflt)
{
	struct rfs_dcache_data *rdata;

	rdata = kzalloc(sizeof(struct rfs_dcache_data), GFP_KERNEL);
	if (!rdata)
		return ERR_PTR(-ENOMEM);

	rdata->rinfo = rinfo;
	rdata->rflt = rflt;
	rdata->droot = dentry;

	return rdata;
}

void rfs_dcache_data_free(struct rfs_dcache_data *rdata)
{
	if (!rdata || IS_ERR(rdata))
		return;

	kfree(rdata);
}

static struct rfs_dcache_entry *rfs_dcache_entry_alloc_locked(
		struct dentry *dentry, struct list_head *list)
{
	struct rfs_dcache_entry *entry;

	entry = kzalloc(sizeof(struct rfs_dcache_entry), GFP_ATOMIC);
	if (!entry)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&entry->list);
	entry->dentry = rfs_dget_locked(dentry);
	list_add_tail(&entry->list, list);

	return entry;
}

static struct rfs_dcache_entry *rfs_dcache_entry_alloc(struct dentry *dentry,
		struct list_head *list)
{
	struct rfs_dcache_entry *entry;

	entry = kzalloc(sizeof(struct rfs_dcache_entry), GFP_KERNEL);
	if (!entry)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&entry->list);
	entry->dentry = dget(dentry);
	list_add_tail(&entry->list, list);

	return entry;
}

static void rfs_dcache_entry_free(struct rfs_dcache_entry *entry)
{
	if (!entry)
		return;

	list_del_init(&entry->list);
	dput(entry->dentry);
	kfree(entry);
}

static int rfs_dcache_get_subs_atomic(struct dentry *dir,
		struct list_head *sibs)
{
	struct rfs_dcache_entry *sib;
	struct dentry *dentry;
	int rv = 0;

	rfs_dcache_lock(dir);

	rfs_for_each_d_child(dentry, &dir->d_subdirs) {

		sib = rfs_dcache_entry_alloc_locked(dentry, sibs);
		if (IS_ERR(sib)) {
			rv = PTR_ERR(sib);
			break;
		}
	}

	rfs_dcache_unlock(dir);

	return rv;
}

static int rfs_dcache_get_subs_kernel(struct dentry *dir,
		struct list_head *sibs)
{
	LIST_HEAD(pool);
	int pool_size = 32;
	int pool_small;
	struct rfs_dcache_entry *sib;
	struct dentry *dentry;
	int i;

again:
	pool_small = 0;

	for (i = 0; i < pool_size; i++) {
		sib = rfs_dcache_entry_alloc(NULL, &pool);
		if (IS_ERR(sib)) {
			rfs_dcache_entry_free_list(&pool);
			return PTR_ERR(sib);
		}
	}

	rfs_dcache_lock(dir);

	rfs_for_each_d_child(dentry, &dir->d_subdirs) {
		if (list_empty(&pool)) {
			pool_small = 1;
			break;
		}
		
		sib = list_entry(pool.next, struct rfs_dcache_entry, list);
		sib->dentry = rfs_dget_locked(dentry);
		list_move(&sib->list, sibs);
	}

	rfs_dcache_unlock(dir);

	rfs_dcache_entry_free_list(&pool);

	if (pool_small) {
		rfs_dcache_entry_free_list(sibs);
		pool_size *= 2;
		goto again;
	}

	return 0;
}

int rfs_dcache_get_subs(struct dentry *dir, struct list_head *sibs)
{
	int rv;

	rv = rfs_dcache_get_subs_atomic(dir, sibs);
	if (!rv)
		return rv;

	rfs_dcache_entry_free_list(sibs);
	
	rv = rfs_dcache_get_subs_kernel(dir, sibs);

	return rv;
}

void rfs_dcache_entry_free_list(struct list_head *head)
{
	struct rfs_dcache_entry *entry;
	struct rfs_dcache_entry *tmp;

	list_for_each_entry_safe(entry, tmp, head, list) {
		rfs_dcache_entry_free(entry);
	}
}

static int rfs_dcache_get_subs_mutex(struct dentry *dir, struct list_head *sibs)
{
	int rv = 0;

	if (!dir || !dir->d_inode)
		return 0;

	rfs_inode_mutex_lock(dir->d_inode);
	rv = rfs_dcache_get_subs(dir, sibs);
	rfs_inode_mutex_unlock(dir->d_inode);

	return rv;
}

static int rfs_dcache_get_dirs(struct list_head *dirs, struct list_head *sibs)
{
	struct rfs_dcache_entry *entry;
	struct rfs_dcache_entry *dir;
	struct rfs_dcache_entry *tmp;

	list_for_each_entry_safe(entry, tmp, sibs, list) {
		if (!entry->dentry->d_inode)
			continue;

		if (!S_ISDIR(entry->dentry->d_inode->i_mode))
			continue;

		dir = rfs_dcache_entry_alloc(entry->dentry, dirs);
		if (IS_ERR(dir))
			return PTR_ERR(dir);

		rfs_dcache_entry_free(entry);
	}

	return 0;
}

int rfs_dcache_walk(struct dentry *root, int (*cb)(struct dentry *, void *),
		void *data)
{
	LIST_HEAD(dirs);
	LIST_HEAD(sibs);
	struct rfs_dcache_entry *dir;
	struct rfs_dcache_entry *sib;
	int rv = 0;

	dir = rfs_dcache_entry_alloc(root, &dirs);
	if (IS_ERR(dir))
		return PTR_ERR(dir);

	while (!list_empty(&dirs)) {
		dir = list_entry(dirs.next, struct rfs_dcache_entry, list);

		rv = cb(dir->dentry, data);
		if (rv < 0)
			goto exit;

		if (rv > 0 || !dir->dentry->d_inode) {
			rfs_dcache_entry_free(dir);
			rv = 0;
			continue;
		}

		rv = rfs_dcache_get_subs_mutex(dir->dentry, &sibs);
		if (rv)
			goto exit;

		rv = rfs_dcache_get_dirs(&dirs, &sibs);
		if (rv)
			goto exit;

		list_for_each_entry(sib, &sibs, list) {
			rv = cb(sib->dentry, data);
			if (rv < 0)
				goto exit;
		}
		rfs_dcache_entry_free_list(&sibs);
		rfs_dcache_entry_free(dir);
	}
exit:
	list_splice(&sibs, &dirs);
	rfs_dcache_entry_free_list(&dirs);

	return rv;
}

static int rfs_dcache_skip(struct dentry *dentry, struct rfs_dcache_data *rdata)
{
	struct rfs_dentry *rdentry = NULL;
	int rv = 0;

	if (dentry == rdata->droot)
		return 0;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return 0;

	if (!rdentry->rinfo)
		goto exit;

	if (!rdentry->rinfo->rroot)
		goto exit;

	if (rdentry->rinfo->rroot->dentry != dentry)
		goto exit;

	rv = 1;
exit:
	rfs_dentry_put(rdentry);
	return rv;
}

int rfs_dcache_rdentry_add(struct dentry *dentry, struct rfs_info *rinfo)
{
	struct rfs_dentry *rdentry = NULL;
	int rv = 0;

	rdentry = rfs_dentry_add(dentry, rinfo);
	if (IS_ERR(rdentry))
		return PTR_ERR(rdentry);

	rfs_dentry_set_rinfo(rdentry, rinfo);

	rv = rfs_dentry_add_rinode(rdentry, rinfo);
	if (rv)
		goto exit;

	rv = rfs_inode_set_rinfo(rdentry->rinode);
	if (rv)
		goto exit;

	rfs_dentry_set_ops(rdentry);
exit:
	rfs_dentry_put(rdentry);
	return rv;
}

int rfs_dcache_rinode_del(struct rfs_dentry *rdentry, struct inode *inode)
{
	struct rfs_inode *rinode = NULL;
	int rv = 0;

	rfs_dentry_rem_rinode(rdentry);

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return 0;

	rv = rfs_inode_set_rinfo(rinode);
	if (rv) {
		rfs_inode_put(rinode);
		return rv;
	}

	rfs_inode_set_ops(rinode);
	rfs_inode_put(rinode);

	return 0;
}

static int rfs_dcache_rdentry_del(struct dentry *dentry, struct rfs_info *rinfo)
{
	struct rfs_dentry *rdentry = NULL;
	int rv = 0;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return 0;

	rfs_dentry_set_rinfo(rdentry, rinfo);
	rv = rfs_inode_set_rinfo(rdentry->rinode);
	if (rv)
		goto exit;

	rfs_dentry_set_ops(rdentry);
exit:
	rfs_dentry_put(rdentry);
	return rv;
}

int rfs_dcache_add_dir(struct dentry *dentry, void *data)
{
	if (!dentry->d_inode)
		return 0;

	if (!S_ISDIR(dentry->d_inode->i_mode))
		return 0;

	return rfs_dcache_rdentry_add(dentry, rfs_info_none);
}

int rfs_dcache_add(struct dentry *dentry, void *data)
{
	struct rfs_dcache_data *rdata = data;

	if (rfs_dcache_skip(dentry, rdata)) {
		rfs_root_add_walk(dentry);
		return 1;
	}

	return rfs_dcache_rdentry_add(dentry, rdata->rinfo);
}

int rfs_dcache_rem(struct dentry *dentry, void *data)
{
	struct rfs_dcache_data *rdata = data;
	int rv;

	if (rfs_dcache_skip(dentry, rdata)) {
		rfs_root_add_walk(dentry);
		return 1;
	}

	if (rdata->rinfo->rchain)
		return rfs_dcache_rdentry_add(dentry, rdata->rinfo);

	rv = rfs_dcache_rdentry_del(dentry, rfs_info_none);
	if (rv)
		return rv;

	rfs_dentry_rem_data(dentry, rdata->rflt);
	return 0;
}

int rfs_dcache_set(struct dentry *dentry, void *data)
{
	struct rfs_dcache_data *rdata = data;
	struct rfs_dentry *rdentry = NULL;
	struct rfs_root *rroot = NULL;
	int rv = 0;

	if (rfs_dcache_skip(dentry, rdata))
		return 1;

	if (!rdata->rinfo->rchain)
		return rfs_dcache_rdentry_del(dentry, rfs_info_none);

	rdentry = rfs_dentry_find(dentry);
	if (rdentry)
		rroot = rfs_root_get(rdentry->rinfo->rroot);

	rv = rfs_dcache_rdentry_add(dentry, rdata->rinfo);
	if (rv)
		goto exit;

	if (!rroot)
		goto exit;

	if (rroot == rdata->rinfo->rroot)
		goto exit;

	rv = rfs_dentry_move(dentry, rdata->rflt, rroot, rdata->rinfo->rroot);
exit:
	rfs_dentry_put(rdentry);
	rfs_root_put(rroot);
	return rv;
}

int rfs_dcache_reset(struct dentry *dentry, void *data)
{
	struct rfs_dcache_data *rdata = data;

	if (rfs_dcache_skip(dentry, rdata))
		return 1;

	if (!rdata->rinfo->rchain)
		return rfs_dcache_rdentry_del(dentry, rfs_info_none);

	return rfs_dcache_rdentry_add(dentry, rdata->rinfo);
}

driver/redirfs/rfs_sysfs.c0000644000076400007640000003175712112622747015547 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

#define rfs_kattr_to_rattr(__kattr) \
	container_of(__kattr, struct redirfs_filter_attribute, attr)

static struct rfs_flt *rfs_sysfs_flt_get(struct rfs_flt *rflt)
{
	spin_lock(&rflt->lock);

	if (atomic_read(&rflt->count) < 3) {
		spin_unlock(&rflt->lock);
		return ERR_PTR(-ENOENT);
	}

	rfs_flt_get(rflt);

	spin_unlock(&rflt->lock);

	return rflt;
}

static ssize_t rfs_flt_show(struct kobject *kobj, struct attribute *attr,
		char *buf)
{
	struct rfs_flt *rflt = rfs_kobj_to_rflt(kobj);
	struct redirfs_filter_attribute *rattr = rfs_kattr_to_rattr(attr);
	ssize_t rv;

	rflt = rfs_sysfs_flt_get(rflt);
	if (IS_ERR(rflt))
		return PTR_ERR(rflt);

	rv = rattr->show(rflt, rattr, buf);

	rfs_flt_put(rflt);

	return rv;
}

static ssize_t rfs_flt_store(struct kobject *kobj, struct attribute *attr,
		const char *buf, size_t count)
{
	struct rfs_flt *rflt = rfs_kobj_to_rflt(kobj);
	struct redirfs_filter_attribute *rattr = rfs_kattr_to_rattr(attr);
	ssize_t rv;

	if (strcmp(attr->name, "unregister") == 0)
		return rattr->store(rflt, rattr, buf, count);

	rflt = rfs_sysfs_flt_get(rflt);
	if (IS_ERR(rflt))
		return PTR_ERR(rflt);

	rv = rattr->store(rflt, rattr, buf, count);

	rfs_flt_put(rflt);

	return rv;
}

static ssize_t rfs_flt_priority_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	struct rfs_flt *rflt = filter;

	return snprintf(buf, PAGE_SIZE, "%d", rflt->priority);
}

static ssize_t rfs_flt_active_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	struct rfs_flt *rflt = filter;

	return snprintf(buf, PAGE_SIZE, "%d",
			atomic_read(&rflt->active));
}

static ssize_t rfs_flt_active_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	int act;
	int rv;

	if (sscanf(buf, "%d", &act) != 1)
		return -EINVAL;

	if (act) {
		if (rflt->ops && rflt->ops->activate)
			rv = rflt->ops->activate();
		else
			rv = redirfs_activate_filter(filter);

	} else {
		if (rflt->ops && rflt->ops->deactivate)
			rv = rflt->ops->deactivate();
		else
			rv = redirfs_deactivate_filter(filter);
	}

	if (rv)
		return rv;

	return count;
}

static ssize_t rfs_flt_paths_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	struct rfs_flt *rflt = filter;
	
	return rfs_path_get_info(rflt, buf, PAGE_SIZE);
}

static int rfs_flt_paths_add(redirfs_filter filter, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	struct rfs_path *rpath;
	struct redirfs_path_info info;
	struct nameidata nd;
	char *path;
	char type;
	int rv;

	path = kzalloc(sizeof(char) * PAGE_SIZE, GFP_KERNEL);
	if (!path)
		return -ENOMEM;

	if (sscanf(buf, "a:%c:%s", &type, path) != 2) {
		kfree(path);
		return -EINVAL;
	}

	if (type == 'i')
		info.flags = REDIRFS_PATH_INCLUDE;

	else if (type == 'e')
		info.flags = REDIRFS_PATH_EXCLUDE;

	else {
		kfree(path);
		return -EINVAL;
	}

	rv = rfs_path_lookup(path, &nd);
	if (rv) {
		kfree(path);
		return rv;
	}

	info.dentry = rfs_nameidata_dentry(&nd);
	info.mnt = rfs_nameidata_mnt(&nd);

	if (!rflt->ops || !rflt->ops->add_path) {
		rpath = redirfs_add_path(filter, &info);
		if (IS_ERR(rpath))
			rv = PTR_ERR(rpath);
		rfs_path_put(rpath);

	} else
		rv = rflt->ops->add_path(&info);

	rfs_nameidata_put(&nd);
	kfree(path);

	return rv;
}

static int rfs_flt_paths_rem(redirfs_filter filter, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	struct rfs_path *rpath;
	int id;
	int rv;

	if (sscanf(buf, "r:%d", &id) != 1)
		return -EINVAL;

	rfs_mutex_lock(&rfs_path_mutex);
	rpath = rfs_path_find_id(id);
	if (!rpath) {
		rfs_mutex_unlock(&rfs_path_mutex);
		return -ENOENT;
	}
	rfs_mutex_unlock(&rfs_path_mutex);
	
	if (rflt->ops && rflt->ops->rem_path)
		rv = rflt->ops->rem_path(rpath);
	else
		rv = redirfs_rem_path(filter, rpath);

	rfs_path_put(rpath);

	return rv;
}

static int rfs_flt_paths_clean(redirfs_filter filter, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	char clean;
	int rv;

	if (sscanf(buf, "%c", &clean) != 1)
		return -EINVAL;

	if (clean != 'c')
		return -EINVAL;

	if (rflt->ops && rflt->ops->rem_paths)
		rv = rflt->ops->rem_paths();
	else
		rv = redirfs_rem_paths(filter);

	return rv;
}

static ssize_t rfs_flt_paths_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	int rv;

	if (count < 2)
		return -EINVAL;

	if (*buf == 'a')
		rv = rfs_flt_paths_add(filter, buf, count);

	else if (*buf == 'r')
		rv = rfs_flt_paths_rem(filter, buf, count);

	else if (*buf == 'c')
		rv = rfs_flt_paths_clean(filter, buf, count);

	else
		rv = -EINVAL;

	if (rv)
		return rv;

	return count;
}

static ssize_t rfs_flt_unregister_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	int unreg;
	int rv;

	if (sscanf(buf, "%d", &unreg) != 1)
		return -EINVAL;

	if (unreg != 1)
		return -EINVAL;

	if (rflt->ops && rflt->ops->unregister)
		rv = rflt->ops->unregister();
	else
		rv = redirfs_unregister_filter(filter);

	if (rv)
		return rv;

	return count;
}

static struct redirfs_filter_attribute rfs_flt_priority_attr =
	REDIRFS_FILTER_ATTRIBUTE(priority, 0444, rfs_flt_priority_show, NULL);

static struct redirfs_filter_attribute rfs_flt_active_attr = 
	REDIRFS_FILTER_ATTRIBUTE(active, 0644, rfs_flt_active_show,
			rfs_flt_active_store);

static struct redirfs_filter_attribute rfs_flt_paths_attr = 
	REDIRFS_FILTER_ATTRIBUTE(paths, 0644, rfs_flt_paths_show,
			rfs_flt_paths_store);

static struct redirfs_filter_attribute rfs_flt_unregister_attr = 
	REDIRFS_FILTER_ATTRIBUTE(unregister, 0200, NULL,
			rfs_flt_unregister_store);

static struct attribute *rfs_flt_attrs[] = {
	&rfs_flt_priority_attr.attr,
	&rfs_flt_active_attr.attr,
	&rfs_flt_paths_attr.attr,
	&rfs_flt_unregister_attr.attr,
	NULL
};

static struct kset *rfs_flt_kset;

static struct sysfs_ops rfs_sysfs_ops = {
	.show = rfs_flt_show,
	.store = rfs_flt_store
};

struct kobj_type rfs_flt_ktype = {
	.sysfs_ops = &rfs_sysfs_ops,
	.release = rfs_flt_release,
	.default_attrs = rfs_flt_attrs
};

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
static struct kobject *rfs_fs_kobj;
static struct kobject *rfs_kobj;

static inline void rfs_kobj_release(struct kobject *kobj)
{
	kfree(kobj);
}

static struct kobj_type rfs_kobj_ktype = {
	.release = rfs_kobj_release
};

int rfs_sysfs_create(void)
{
	int rv;

	rfs_fs_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
	if (!rfs_fs_kobj)
		return -ENOMEM;

	kobject_init(rfs_fs_kobj);
	rfs_fs_kobj->ktype = &rfs_kobj_ktype;
	rv = kobject_set_name(rfs_fs_kobj, "%s", "fs");
	if (rv) {
		kobject_put(rfs_fs_kobj);
		return rv;
	}

	rv = kobject_register(rfs_fs_kobj);
	if (rv) {
		kobject_put(rfs_fs_kobj);
		return rv;
	}

	rv = -ENOMEM;
	rfs_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
	if (!rfs_kobj) 
		goto err_fs_kobj;

	kobject_init(rfs_kobj);
	rfs_kobj->ktype = &rfs_kobj_ktype;
	rfs_kobj->parent = rfs_fs_kobj;
	rv = kobject_set_name(rfs_kobj, "%s", "redirfs");
	if (rv) {
		kobject_put(rfs_kobj);
		goto err_fs_kobj;
	}

	rv = kobject_register(rfs_kobj);
	if (rv) {
		kobject_put(rfs_kobj);
		goto err_fs_kobj;
	}

	rv = -ENOMEM;
	rfs_flt_kset = kzalloc(sizeof(struct kset), GFP_KERNEL);
	if (!rfs_flt_kset)
		goto err_rfs_kobj;

	kobject_init(&rfs_flt_kset->kobj);
	rfs_flt_kset->kobj.ktype = &rfs_kobj_ktype;
	rfs_flt_kset->kobj.parent = rfs_kobj;
	rv = kobject_set_name(&rfs_flt_kset->kobj, "%s", "filters");
	if (rv) 
		goto err_kset;

	rv = kset_register(rfs_flt_kset);
	if (rv)
		goto err_kset;

	return 0;

err_kset:
	kset_put(rfs_flt_kset);
err_rfs_kobj:
	kobject_unregister(rfs_kobj);
err_fs_kobj:
	kobject_unregister(rfs_fs_kobj);
	return rv;
}
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
static struct kobject *rfs_kobj;

static inline void rfs_kobj_release(struct kobject *kobj)
{
	kfree(kobj);
}

static struct kobj_type rfs_kobj_ktype = {
	.release = rfs_kobj_release
};

int rfs_sysfs_create(void)
{
	int rv;

	rfs_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
	if (!rfs_kobj)
		return -ENOMEM;

	kobject_init(rfs_kobj);
	rfs_kobj->ktype = &rfs_kobj_ktype;
	rfs_kobj->parent = &fs_subsys.kset.kobj;
	rv = kobject_set_name(rfs_kobj, "%s", "redirfs");
	if (rv) {
		kobject_put(rfs_kobj);
		return rv;
	}

	rv = kobject_register(rfs_kobj);
	if (rv) {
		kobject_put(rfs_kobj);
		return rv;
	}

	rv = -ENOMEM;
	rfs_flt_kset = kzalloc(sizeof(struct kset), GFP_KERNEL);
	if (!rfs_flt_kset)
		goto err_kobj;

	kobject_init(&rfs_flt_kset->kobj);
	rfs_flt_kset->kobj.ktype = &rfs_kobj_ktype;
	rfs_flt_kset->kobj.parent = rfs_kobj;
	rv = kobject_set_name(&rfs_flt_kset->kobj, "%s", "filters");
	if (rv) 
		goto err_kset;

	rv = kset_register(rfs_flt_kset);
	if (rv)
		goto err_kset;

	return 0;

err_kset:
	kset_put(rfs_flt_kset);
err_kobj:
	kobject_unregister(rfs_kobj);
	return rv;
}
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
static struct kobject *rfs_kobj;

static inline void rfs_kobj_release(struct kobject *kobj)
{
	kfree(kobj);
}

static struct kobj_type rfs_kobj_ktype = {
	.release = rfs_kobj_release
};

int rfs_sysfs_create(void)
{
	int rv;

	rfs_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
	if (!rfs_kobj)
		return -ENOMEM;

	kobject_init(rfs_kobj);
	rfs_kobj->ktype = &rfs_kobj_ktype;
	rfs_kobj->parent = &fs_subsys.kobj;
	rv = kobject_set_name(rfs_kobj, "%s", "redirfs");
	if (rv) {
		kobject_put(rfs_kobj);
		return rv;
	}

	rv = kobject_register(rfs_kobj);
	if (rv) {
		kobject_put(rfs_kobj);
		return rv;
	}

	rv = -ENOMEM;
	rfs_flt_kset = kzalloc(sizeof(struct kset), GFP_KERNEL);
	if (!rfs_flt_kset)
		goto err_kobj;

	kobject_init(&rfs_flt_kset->kobj);
	rfs_flt_kset->kobj.ktype = &rfs_kobj_ktype;
	rfs_flt_kset->kobj.parent = rfs_kobj;
	rv = kobject_set_name(&rfs_flt_kset->kobj, "%s", "filters");
	if (rv) 
		goto err_kset;

	rv = kset_register(rfs_flt_kset);
	if (rv)
		goto err_kset;

	return 0;

err_kset:
	kset_put(rfs_flt_kset);
err_kobj:
	kobject_unregister(rfs_kobj);
	return rv;
}
#else
static struct kobject *rfs_kobj;

int rfs_sysfs_create(void)
{
	rfs_kobj = kobject_create_and_add("redirfs", fs_kobj);
	if (!rfs_kobj)
		return -ENOMEM;

	rfs_flt_kset = kset_create_and_add("filters", NULL, rfs_kobj);
	if (!rfs_flt_kset) {
		kobject_put(rfs_kobj);
		return -ENOMEM;
	}

	return 0;
}
#endif

int redirfs_create_attribute(redirfs_filter filter,
		struct redirfs_filter_attribute *attr)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || !attr)
		return -EINVAL;

	return sysfs_create_file(&rflt->kobj, &attr->attr);
}

int redirfs_remove_attribute(redirfs_filter filter,
		struct redirfs_filter_attribute *attr)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || !attr)
		return -EINVAL;

	sysfs_remove_file(&rflt->kobj, &attr->attr);

	return 0;
}

struct kobject *redirfs_filter_kobject(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || IS_ERR(rflt))
		return ERR_PTR(-EINVAL);

	return &rflt->kobj;
}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
int rfs_flt_sysfs_init(struct rfs_flt *rflt)
{
	int rv;

	rflt->kobj.ktype = &rfs_flt_ktype;
	rflt->kobj.kset = rfs_flt_kset;
	kobject_init(&rflt->kobj);

	rv = kobject_set_name(&rflt->kobj, rflt->name);
	if (rv)
		return rv;

	rv = kobject_add(&rflt->kobj);
	if (rv)
		return rv;

	kobject_uevent(&rflt->kobj, KOBJ_ADD, NULL);

	rfs_flt_get(rflt);

	return 0;
}
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
int rfs_flt_sysfs_init(struct rfs_flt *rflt)
{
	int rv;

	rflt->kobj.ktype = &rfs_flt_ktype;
	rflt->kobj.kset = rfs_flt_kset;
	kobject_init(&rflt->kobj);

	rv = kobject_set_name(&rflt->kobj, rflt->name);
	if (rv)
		return rv;

	rv = kobject_add(&rflt->kobj);
	if (rv)
		return rv;

	kobject_uevent(&rflt->kobj, KOBJ_ADD);

	rfs_flt_get(rflt);

	return 0;
}
#else
int rfs_flt_sysfs_init(struct rfs_flt *rflt)
{
	int rv;

	rflt->kobj.kset = rfs_flt_kset;
	kobject_init(&rflt->kobj, &rfs_flt_ktype);

	rv = kobject_add(&rflt->kobj, NULL, "%s", rflt->name);
	if (rv)
		return rv;

	kobject_uevent(&rflt->kobj, KOBJ_ADD);

	rfs_flt_get(rflt);

	return 0;
}
#endif

void rfs_flt_sysfs_exit(struct rfs_flt *rflt)
{
	kobject_del(&rflt->kobj);
}

EXPORT_SYMBOL(redirfs_create_attribute);
EXPORT_SYMBOL(redirfs_remove_attribute);
EXPORT_SYMBOL(redirfs_filter_kobject);

driver/redirfs/rfs_info.c0000644000076400007640000002136512112622747015325 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static int rfs_info_add_ops(struct rfs_info *rinfo, struct rfs_chain *rchain)
{
	struct rfs_ops *rops;

	if (!rchain) {
		rinfo->rops = NULL;
		return 0;
	}

	rops = rfs_ops_alloc();
	if (IS_ERR(rops))
		return PTR_ERR(rops);

	rfs_chain_ops(rchain, rops);
	rinfo->rops = rops;

	return 0;
}

struct rfs_info *rfs_info_alloc(struct rfs_root *rroot,
		struct rfs_chain *rchain)
{
	struct rfs_info *rinfo;
	int rv;

	rinfo = kzalloc(sizeof(struct rfs_info), GFP_KERNEL);
	if (!rinfo)
		return ERR_PTR(-ENOMEM);

	rv = rfs_info_add_ops(rinfo, rchain);
	if (rv) {
		kfree(rinfo);
		return ERR_PTR(rv);
	}

	rinfo->rchain = rfs_chain_get(rchain);
	rinfo->rroot = rfs_root_get(rroot);
	atomic_set(&rinfo->count, 1);

	return rinfo;
}

struct rfs_info *rfs_info_get(struct rfs_info *rinfo)
{
	if (!rinfo || IS_ERR(rinfo))
		return NULL;

	BUG_ON(!atomic_read(&rinfo->count));
	atomic_inc(&rinfo->count);

	return rinfo;
}

void rfs_info_put(struct rfs_info *rinfo)
{
	if (!rinfo || IS_ERR(rinfo))
		return;

	BUG_ON(!atomic_read(&rinfo->count));
	if (!atomic_dec_and_test(&rinfo->count))
		return;

	rfs_chain_put(rinfo->rchain);
	rfs_ops_put(rinfo->rops);
	rfs_root_put(rinfo->rroot);
	kfree(rinfo);
}

static struct rfs_info *rfs_info_dentry(struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	rinfo = rfs_info_get(rdentry->rinfo);

	rfs_dentry_put(rdentry);

	return rinfo;
}

struct rfs_info *rfs_info_parent(struct dentry *dentry)
{
	struct dentry *dparent = NULL;
	struct rfs_info *rinfo = NULL;

	dparent = dget_parent(dentry);
	if (dparent != dentry)
		rinfo = rfs_info_dentry(dparent);
	dput(dparent);

	return rinfo;
}

static int rfs_info_rdentry_add(struct rfs_info *rinfo)
{
	struct rfs_dentry *rdentry;

	rdentry = rfs_dentry_add(rinfo->rroot->dentry, rinfo);
	if (IS_ERR(rdentry))
		return PTR_ERR(rdentry);

	rfs_dentry_set_rinfo(rdentry, rinfo);
	rfs_dentry_put(rdentry);
	return 0;
}

static void rfs_info_rdentry_rem(struct dentry *dentry)
{
	struct rfs_dentry *rdentry;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return;

	spin_lock(&rdentry->lock);
	rfs_info_put(rdentry->rinfo);
	rdentry->rinfo = rfs_info_get(rfs_info_none);
	spin_unlock(&rdentry->lock);

	rfs_dentry_put(rdentry);
}

int rfs_info_add(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt)
{
	struct rfs_dcache_data *rdata = NULL;
	int rv = 0;

	rdata = rfs_dcache_data_alloc(dentry, rinfo, rflt);
	if (IS_ERR(rdata))
		return PTR_ERR(rdata);

	rv = rfs_dcache_walk(dentry, rfs_dcache_add, rdata);
	rfs_dcache_data_free(rdata);

	if (!rv)
		rv = rfs_root_walk(rfs_root_add_flt, rflt);

	return rv;
}

int rfs_info_rem(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt)
{
	struct rfs_dcache_data *rdata = NULL;
	int rv = 0;

	rdata = rfs_dcache_data_alloc(dentry, rinfo, rflt);
	if (IS_ERR(rdata))
		return PTR_ERR(rdata);

	rv = rfs_dcache_walk(dentry, rfs_dcache_rem, rdata);
	rfs_dcache_data_free(rdata);

	if (!rv)
		rv = rfs_root_walk(rfs_root_rem_flt, rflt);

	return rv;
}

int rfs_info_set(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt)
{
	struct rfs_dcache_data *rdata = NULL;
	int rv = 0;

	rdata = rfs_dcache_data_alloc(dentry, rinfo, rflt);
	if (IS_ERR(rdata))
		return PTR_ERR(rdata);

	if (rflt->ops && rflt->ops->move_begin)
		rflt->ops->move_begin();

	rv = rfs_dcache_walk(dentry, rfs_dcache_set, rdata);

	if (rflt->ops && rflt->ops->move_end)
		rflt->ops->move_end();

	rfs_dcache_data_free(rdata);

	return rv;
}

int rfs_info_reset(struct dentry *dentry, struct rfs_info *rinfo)
{
	struct rfs_dcache_data *rdata = NULL;
	int rv = 0;

	rdata = rfs_dcache_data_alloc(dentry, rinfo, NULL);
	if (IS_ERR(rdata))
		return PTR_ERR(rdata);

	rv = rfs_dcache_walk(dentry, rfs_dcache_reset, rdata);
	rfs_dcache_data_free(rdata);

	return rv;
}

int rfs_info_add_include(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_info *rinfo = NULL;
	struct rfs_info *rinfo_old = NULL;
	struct rfs_chain *rchain = NULL;
	int rv = 0;

	if (rroot->rinfo && rfs_chain_find(rroot->rinfo->rchain, rflt) != -1)
		return 0;

	rinfo_old = rfs_info_get(rroot->rinfo);
	if (!rinfo_old)
		rinfo_old = rfs_info_dentry(rroot->dentry);

	if (rinfo_old) 
		rchain = rfs_chain_add(rinfo_old->rchain, rflt);
	else
		rchain = rfs_chain_add(NULL, rflt);

	if (IS_ERR(rchain)) {
		rv = PTR_ERR(rchain);
		goto exit;
	}

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	if (rinfo_old && rfs_chain_find(rinfo_old->rchain, rflt) != -1)
		rv = rfs_info_set(rroot->dentry, rinfo, rflt);
	else
		rv = rfs_info_add(rroot->dentry, rinfo, rflt);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_info_put(rinfo_old);
	rfs_info_put(rinfo);
	rfs_chain_put(rchain);
	return rv;
}

int rfs_info_add_exclude(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_info *rinfo = NULL;
	struct rfs_info *rinfo_old = NULL;
	struct rfs_chain *rchain = NULL;
	int rv = 0;

	if (rroot->rinfo && rfs_chain_find(rroot->rinfo->rchain, rflt) == -1)
		return 0;

	rinfo_old = rfs_info_get(rroot->rinfo);
	if (!rinfo_old)
		rinfo_old = rfs_info_dentry(rroot->dentry);

	if (rinfo_old) 
		rchain = rfs_chain_rem(rinfo_old->rchain, rflt);

	if (IS_ERR(rchain)) {
		rv = PTR_ERR(rchain);
		goto exit;
	}

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	if (rinfo_old) {
		if (rfs_chain_find(rinfo_old->rchain, rflt) == -1)
			rv = rfs_info_set(rroot->dentry, rinfo, rflt);
		else
			rv = rfs_info_rem(rroot->dentry, rinfo, rflt);
	} else
		rv = rfs_info_rdentry_add(rinfo);

	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_info_put(rinfo);
	rfs_info_put(rinfo_old);
	rfs_chain_put(rchain);
	return rv;
}

int rfs_info_rem_include(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_info *prinfo = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_chain *rchain = NULL;
	int rv = 0;

	rchain = rfs_chain_rem(rroot->rinfo->rchain, rflt);
	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	prinfo = rfs_info_parent(rroot->dentry);

	if (rroot->rinch->rflts_nr == 1 && !rroot->rexch) {
		if (prinfo && rfs_chain_find(prinfo->rchain, rflt) != -1)
			rv = rfs_info_set(rroot->dentry, prinfo, rflt);
		else if (prinfo && prinfo->rchain)
			rv = rfs_info_rem(rroot->dentry, prinfo, rflt);
		else
			rv = rfs_info_rem(rroot->dentry, rinfo, rflt);

		if (!rv)
			rfs_root_set_rinfo(rroot, NULL);

		goto exit;
	}

	if (prinfo && rfs_chain_find(prinfo->rchain, rflt) != -1)
		goto exit;

	rv = rfs_info_rem(rroot->dentry, rinfo, rflt);
	if (rv)
		goto exit;

	rv = rfs_info_rdentry_add(rinfo);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_info_put(prinfo);
	rfs_info_put(rinfo);
	rfs_chain_put(rchain);
	return rv;
}

int rfs_info_rem_exclude(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_info *prinfo = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_chain *rchain = NULL;
	int rv = 0;

	prinfo = rfs_info_parent(rroot->dentry);

	if (rroot->rexch->rflts_nr == 1 && !rroot->rinch) {
		if (prinfo && rfs_chain_find(prinfo->rchain, rflt) != -1)
			rv = rfs_info_add(rroot->dentry, prinfo, rflt);
		else if (prinfo && prinfo->rchain)
			rv = rfs_info_set(rroot->dentry, prinfo, rflt);
		else  
			rfs_info_rdentry_rem(rroot->dentry);

		if (!rv)
			rfs_root_set_rinfo(rroot, NULL);

		goto exit;
	}

	if (!prinfo || rfs_chain_find(prinfo->rchain, rflt) == -1)
		goto exit;

	rchain = rfs_chain_add(rroot->rinfo->rchain, rflt);
	if (IS_ERR(rchain)) {
		rv = PTR_ERR(rchain);
		goto exit;
	}

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	rv = rfs_info_add(rroot->dentry, rinfo, rflt);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_info_put(prinfo);
	rfs_info_put(rinfo);
	rfs_chain_put(rchain);
	return rv;
}

driver/redirfs/TODO0000644000076400007640000000031712112622747014036 0ustar  comodocomodo		================================
		RedirFS - Redirecting FileSystem
			      TODO 
		================================

* support for address space operations
* allow redirect all operations in VFS objects
driver/redirfs/rfs_chain.c0000644000076400007640000001310412112622747015444 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static struct rfs_chain *rfs_chain_alloc(int size, int type)
{
	struct rfs_chain *rchain;
	struct rfs_flt **rflts;

	rchain = kzalloc(sizeof(struct rfs_chain), type);
	rflts = kzalloc(sizeof(struct rfs_flt*) * size, type);
	if (!rchain || !rflts) {
		kfree(rchain);
		kfree(rflts);
		return ERR_PTR(-ENOMEM);
	}

	rchain->rflts = rflts;
	rchain->rflts_nr = size;
	atomic_set(&rchain->count, 1);

	return rchain;
}

struct rfs_chain *rfs_chain_get(struct rfs_chain *rchain)
{
	if (!rchain || IS_ERR(rchain))
		return NULL;

	BUG_ON(!atomic_read(&rchain->count));
	atomic_inc(&rchain->count);

	return rchain;
}

void rfs_chain_put(struct rfs_chain *rchain)
{
	int i;

	if (!rchain || IS_ERR(rchain))
		return;

	BUG_ON(!atomic_read(&rchain->count));
	if (!atomic_dec_and_test(&rchain->count))
		return;

	for (i = 0; i < rchain->rflts_nr; i++)
		rfs_flt_put(rchain->rflts[i]);

	kfree(rchain->rflts);
	kfree(rchain);
}

int rfs_chain_find(struct rfs_chain *rchain, struct rfs_flt *rflt)
{
	int i;

	if (!rchain)
		return -1;

	for (i = 0; i < rchain->rflts_nr; i++) {
		if (rchain->rflts[i] == rflt)
			return i;
	}

	return -1;
}

struct rfs_chain *rfs_chain_add(struct rfs_chain *rchain, struct rfs_flt *rflt)
{
	struct rfs_chain *rchain_new;
	int size;
	int i = 0;
	int j = 0;

	if (rfs_chain_find(rchain, rflt) != -1)
		return rfs_chain_get(rchain);

	if (!rchain) 
		size = 1;
	else
		size = rchain->rflts_nr + 1;

	rchain_new = rfs_chain_alloc(size, GFP_KERNEL);
	if (IS_ERR(rchain_new))
		return rchain_new;

	if (!rchain) {
		rchain_new->rflts[0] = rfs_flt_get(rflt);
		return rchain_new;
	}

	while (rchain->rflts[i]->priority < rflt->priority) {
		rchain_new->rflts[j++] = rfs_flt_get(rchain->rflts[i++]);
		if (i == rchain->rflts_nr)
			break;
	}

	rchain_new->rflts[j++] = rfs_flt_get(rflt);

	while (j < rchain_new->rflts_nr) {
		rchain_new->rflts[j++] = rfs_flt_get(rchain->rflts[i++]);
	}

	return rchain_new;
}

struct rfs_chain *rfs_chain_rem(struct rfs_chain *rchain, struct rfs_flt *rflt)
{
	struct rfs_chain *rchain_new;
	int i, j;

	if (rfs_chain_find(rchain, rflt) == -1)
		return rfs_chain_get(rchain);

	if (rchain->rflts_nr == 1)
		return NULL;

	rchain_new = rfs_chain_alloc(rchain->rflts_nr - 1, GFP_KERNEL);
	if (IS_ERR(rchain_new))
		return rchain_new;

	for (i = 0, j = 0; i < rchain->rflts_nr; i++) {
		if (rchain->rflts[i] != rflt)
			rchain_new->rflts[j++] = rfs_flt_get(rchain->rflts[i]);
	}

	return rchain_new;
}

void rfs_chain_ops(struct rfs_chain *rchain, struct rfs_ops *rops)
{
	int i, j;

	if (!rchain)
		return;

	for (i = 0; i < rchain->rflts_nr; i++) {
		for (j = 0; j < REDIRFS_OP_END; j++) {
			if (rchain->rflts[i]->cbs[j].pre_cb)
				rops->arr[j]++;
			if (rchain->rflts[i]->cbs[j].post_cb)
				rops->arr[j]++;
		}
	}
}

int rfs_chain_cmp(struct rfs_chain *rch1, struct rfs_chain *rch2)
{
	int i;

	if (!rch1 && !rch2)
		return 0;

	if (!rch1 || !rch2)
		return -1;

	if (rch1->rflts_nr != rch2->rflts_nr)
		return -1;

	for (i = 0; i < rch1->rflts_nr; i++) {
		if (rch1->rflts[i] != rch2->rflts[i])
			return -1;
	}

	return 0;
}

struct rfs_chain *rfs_chain_join(struct rfs_chain *rch1, struct rfs_chain *rch2)
{
	struct rfs_chain *rch;
	int size;
	int i,k,l;

	if (!rch1 && !rch2)
		return NULL;

	if (!rch1)
		return rfs_chain_get(rch2);

	if (!rch2)
		return rfs_chain_get(rch1);

	if (!rfs_chain_cmp(rch1, rch2))
		return rfs_chain_get(rch1);

	size = rch1->rflts_nr;

	for (i = 0; i < rch2->rflts_nr; i++) {
		if (rfs_chain_find(rch1, rch2->rflts[i]) == -1)
			size++;
	}

	rch = rfs_chain_alloc(size, GFP_KERNEL);
	if (IS_ERR(rch))
		return rch;

	i = k = l = 0;
	while (k != rch1->rflts_nr && l != rch2->rflts_nr) {
		if (rch1->rflts[k]->priority == rch2->rflts[l]->priority) {
			rch->rflts[i++] = rfs_flt_get(rch1->rflts[k++]);
			l++;
		} else if (rch1->rflts[k]->priority < rch2->rflts[l]->priority) {
			rch->rflts[i++] = rfs_flt_get(rch1->rflts[k++]);
		} else
			rch->rflts[i++] = rfs_flt_get(rch2->rflts[l++]);
	}

	while (k != rch1->rflts_nr)
		rch->rflts[i++] = rfs_flt_get(rch1->rflts[k++]);

	while (l != rch2->rflts_nr)
		rch->rflts[i++] = rfs_flt_get(rch2->rflts[l++]);

	return rch;
}

struct rfs_chain *rfs_chain_diff(struct rfs_chain *rch1, struct rfs_chain *rch2)
{
	struct rfs_chain *rch;
	int size;
	int i,j;

	if (!rch1)
		return NULL;

	if (!rch2)
		return rfs_chain_get(rch1);

	size = rch1->rflts_nr;

	for (i = 0; i < rch1->rflts_nr; i++) {
		if (rfs_chain_find(rch2, rch1->rflts[i]) != -1)
			size--;
	}

	if (!size)
		return NULL;

	if (size == rch1->rflts_nr)
		return rfs_chain_get(rch1);

	rch = rfs_chain_alloc(size, GFP_KERNEL);
	if (IS_ERR(rch))
		return rch;

	for (i = 0, j = 0; i < rch1->rflts_nr; i++) {
		if (rfs_chain_find(rch2, rch1->rflts[i]) == -1)
			rch->rflts[j++] = rfs_flt_get(rch1->rflts[i]);
	}

	BUG_ON(j != size);

	return rch;
}

driver/redirfs/rfs.h0000644000076400007640000004067612112622747014325 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _RFS_H
#define _RFS_H

#include <linux/mount.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
#include "redirfs.h"

#define RFS_ADD_OP(ops_new, op) \
	(ops_new.op = rfs_##op)

#define RFS_REM_OP(ops_new, ops_old, op) \
	(ops_new.op = ops_old ? ops_old->op : NULL)

#define RFS_SET_OP(arr, id, ops_new, ops_old, op) \
	(arr[id] ? \
	 	RFS_ADD_OP(ops_new, op) : \
	 	RFS_REM_OP(ops_new, ops_old, op) \
	)

#define RFS_SET_FOP(rf, id, op) \
	(rf->rdentry->rinfo->rops ? \
		RFS_SET_OP(rf->rdentry->rinfo->rops->arr, id, rf->op_new, \
			rf->op_old, op) : \
	 	RFS_REM_OP(rf->op_new, rf->op_old, op) \
	)

#define RFS_SET_DOP(rd, id, op) \
	(rd->rinfo->rops ? \
		RFS_SET_OP(rd->rinfo->rops->arr, id, rd->op_new,\
			rd->op_old, op) : \
	 	RFS_REM_OP(rd->op_new, rd->op_old, op) \
	)

#define RFS_SET_IOP_MGT(ri, op) \
	(ri->rinfo->rops ? \
	 	RFS_ADD_OP(ri->op_new, op) : \
	 	RFS_REM_OP(ri->op_new, ri->op_old, op) \
	)

#define RFS_SET_IOP(ri, id, op) \
	(ri->rinfo->rops ? \
	 	RFS_SET_OP(ri->rinfo->rops->arr, id, ri->op_new, \
			ri->op_old, op) : \
	 	RFS_REM_OP(ri->op_new, ri->op_old, op) \
	)

struct rfs_file;

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
#define rfs_mutex_t semaphore
#define RFS_DEFINE_MUTEX(mutex) DECLARE_MUTEX(mutex)
#define rfs_mutex_init(mutex) init_MUTEX(mutex)
#define rfs_mutex_lock(mutex) down(mutex)
#define rfs_mutex_unlock(mutex) up(mutex)
#define rfs_for_each_d_child(pos, head) list_for_each_entry(pos, head, d_child)
inline static void rfs_inode_mutex_lock(struct inode *inode)
{
	down(&inode->i_sem);
}
inline static void rfs_inode_mutex_unlock(struct inode *inode)
{
	up(&inode->i_sem);
}
#else
#define rfs_mutex_t mutex
#define RFS_DEFINE_MUTEX(mutex) DEFINE_MUTEX(mutex)
#define rfs_mutex_init(mutex) mutex_init(mutex)
#define rfs_mutex_lock(mutex) mutex_lock(mutex)
#define rfs_mutex_unlock(mutex) mutex_unlock(mutex)
#define rfs_for_each_d_child(pos, head) list_for_each_entry(pos, head, d_u.d_child)
inline static void rfs_inode_mutex_lock(struct inode *inode)
{
	mutex_lock(&inode->i_mutex);
}
inline static void rfs_inode_mutex_unlock(struct inode *inode)
{
	mutex_unlock(&inode->i_mutex);
}
#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
#define rfs_kmem_cache_t kmem_cache_t
#else
#define rfs_kmem_cache_t struct kmem_cache
#endif

struct rfs_op_info {
	enum redirfs_rv (*pre_cb)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv (*post_cb)(redirfs_context, struct redirfs_args *);
};

struct rfs_flt {
	struct list_head list;
	struct rfs_op_info cbs[REDIRFS_OP_END];
	struct module *owner;
	struct kobject kobj;
	char *name;
	int priority;
	int paths_nr;
	spinlock_t lock;
	atomic_t active;
	atomic_t count;
	struct redirfs_filter_operations *ops;
};

void rfs_flt_put(struct rfs_flt *rflt);
struct rfs_flt *rfs_flt_get(struct rfs_flt *rflt);
void rfs_flt_release(struct kobject *kobj);

struct rfs_path {
	struct list_head list;
	struct list_head rfst_list;
	struct list_head rroot_list;
	struct rfs_root *rroot;
	struct rfs_chain *rinch;
	struct rfs_chain *rexch;
	struct vfsmount *mnt;
	struct dentry *dentry;
	atomic_t count;
	int id;
};

extern struct rfs_mutex_t rfs_path_mutex;

struct rfs_path *rfs_path_get(struct rfs_path *rpath);
void rfs_path_put(struct rfs_path *rpath);
struct rfs_path *rfs_path_find_id(int id);
int rfs_path_get_info(struct rfs_flt *rflt, char *buf, int size);
int rfs_fsrename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry);

struct rfs_root {
	struct list_head list;
	struct list_head walk_list;
	struct list_head rpaths;
	struct list_head data;
	struct rfs_chain *rinch;
	struct rfs_chain *rexch;
	struct rfs_info *rinfo;
	struct dentry *dentry;
	int paths_nr;
	spinlock_t lock;
	atomic_t count;
};

extern struct list_head rfs_root_list;
extern struct list_head rfs_root_walk_list;

struct rfs_root *rfs_root_get(struct rfs_root *rroot);
void rfs_root_put(struct rfs_root *rroot);
void rfs_root_add_rpath(struct rfs_root *rroot, struct rfs_path *rpath);
void rfs_root_rem_rpath(struct rfs_root *rroot, struct rfs_path *rpath);
struct rfs_root *rfs_root_add(struct dentry *dentry);
int rfs_root_add_include(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_root_add_exclude(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_root_rem_include(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_root_rem_exclude(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_root_add_flt(struct rfs_root *rroot, void *data);
int rfs_root_rem_flt(struct rfs_root *rroot, void *data);
int rfs_root_walk(int (*cb)(struct rfs_root*, void *), void *data);
void rfs_root_add_walk(struct dentry *dentry);
void rfs_root_set_rinfo(struct rfs_root *rroot, struct rfs_info *rinfo);

struct rfs_ops {
	char *arr;
	atomic_t count;
	int flags;
};

struct rfs_ops *rfs_ops_alloc(void);
struct rfs_ops *rfs_ops_get(struct rfs_ops *rops);
void rfs_ops_put(struct rfs_ops *rops);

struct rfs_chain {
	struct rfs_flt **rflts;
	int rflts_nr;
	atomic_t count;
};

struct rfs_chain *rfs_chain_get(struct rfs_chain *rchain);
void rfs_chain_put(struct rfs_chain *rchain);
int rfs_chain_find(struct rfs_chain *rchain, struct rfs_flt *rflt);
struct rfs_chain *rfs_chain_add(struct rfs_chain *rchain, struct rfs_flt *rflt);
struct rfs_chain *rfs_chain_rem(struct rfs_chain *rchain, struct rfs_flt *rflt);
void rfs_chain_ops(struct rfs_chain *rchain, struct rfs_ops *ops);
int rfs_chain_cmp(struct rfs_chain *rch1, struct rfs_chain *rch2);
struct rfs_chain *rfs_chain_join(struct rfs_chain *rch1,
		struct rfs_chain *rch2);
struct rfs_chain *rfs_chain_diff(struct rfs_chain *rch1,
		struct rfs_chain *rch2);

struct rfs_info {
	struct rfs_chain *rchain;
	struct rfs_ops *rops;
	struct rfs_root *rroot;
	atomic_t count;
};

extern struct rfs_info *rfs_info_none;

struct rfs_info *rfs_info_alloc(struct rfs_root *rroot,
		struct rfs_chain *rchain);
struct rfs_info *rfs_info_get(struct rfs_info *rinfo);
void rfs_info_put(struct rfs_info *rinfo);
struct rfs_info *rfs_info_parent(struct dentry *dentry);
int rfs_info_add_include(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_info_add_exclude(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_info_rem_include(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_info_rem_exclude(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_info_add(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt);
int rfs_info_rem(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt);
int rfs_info_set(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt);
int rfs_info_reset(struct dentry *dentry, struct rfs_info *rinfo);

struct rfs_dentry {
	struct list_head rinode_list;
	struct list_head rfiles;
	struct list_head data;
	struct dentry *dentry;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
	const struct dentry_operations *op_old;
#else
	struct dentry_operations *op_old;
#endif
	struct dentry_operations op_new;
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	spinlock_t lock;
	atomic_t count;
};

#define rfs_dentry_find(dentry) \
	(dentry && dentry->d_op && dentry->d_op->d_iput == rfs_d_iput ? \
	 rfs_dentry_get(container_of(dentry->d_op, struct rfs_dentry, op_new)) : \
	 NULL)

void rfs_d_iput(struct dentry *dentry, struct inode *inode);
struct rfs_dentry *rfs_dentry_get(struct rfs_dentry *rdentry);
void rfs_dentry_put(struct rfs_dentry *rdentry);
struct rfs_dentry *rfs_dentry_add(struct dentry *dentry,
		struct rfs_info *rinfo);
void rfs_dentry_del(struct rfs_dentry *rdentry);
int rfs_dentry_add_rinode(struct rfs_dentry *rdentry, struct rfs_info *rinfo);
void rfs_dentry_rem_rinode(struct rfs_dentry *rdentry);
struct rfs_info *rfs_dentry_get_rinfo(struct rfs_dentry *rdentry);
void rfs_dentry_set_rinfo(struct rfs_dentry *rdentry, struct rfs_info *rinfo);
void rfs_dentry_add_rfile(struct rfs_dentry *rdentry, struct rfs_file *rfile);
void rfs_dentry_rem_rfile(struct rfs_file *rfile);
void rfs_dentry_rem_rfiles(struct rfs_dentry *rdentry);
void rfs_dentry_set_ops(struct rfs_dentry *dentry);
int rfs_dentry_cache_create(void);
void rfs_dentry_cache_destory(void);
void rfs_dentry_rem_data(struct dentry *dentry, struct rfs_flt *rflt);
int rfs_dentry_move(struct dentry *dentry, struct rfs_flt *rflt,
		struct rfs_root *src, struct rfs_root *dst);

struct rfs_inode {
	struct list_head rdentries; /* mutex */
	struct list_head data;
	struct inode *inode;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17))
	const struct inode_operations *op_old;
	const struct file_operations *fop_old;
#else
	struct inode_operations *op_old;
	struct file_operations *fop_old;
#endif
	struct inode_operations op_new;
	struct rfs_info *rinfo;
	struct rfs_mutex_t mutex;
	spinlock_t lock;
	atomic_t count;
	atomic_t nlink;
	int rdentries_nr; /* mutex */
};

#define rfs_inode_find(inode) \
	(inode && inode->i_op && inode->i_op->rename == rfs_rename ? \
	 rfs_inode_get(container_of(inode->i_op, struct rfs_inode, op_new)) : \
	 NULL)

int rfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry);
struct rfs_inode *rfs_inode_get(struct rfs_inode *rinode);
void rfs_inode_put(struct rfs_inode *rinode);
struct rfs_inode *rfs_inode_add(struct inode *inode, struct rfs_info *rinfo);
void rfs_inode_del(struct rfs_inode *rinode);
void rfs_inode_add_rdentry(struct rfs_inode *rinode,
		struct rfs_dentry *rdentry);
void rfs_inode_rem_rdentry(struct rfs_inode *rinode,
		struct rfs_dentry *rdentry);
struct rfs_info *rfs_inode_get_rinfo(struct rfs_inode *rinode);
int rfs_inode_set_rinfo(struct rfs_inode *rinode);
void rfs_inode_set_ops(struct rfs_inode *rinode);
int rfs_inode_cache_create(void);
void rfs_inode_cache_destroy(void);

struct rfs_file {
	struct list_head rdentry_list;
	struct list_head data;
	struct file *file;
	struct rfs_dentry *rdentry;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17))
	const struct file_operations *op_old;
#else
	struct file_operations *op_old;
#endif
	struct file_operations op_new;
	spinlock_t lock;
	atomic_t count;
};

#define rfs_file_find(file) \
	(file && file->f_op && file->f_op->open == rfs_open ? \
	 rfs_file_get(container_of(file->f_op, struct rfs_file, op_new)) : \
	 NULL)
	 
extern struct file_operations rfs_file_ops;

int rfs_open(struct inode *inode, struct file *file);
struct rfs_file *rfs_file_get(struct rfs_file *rfile);
void rfs_file_put(struct rfs_file *rfile);
void rfs_file_set_ops(struct rfs_file *rfile);
int rfs_file_cache_create(void);
void rfs_file_cache_destory(void);

struct rfs_dcache_data {
	struct rfs_info *rinfo;
	struct rfs_flt *rflt;
	struct dentry *droot;
};

struct rfs_dcache_data *rfs_dcache_data_alloc(struct dentry *dentry,
		struct rfs_info *rinfo, struct rfs_flt *rflt);
void rfs_dcache_data_free(struct rfs_dcache_data *rdata);

struct rfs_dcache_entry {
	struct list_head list;
	struct dentry *dentry;
};

int rfs_dcache_walk(struct dentry *root, int (*cb)(struct dentry *, void *),
		void *data);
int rfs_dcache_add_dir(struct dentry *dentry, void *data);
int rfs_dcache_add(struct dentry *dentry, void *data);
int rfs_dcache_rem(struct dentry *dentry, void *data);
int rfs_dcache_set(struct dentry *dentry, void *data);
int rfs_dcache_reset(struct dentry *dentry, void *data);
int rfs_dcache_rdentry_add(struct dentry *dentry, struct rfs_info *rinfo);
int rfs_dcache_rinode_del(struct rfs_dentry *rdentry, struct inode *inode);
int rfs_dcache_get_subs(struct dentry *dir, struct list_head *sibs);
void rfs_dcache_entry_free_list(struct list_head *head);

struct rfs_context {
	struct list_head data;
	int idx;
	int idx_start;
};

void rfs_context_init(struct rfs_context *rcont, int start);
void rfs_context_deinit(struct rfs_context *rcont);

int rfs_precall_flts(struct rfs_chain *rchain, struct rfs_context *rcont,
		struct redirfs_args *rargs);
void rfs_postcall_flts(struct rfs_chain *rchain, struct rfs_context *rcont,
		struct redirfs_args *rargs);

#define rfs_kobj_to_rflt(__kobj) container_of(__kobj, struct rfs_flt, kobj)
int rfs_flt_sysfs_init(struct rfs_flt *rflt);
void rfs_flt_sysfs_exit(struct rfs_flt *rflt);
void rfs_kobject_init(struct kobject *kobj);

int rfs_sysfs_create(void);

void rfs_data_remove(struct list_head *head);



#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16))

#define rfs_rename_lock(sb) down(&sb->s_vfs_rename_sem)
#define rfs_rename_unlock(sb) up(&sb->s_vfs_rename_sem)

#  if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14))
typedef unsigned gfp_t;

static inline void *kzalloc(size_t size, gfp_t flags)
{
	void *p;
	
	p = kmalloc(size, flags);
	if (!p)
		return NULL;

	memset(p, 0, size);

	return p;
}

#  endif

static inline void *kmem_cache_zalloc(kmem_cache_t *cache, gfp_t flags)
{
	void *obj;

	obj = kmem_cache_alloc(cache, flags);
	if (!obj)
		return NULL;

	memset(obj, 0, kmem_cache_size(cache));

	return obj;
}       

#else

#define rfs_rename_lock(sb) mutex_lock(&sb->s_vfs_rename_mutex)
#define rfs_rename_unlock(sb) mutex_unlock(&sb->s_vfs_rename_mutex)

#endif

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23))

static inline rfs_kmem_cache_t *rfs_kmem_cache_create(const char *n, size_t s)
{
	return kmem_cache_create(n, s, 0, SLAB_RECLAIM_ACCOUNT, NULL);
}

#else

static inline rfs_kmem_cache_t *rfs_kmem_cache_create(const char *n, size_t s)
{
	return kmem_cache_create(n, s, 0, SLAB_RECLAIM_ACCOUNT, NULL, NULL);
}

#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))

static inline void rfs_nameidata_put(struct nameidata *nd)
{
	path_release(nd);
}

static inline struct dentry *rfs_nameidata_dentry(struct nameidata *nd)
{
	return nd->dentry;
}

static inline struct vfsmount *rfs_nameidata_mnt(struct nameidata *nd)
{
	return nd->mnt;
}

#else

static inline void rfs_nameidata_put(struct nameidata *nd)
{
	path_put(&nd->path);
}

static inline struct dentry *rfs_nameidata_dentry(struct nameidata *nd)
{
	return nd->path.dentry;
}

static inline struct vfsmount *rfs_nameidata_mnt(struct nameidata *nd)
{
	return nd->path.mnt;
}

#endif

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
#define rfs_dq_transfer vfs_dq_transfer
#else
#define rfs_dq_transfer DQUOT_TRANSFER
#endif

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))

static inline int rfs_follow_up(struct vfsmount **mnt, struct dentry **dentry)
{
	struct path path;
	int rv;

	path.mnt = *mnt;
	path.dentry = *dentry;

	rv = follow_up(&path);

	*mnt = path.mnt;
	*dentry = path.dentry;

	return rv;
}

#else

static inline int rfs_follow_up(struct vfsmount **mnt, struct dentry **dentry)
{
	return follow_up(mnt, dentry);
}

#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))

static inline void rfs_dcache_lock(struct dentry *d)
{
	spin_lock(&dcache_lock);
}

static inline void rfs_dcache_unlock(struct dentry *d)
{
	spin_unlock(&dcache_lock);
}

static inline struct dentry *rfs_dget_locked(struct dentry *d)
{
	return dget_locked(d);
}

#else

static inline void rfs_dcache_lock(struct dentry *d)
{
	spin_lock(&d->d_lock);
}

static inline void rfs_dcache_unlock(struct dentry *d)
{
	spin_unlock(&d->d_lock);
}

static inline struct dentry *rfs_dget_locked(struct dentry *d)
{
	return dget_dlock(d);
}

#endif


#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))

static inline int rfs_path_lookup(const char *name, struct nameidata *nd)
{
	return path_lookup(name, LOOKUP_FOLLOW, nd);
}

#else

static inline int rfs_path_lookup(const char *name, struct nameidata *nd)
{
	struct path path;
	int rv;

	rv = kern_path(name, LOOKUP_FOLLOW, &path);
	if (rv)
		return rv;

	nd->path = path;
	return 0;
}

#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36))

static inline int rfs_inode_setattr(struct inode *inode, const struct iattr *attr)
{
	return inode_setattr(inode, attr);
}

#else

static inline int rfs_inode_setattr(struct inode *inode, const struct iattr *attr)
{
	setattr_copy(inode, attr);
	mark_inode_dirty(inode);
	return 0;
}

#endif

#endif

driver/redirfs/rfs_dentry.c0000644000076400007640000003753612112622747015706 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static rfs_kmem_cache_t *rfs_dentry_cache = NULL;

static struct rfs_dentry *rfs_dentry_alloc(struct dentry *dentry)
{
	struct rfs_dentry *rdentry;

	rdentry = kmem_cache_zalloc(rfs_dentry_cache, GFP_KERNEL);
	if (!rdentry)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rdentry->rinode_list);
	INIT_LIST_HEAD(&rdentry->rfiles);
	INIT_LIST_HEAD(&rdentry->data);
	rdentry->dentry = dentry;
	rdentry->op_old = dentry->d_op;
	spin_lock_init(&rdentry->lock);
	atomic_set(&rdentry->count, 1);

	if (dentry->d_op)
		memcpy(&rdentry->op_new, dentry->d_op,
				sizeof(struct dentry_operations));

	rdentry->op_new.d_iput = rfs_d_iput;

	return rdentry;
}

struct rfs_dentry *rfs_dentry_get(struct rfs_dentry *rdentry)
{
	if (!rdentry || IS_ERR(rdentry))
		return NULL;

	BUG_ON(!atomic_read(&rdentry->count));
	atomic_inc(&rdentry->count);

	return rdentry;
}

void rfs_dentry_put(struct rfs_dentry *rdentry)
{
	if (!rdentry || IS_ERR(rdentry))
		return;

	BUG_ON(!atomic_read(&rdentry->count));
	if (!atomic_dec_and_test(&rdentry->count))
		return;

	rfs_inode_put(rdentry->rinode);
	rfs_info_put(rdentry->rinfo);

	rfs_data_remove(&rdentry->data);
	kmem_cache_free(rfs_dentry_cache, rdentry);
}

struct rfs_dentry *rfs_dentry_add(struct dentry *dentry, struct rfs_info *rinfo)
{
	struct rfs_dentry *rd_new;
	struct rfs_dentry *rd;

	if (!dentry)
		return NULL;

	rd_new = rfs_dentry_alloc(dentry);
	if (IS_ERR(rd_new))
		return rd_new;

	spin_lock(&dentry->d_lock);

	rd = rfs_dentry_find(dentry);

	/*
	 * Workaround for the isofs_lookup function. It assigns
	 * dentry operations for the new dentry from the root dentry.
	 * This leads to the situation when one rdentry object can be
	 * found for more dentry objects.
	 *
	 * isofs_lookup: dentry->d_op = dir->i_sb->s_root->d_op;
	 */
	if (rd && (rd->dentry != dentry)) {
		rd_new->op_old = rd->op_old;
		rfs_dentry_put(rd);
		rd = NULL;
	}

	if (!rd) {
		rd_new->rinfo = rfs_info_get(rinfo);
		dentry->d_op = &rd_new->op_new;
		rfs_dentry_get(rd_new);
		rd = rfs_dentry_get(rd_new);
	}

	spin_unlock(&dentry->d_lock);

	rfs_dentry_put(rd_new);

	return rd;
}

void rfs_dentry_del(struct rfs_dentry *rdentry)
{
	rdentry->dentry->d_op = rdentry->op_old;
	rfs_dentry_put(rdentry);
}

int rfs_dentry_add_rinode(struct rfs_dentry *rdentry, struct rfs_info *rinfo)
{
	struct rfs_inode *rinode;

	if (!rdentry->dentry->d_inode)
		return 0;

	spin_lock(&rdentry->lock);
	if (rdentry->rinode) {
		spin_unlock(&rdentry->lock);
		return 0;
	}
	spin_unlock(&rdentry->lock);

	rinode = rfs_inode_add(rdentry->dentry->d_inode, rinfo);
	if (IS_ERR(rinode))
		return PTR_ERR(rinode);

	spin_lock(&rdentry->lock);
	if (rdentry->rinode) {
		spin_unlock(&rdentry->lock);
		rfs_inode_del(rinode);
		rfs_inode_put(rinode);
		return 0;
	}

	rdentry->rinode = rfs_inode_get(rinode);
	spin_unlock(&rdentry->lock);

	rfs_inode_add_rdentry(rinode, rdentry);
	rfs_inode_put(rinode);
	return 0;
}

void rfs_dentry_rem_rinode(struct rfs_dentry *rdentry)
{
	if (!rdentry->rinode)
		return;

	rfs_inode_rem_rdentry(rdentry->rinode, rdentry);
	rfs_inode_del(rdentry->rinode);
	rfs_inode_put(rdentry->rinode);
	rdentry->rinode = NULL;
}

struct rfs_info *rfs_dentry_get_rinfo(struct rfs_dentry *rdentry)
{
	struct rfs_info *rinfo;

	spin_lock(&rdentry->lock);
	rinfo = rfs_info_get(rdentry->rinfo);
	spin_unlock(&rdentry->lock);

	return rinfo;
}

void rfs_dentry_set_rinfo(struct rfs_dentry *rdentry, struct rfs_info *rinfo)
{
	spin_lock(&rdentry->lock);
	rfs_info_put(rdentry->rinfo);
	rdentry->rinfo = rfs_info_get(rinfo);
	spin_unlock(&rdentry->lock);
}

void rfs_dentry_add_rfile(struct rfs_dentry *rdentry, struct rfs_file *rfile)
{
	spin_lock(&rdentry->lock);
	list_add_tail(&rfile->rdentry_list, &rdentry->rfiles);
	spin_unlock(&rdentry->lock);
	rfs_file_get(rfile);
}

void rfs_dentry_rem_rfile(struct rfs_file *rfile)
{
	spin_lock(&rfile->rdentry->lock);
	list_del_init(&rfile->rdentry_list);
	spin_unlock(&rfile->rdentry->lock);
	rfs_file_put(rfile);
}

int rfs_dentry_cache_create(void)
{
	rfs_dentry_cache = rfs_kmem_cache_create("rfs_dentry_cache",
			sizeof(struct rfs_dentry));

	if (!rfs_dentry_cache)
		return -ENOMEM;

	return 0;
}

void rfs_dentry_cache_destory(void)
{
	kmem_cache_destroy(rfs_dentry_cache);
}

void rfs_d_iput(struct dentry *dentry, struct inode *inode)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_DOP_D_IPUT;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_DOP_D_IPUT;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_DOP_D_IPUT;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_DOP_D_IPUT;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_DOP_D_IPUT;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_DOP_D_IPUT;
	else
		rargs.type.id = REDIRFS_SOCK_DOP_D_IPUT;

	rargs.args.d_iput.dentry = dentry;
	rargs.args.d_iput.inode = inode;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		BUG_ON(rfs_dcache_rinode_del(rdentry, inode));

		if (rdentry->op_old && rdentry->op_old->d_iput)
			rdentry->op_old->d_iput(rargs.args.d_iput.dentry,
					rargs.args.d_iput.inode);
		else
			iput(inode);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);
}

static void rfs_d_release(struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);
	rargs.type.id = REDIRFS_NONE_DOP_D_RELEASE;
	rargs.args.d_release.dentry = dentry;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rdentry->op_old && rdentry->op_old->d_release)
			rdentry->op_old->d_release(rargs.args.d_release.dentry);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_del(rdentry);
	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);
}

static inline int rfs_d_compare_default(const struct qstr *name1,
		const struct qstr *name2)
{
	if (name1->len != name2->len)
		return 1;
	if (memcmp(name1->name, name2->name, name1->len))
		return 1;

	return 0;
}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))

static int rfs_d_compare(struct dentry *dentry, struct qstr *name1,
		struct qstr *name2)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);

	if (dentry->d_inode) {
		if (S_ISREG(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_REG_DOP_D_COMPARE;
		else if (S_ISDIR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_DIR_DOP_D_COMPARE;
		else if (S_ISLNK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_LNK_DOP_D_COMPARE;
		else if (S_ISCHR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_CHR_DOP_D_COMPARE;
		else if (S_ISBLK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_BLK_DOP_D_COMPARE;
		else if (S_ISFIFO(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_FIFO_DOP_D_COMPARE;
		else
			rargs.type.id = REDIRFS_SOCK_DOP_D_COMPARE;
	} else
		rargs.type.id = REDIRFS_NONE_DOP_D_COMPARE;

	rargs.args.d_compare.dentry = dentry;
	rargs.args.d_compare.name1 = name1;
	rargs.args.d_compare.name2 = name2;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rdentry->op_old && rdentry->op_old->d_compare)
			rargs.rv.rv_int = rdentry->op_old->d_compare(
					rargs.args.d_compare.dentry,
					rargs.args.d_compare.name1,
					rargs.args.d_compare.name2);
		else
			rargs.rv.rv_int = rfs_d_compare_default(
					rargs.args.d_compare.name1,
					rargs.args.d_compare.name2);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);

	return rargs.rv.rv_int;
}

#else

static int rfs_d_compare(const struct dentry *parent, const struct inode *inode,
		const struct dentry *dentry, const struct inode *d_inode,
		unsigned int tlen, const char *tname,
		const struct qstr *name)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);

	if (dentry->d_inode) {
		if (S_ISREG(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_REG_DOP_D_COMPARE;
		else if (S_ISDIR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_DIR_DOP_D_COMPARE;
		else if (S_ISLNK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_LNK_DOP_D_COMPARE;
		else if (S_ISCHR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_CHR_DOP_D_COMPARE;
		else if (S_ISBLK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_BLK_DOP_D_COMPARE;
		else if (S_ISFIFO(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_FIFO_DOP_D_COMPARE;
		else
			rargs.type.id = REDIRFS_SOCK_DOP_D_COMPARE;
	} else
		rargs.type.id = REDIRFS_NONE_DOP_D_COMPARE;

	rargs.args.d_compare.parent = parent;
	rargs.args.d_compare.inode = inode;
	rargs.args.d_compare.dentry = dentry;
	rargs.args.d_compare.d_inode = d_inode;
	rargs.args.d_compare.tlen = tlen;
	rargs.args.d_compare.tname = tname;
	rargs.args.d_compare.name = name;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rdentry->op_old && rdentry->op_old->d_compare)
			rargs.rv.rv_int = rdentry->op_old->d_compare(
					rargs.args.d_compare.parent,
					rargs.args.d_compare.inode,
					rargs.args.d_compare.dentry,
					rargs.args.d_compare.d_inode,
					rargs.args.d_compare.tlen,
					rargs.args.d_compare.tname,
					rargs.args.d_compare.name);
		else
			rargs.rv.rv_int = rfs_d_compare_default(
					&rargs.args.d_compare.dentry->d_name,
					rargs.args.d_compare.name);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);

	return rargs.rv.rv_int;
}

#endif

static int rfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);

	if (dentry->d_inode) {
		if (S_ISREG(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_REG_DOP_D_REVALIDATE;
		else if (S_ISDIR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_DIR_DOP_D_REVALIDATE;
		else if (S_ISLNK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_LNK_DOP_D_REVALIDATE;
		else if (S_ISCHR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_CHR_DOP_D_REVALIDATE;
		else if (S_ISBLK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_BLK_DOP_D_REVALIDATE;
		else if (S_ISFIFO(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_FIFO_DOP_D_REVALIDATE;
		else
			rargs.type.id = REDIRFS_SOCK_DOP_D_REVALIDATE;
	} else
		rargs.type.id = REDIRFS_NONE_DOP_D_REVALIDATE;

	rargs.args.d_revalidate.dentry = dentry;
	rargs.args.d_revalidate.nd = nd;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rdentry->op_old && rdentry->op_old->d_revalidate)
			rargs.rv.rv_int = rdentry->op_old->d_revalidate(
					rargs.args.d_revalidate.dentry,
					rargs.args.d_revalidate.nd);
		else
			rargs.rv.rv_int = 1;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);

	return rargs.rv.rv_int;
}

static void rfs_dentry_set_ops_none(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_NONE_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_NONE_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_reg(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_REG_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_REG_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_dir(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_DIR_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_DIR_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_lnk(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_LNK_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_LNK_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_chr(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_CHR_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_CHR_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_blk(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_BLK_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_BLK_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_fifo(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_FIFO_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_FIFO_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_sock(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_SOCK_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_SOCK_DOP_D_REVALIDATE, d_revalidate);
}

void rfs_dentry_set_ops(struct rfs_dentry *rdentry)
{
	struct rfs_file *rfile;
	umode_t mode;

	spin_lock(&rdentry->lock);

	rdentry->op_new.d_release = rfs_d_release;

	if (!rdentry->rinode) {
		rfs_dentry_set_ops_none(rdentry);
		spin_unlock(&rdentry->lock);
		return;
	}

	list_for_each_entry(rfile, &rdentry->rfiles, rdentry_list) {
		rfs_file_set_ops(rfile);
	}

	mode = rdentry->rinode->inode->i_mode;

	if (S_ISREG(mode))
		rfs_dentry_set_ops_reg(rdentry);

	else if (S_ISDIR(mode))
		rfs_dentry_set_ops_dir(rdentry);

	else if (S_ISLNK(mode))
		rfs_dentry_set_ops_lnk(rdentry);

	else if (S_ISCHR(mode))
		rfs_dentry_set_ops_chr(rdentry);

	else if (S_ISBLK(mode))
		rfs_dentry_set_ops_blk(rdentry);

	else if (S_ISFIFO(mode))
		rfs_dentry_set_ops_fifo(rdentry);

	else if (S_ISSOCK(mode))
		rfs_dentry_set_ops_sock(rdentry);

	spin_unlock(&rdentry->lock);
	rfs_inode_set_ops(rdentry->rinode);
}

void rfs_dentry_rem_data(struct dentry *dentry, struct rfs_flt *rflt)
{
	struct redirfs_data *data;
	struct rfs_dentry *rdentry;
	struct rfs_file *rfile;
	
	data = redirfs_detach_data_dentry(rflt, dentry);
	if (data && data->detach)
		data->detach(data);
	redirfs_put_data(data);

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return;

	spin_lock(&rdentry->lock);

	list_for_each_entry(rfile, &rdentry->rfiles, rdentry_list) {
		data = redirfs_detach_data_file(rflt, rfile->file);
		if (data && data->detach)
			data->detach(data);
		redirfs_put_data(data);
	}

	spin_unlock(&rdentry->lock);

	if (!dentry->d_inode) {
		rfs_dentry_put(rdentry);
		return;
	}

	data = redirfs_detach_data_inode(rflt, dentry->d_inode);
	if (data && data->detach)
		data->detach(data);
	redirfs_put_data(data);

	rfs_dentry_put(rdentry);
}

int rfs_dentry_move(struct dentry *dentry, struct rfs_flt *rflt,
		struct rfs_root *src, struct rfs_root *dst)
{
	int rv = 0;

	if (!rflt->ops)
		return 0;

	if (rflt->ops->dentry_moved)
		rv = rflt->ops->dentry_moved(src, dst, dentry);

	if (rv)
		return rv;

	if (!dentry->d_inode)
		return 0;

	if (rflt->ops->inode_moved)
		rv = rflt->ops->inode_moved(src, dst, dentry->d_inode);

	return rv;
}

driver/redirfs/rfs_inode.c0000644000076400007640000006540512112622747015473 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static rfs_kmem_cache_t *rfs_inode_cache = NULL;

static struct rfs_inode *rfs_inode_alloc(struct inode *inode)
{
	struct rfs_inode *rinode;

	rinode = kmem_cache_zalloc(rfs_inode_cache, GFP_KERNEL);
	if (IS_ERR(rinode))
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rinode->rdentries);
	INIT_LIST_HEAD(&rinode->data);
	rinode->inode = inode;
	rinode->op_old = inode->i_op;
	rinode->fop_old = inode->i_fop;
	spin_lock_init(&rinode->lock);
	rfs_mutex_init(&rinode->mutex);
	atomic_set(&rinode->count, 1);
	atomic_set(&rinode->nlink, 1);
	rinode->rdentries_nr = 0;

	if (inode->i_op)
		memcpy(&rinode->op_new, inode->i_op,
				sizeof(struct inode_operations));

	rinode->op_new.rename = rfs_rename;

	return rinode;
}

struct rfs_inode *rfs_inode_get(struct rfs_inode *rinode)
{
	if (!rinode || IS_ERR(rinode))
		return NULL;

	BUG_ON(!atomic_read(&rinode->count));
	atomic_inc(&rinode->count);

	return rinode;
}

void rfs_inode_put(struct rfs_inode *rinode)
{
	if (!rinode || IS_ERR(rinode))
		return;

	BUG_ON(!atomic_read(&rinode->count));
	if (!atomic_dec_and_test(&rinode->count))
		return;

	rfs_info_put(rinode->rinfo);
	rfs_data_remove(&rinode->data);
	kmem_cache_free(rfs_inode_cache, rinode);
}

struct rfs_inode *rfs_inode_add(struct inode *inode, struct rfs_info *rinfo)
{
	struct rfs_inode *ri_new;
	struct rfs_inode *ri;

	if (!inode)
		return NULL;

	ri_new = rfs_inode_alloc(inode);
	if (IS_ERR(ri_new))
		return ri_new;

	spin_lock(&inode->i_lock);

	ri = rfs_inode_find(inode);
	if (!ri) {
		ri_new->rinfo = rfs_info_get(rinfo);
		if (!S_ISSOCK(inode->i_mode))
			inode->i_fop = &rfs_file_ops;

		inode->i_op = &ri_new->op_new;
		rfs_inode_get(ri_new);
		ri = rfs_inode_get(ri_new);
	} else
		atomic_inc(&ri->nlink);

	spin_unlock(&inode->i_lock);

	rfs_inode_put(ri_new);

	return ri;
}

void rfs_inode_del(struct rfs_inode *rinode)
{
	if (!atomic_dec_and_test(&rinode->nlink))
		return;

	if (!S_ISSOCK(rinode->inode->i_mode))
		rinode->inode->i_fop = rinode->fop_old;

	rinode->inode->i_op = rinode->op_old;
	rfs_inode_put(rinode);
}

void rfs_inode_add_rdentry(struct rfs_inode *rinode, struct rfs_dentry *rdentry)
{
	rfs_mutex_lock(&rinode->mutex);
	rinode->rdentries_nr++;
	list_add_tail(&rdentry->rinode_list, &rinode->rdentries);
	rfs_mutex_unlock(&rinode->mutex);
	rfs_dentry_get(rdentry);
}

void rfs_inode_rem_rdentry(struct rfs_inode *rinode, struct rfs_dentry *rdentry)
{
	rfs_mutex_lock(&rinode->mutex);
	if (list_empty(&rdentry->rinode_list)) {
		rfs_mutex_unlock(&rinode->mutex);
		return;
	}
	rinode->rdentries_nr--;
	list_del_init(&rdentry->rinode_list);
	rfs_mutex_unlock(&rinode->mutex);
	rfs_dentry_put(rdentry);
}

static struct rfs_chain *rfs_inode_join_rchains(struct rfs_inode *rinode)
{
	struct rfs_dentry *rdentry = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_chain *rchain = NULL;
	struct rfs_chain *rchain_old = NULL;

	list_for_each_entry(rdentry, &rinode->rdentries, rinode_list) {
		spin_lock(&rdentry->lock);
		rinfo = rfs_info_get(rdentry->rinfo);
		spin_unlock(&rdentry->lock);

		rchain = rfs_chain_join(rinfo->rchain, rchain_old);

		rfs_info_put(rinfo);
		rfs_chain_put(rchain_old);

		if (IS_ERR(rchain))
			return rchain;

		rchain_old = rchain;
	}

	return rchain;
}

static int rfs_inode_set_rinfo_fast(struct rfs_inode *rinode)
{
	struct rfs_dentry *rdentry;

	if (!rinode->rdentries_nr)
		return 0;

	if (rinode->rdentries_nr > 1)
		return -1;

	rdentry = list_entry(rinode->rdentries.next, struct rfs_dentry, rinode_list);

	spin_lock(&rdentry->lock);
	spin_lock(&rinode->lock);
	rfs_info_put(rinode->rinfo);
	rinode->rinfo = rfs_info_get(rdentry->rinfo);
	spin_unlock(&rinode->lock);
	spin_unlock(&rdentry->lock);

	return 0;
}

struct rfs_info *rfs_inode_get_rinfo(struct rfs_inode *rinode)
{
	struct rfs_info *rinfo;

	spin_lock(&rinode->lock);
	rinfo = rfs_info_get(rinode->rinfo);
	spin_unlock(&rinode->lock);

	return rinfo;
}

int rfs_inode_set_rinfo(struct rfs_inode *rinode)
{
	struct rfs_chain *rchain;
	struct rfs_info *rinfo;
	struct rfs_ops *rops;
	int rv;

	if (!rinode)
		return 0;

	rfs_mutex_lock(&rinode->mutex);
	rv = rfs_inode_set_rinfo_fast(rinode);
	rfs_mutex_unlock(&rinode->mutex);
	if (!rv)
		return 0;

	rinfo = rfs_info_alloc(NULL, NULL);
	if (IS_ERR(rinfo))
		return PTR_ERR(rinfo);

	rops = rfs_ops_alloc();
	if (IS_ERR(rops)) {
		rfs_info_put(rinfo);
		return PTR_ERR(rops);
	}

	rinfo->rops = rops;

	rfs_mutex_lock(&rinode->mutex);
	rv = rfs_inode_set_rinfo_fast(rinode);
	if (!rv) {
		rfs_mutex_unlock(&rinode->mutex);
		rfs_info_put(rinfo);
		return 0;
	}

	rchain = rfs_inode_join_rchains(rinode);
	if (IS_ERR(rchain)) {
		rfs_mutex_unlock(&rinode->mutex);
		rfs_info_put(rinfo);
		return PTR_ERR(rchain);
	}

	rinfo->rchain = rchain;

	if (!rinfo->rchain) {
		rfs_info_put(rinfo);
		rinfo = rfs_info_get(rfs_info_none);
	}

	rfs_chain_ops(rinfo->rchain, rinfo->rops);
	spin_lock(&rinode->lock);
	rfs_info_put(rinode->rinfo);
	rinode->rinfo = rinfo;
	spin_unlock(&rinode->lock);
	rfs_mutex_unlock(&rinode->mutex);

	return 0;
}

int rfs_inode_cache_create(void)
{
	rfs_inode_cache = rfs_kmem_cache_create("rfs_inode_cache",
			sizeof(struct rfs_inode));

	if (!rfs_inode_cache)
		return -ENOMEM;

	return 0;
}

void rfs_inode_cache_destroy(void)
{
	kmem_cache_destroy(rfs_inode_cache);
}

static struct dentry *rfs_lookup(struct inode *dir, struct dentry *dentry,
		struct nameidata *nd)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	struct dentry *dadd = dentry;

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_LOOKUP;
	else
		return ERR_PTR(-ENOTDIR);

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	rargs.args.i_lookup.dir = dir;
	rargs.args.i_lookup.dentry = dentry;
	rargs.args.i_lookup.nd = nd;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->lookup)
			rargs.rv.rv_dentry = rinode->op_old->lookup(
					rargs.args.i_lookup.dir,
					rargs.args.i_lookup.dentry,
					rargs.args.i_lookup.nd);
		else
			rargs.rv.rv_dentry = ERR_PTR(-ENOSYS);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (IS_ERR(rargs.rv.rv_dentry))
		goto exit;

	if (rargs.rv.rv_dentry)
		dadd = rargs.rv.rv_dentry;

	if (rfs_dcache_rdentry_add(dadd, rinfo))
		BUG();
exit:
	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_dentry;
}

static int rfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_MKDIR;
	else
		BUG();

	rargs.args.i_mkdir.dir = dir;
	rargs.args.i_mkdir.dentry = dentry;
	rargs.args.i_mkdir.mode = mode;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->mkdir)
			rargs.rv.rv_int = rinode->op_old->mkdir(
					rargs.args.i_mkdir.dir,
					rargs.args.i_mkdir.dentry,
					rargs.args.i_mkdir.mode);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_create(struct inode *dir, struct dentry *dentry, int mode,
		struct nameidata *nd)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_CREATE;
	else
		BUG();

	rargs.args.i_create.dir = dir;
	rargs.args.i_create.dentry = dentry;
	rargs.args.i_create.mode = mode;
	rargs.args.i_create.nd = nd;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->create)
			rargs.rv.rv_int = rinode->op_old->create(
					rargs.args.i_create.dir,
					rargs.args.i_create.dentry,
					rargs.args.i_create.mode,
					rargs.args.i_create.nd);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_link(struct dentry *old_dentry, struct inode *dir,
		struct dentry *dentry)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_LINK;
	else
		BUG();

	rargs.args.i_link.old_dentry = old_dentry;
	rargs.args.i_link.dir = dir;
	rargs.args.i_link.dentry = dentry;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->link)
			rargs.rv.rv_int = rinode->op_old->link(
					rargs.args.i_link.old_dentry,
					rargs.args.i_link.dir,
					rargs.args.i_link.dentry);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_symlink(struct inode *dir, struct dentry *dentry,
		const char *oldname)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_SYMLINK;
	else
		BUG();

	rargs.args.i_symlink.dir = dir;
	rargs.args.i_symlink.dentry = dentry;
	rargs.args.i_symlink.oldname = oldname;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->symlink)
			rargs.rv.rv_int = rinode->op_old->symlink(
					rargs.args.i_symlink.dir,
					rargs.args.i_symlink.dentry,
					rargs.args.i_symlink.oldname);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_mknod(struct inode * dir, struct dentry *dentry, int mode,
		dev_t rdev)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_MKNOD;
	else
		BUG();

	rargs.args.i_mknod.dir = dir;
	rargs.args.i_mknod.dentry = dentry;
	rargs.args.i_mknod.mode = mode;
	rargs.args.i_mknod.rdev = rdev;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->mknod)
			rargs.rv.rv_int = rinode->op_old->mknod(
					rargs.args.i_mknod.dir,
					rargs.args.i_mknod.dentry,
					rargs.args.i_mknod.mode,
					rargs.args.i_mknod.rdev);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_unlink(struct inode *inode, struct dentry *dentry)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_UNLINK;
	else
		BUG();

	rargs.args.i_unlink.dir = inode;
	rargs.args.i_unlink.dentry = dentry;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->unlink)
			rargs.rv.rv_int = rinode->op_old->unlink(
					rargs.args.i_unlink.dir,
					rargs.args.i_unlink.dentry);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_rmdir(struct inode *inode, struct dentry *dentry)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_RMDIR;
	else
		BUG();

	rargs.args.i_unlink.dir = inode;
	rargs.args.i_unlink.dentry = dentry;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->rmdir)
			rargs.rv.rv_int = rinode->op_old->rmdir(
					rargs.args.i_unlink.dir,
					rargs.args.i_unlink.dentry);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)

static int rfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	int submask;

	submask = mask & ~MAY_APPEND;
	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_PERMISSION;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_PERMISSION;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_PERMISSION;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_PERMISSION;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_PERMISSION;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION;

	rargs.args.i_permission.inode = inode;
	rargs.args.i_permission.mask = mask;
	rargs.args.i_permission.nd = nd;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->permission)
			rargs.rv.rv_int = rinode->op_old->permission(
					rargs.args.i_permission.inode,
					rargs.args.i_permission.mask,
					rargs.args.i_permission.nd);
		else
			rargs.rv.rv_int = generic_permission(inode, submask,
					NULL);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)

static int rfs_permission(struct inode *inode, int mask)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	int submask;

	submask = mask & ~MAY_APPEND;
	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_PERMISSION;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_PERMISSION;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_PERMISSION;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_PERMISSION;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_PERMISSION;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION;

	rargs.args.i_permission.inode = inode;
	rargs.args.i_permission.mask = mask;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->permission)
			rargs.rv.rv_int = rinode->op_old->permission(
					rargs.args.i_permission.inode,
					rargs.args.i_permission.mask);
		else
			rargs.rv.rv_int = generic_permission(inode, submask,
					NULL);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)

static int rfs_permission(struct inode *inode, int mask, unsigned int flags)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	int submask;

	submask = mask & ~MAY_APPEND;
	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_PERMISSION;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_PERMISSION;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_PERMISSION;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_PERMISSION;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_PERMISSION;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION;

	rargs.args.i_permission.inode = inode;
	rargs.args.i_permission.mask = mask;
	rargs.args.i_permission.flags = flags;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->permission)
			rargs.rv.rv_int = rinode->op_old->permission(
					rargs.args.i_permission.inode,
					rargs.args.i_permission.mask,
					rargs.args.i_permission.flags);
		else
			rargs.rv.rv_int = generic_permission(inode, submask,
					flags, NULL);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#else

static int rfs_permission(struct inode *inode, int mask)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	int submask;

	submask = mask & ~MAY_APPEND;
	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_PERMISSION;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_PERMISSION;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_PERMISSION;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_PERMISSION;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_PERMISSION;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION;

	rargs.args.i_permission.inode = inode;
	rargs.args.i_permission.mask = mask;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->permission)
			rargs.rv.rv_int = rinode->op_old->permission(
					rargs.args.i_permission.inode,
					rargs.args.i_permission.mask);
		else
			rargs.rv.rv_int = generic_permission(inode, submask);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#endif

static int rfs_setattr_default(struct dentry *dentry, struct iattr *iattr)
{
	struct inode *inode = dentry->d_inode;
	int rv;

	rv = inode_change_ok(inode, iattr);
	if (rv)
		return rv;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)
	if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
	    (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid))
		return rfs_dq_transfer(inode, iattr) ? -EDQUOT : 0;
#endif

	return rfs_inode_setattr(inode, iattr);
}

static int rfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dentry->d_inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_SETATTR;
	else if (S_ISDIR(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_SETATTR;
	else if (S_ISLNK(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_SETATTR;
	else if (S_ISCHR(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_SETATTR;
	else if (S_ISBLK(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_SETATTR;
	else if (S_ISFIFO(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_SETATTR;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_SETATTR;

	rargs.args.i_setattr.dentry = dentry;
	rargs.args.i_setattr.iattr = iattr;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->setattr)
			rargs.rv.rv_int = rinode->op_old->setattr(
					rargs.args.i_setattr.dentry,
					rargs.args.i_setattr.iattr);
		else 
			rargs.rv.rv_int = rfs_setattr_default(dentry, iattr);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_precall_flts_rename(struct rfs_info *rinfo,
		struct rfs_context *rcont, struct redirfs_args *rargs)
{
	struct redirfs_filter_operations *ops;
	enum redirfs_rv (*rop)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv rv;

	if (!rinfo)
		return 0;

	if (!rinfo->rchain)
		return 0;

	rargs->type.call = REDIRFS_PRECALL;

	rcont->idx = rcont->idx_start;

	for (; rcont->idx < rinfo->rchain->rflts_nr; rcont->idx++) {
		if (!atomic_read(&rinfo->rchain->rflts[rcont->idx]->active))
			continue;

		ops = rinfo->rchain->rflts[rcont->idx]->ops;
		if (!ops)
			continue;
		rop = ops->pre_rename;
		if (!rop)
			continue;

		rv = rop(rcont, rargs);
		if (rv == REDIRFS_STOP)
			return -1;
	}

	rcont->idx--;

	return 0;
}

static void rfs_postcall_flts_rename(struct rfs_info *rinfo,
		struct rfs_context *rcont, struct redirfs_args *rargs)
{
	struct redirfs_filter_operations *ops;
	enum redirfs_rv (*rop)(redirfs_context, struct redirfs_args *);

	if (!rinfo)
		return;

	if (!rinfo->rchain)
		return;

	rargs->type.call = REDIRFS_POSTCALL;

	for (; rcont->idx >= rcont->idx_start; rcont->idx--) {
		if (!atomic_read(&rinfo->rchain->rflts[rcont->idx]->active))
			continue;

		ops = rinfo->rchain->rflts[rcont->idx]->ops;
		if (!ops)
			continue;
		rop = ops->post_rename;
		if (rop) 
			rop(rcont, rargs);
	}

	rcont->idx++;
}

int rfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
	struct rfs_inode *rinode_old;
	struct rfs_inode *rinode_new;
	struct rfs_info *rinfo_old;
	struct rfs_info *rinfo_new;
	struct rfs_context rcont_old;
	struct rfs_context rcont_new;
	struct redirfs_args rargs;

	rfs_context_init(&rcont_old, 0);
	rinode_old = rfs_inode_find(old_dir);
	rinfo_old = rfs_inode_get_rinfo(rinode_old);

	rfs_context_init(&rcont_new, 0);
	rinode_new = rfs_inode_find(new_dir);

	if (rinode_new)
		rinfo_new = rfs_inode_get_rinfo(rinode_new);
	else
		rinfo_new = NULL;

	if (S_ISDIR(old_dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_RENAME;
	else
		BUG();

	rargs.args.i_rename.old_dir = old_dir;
	rargs.args.i_rename.old_dentry = old_dentry;
	rargs.args.i_rename.new_dir = new_dir;
	rargs.args.i_rename.new_dentry = new_dentry;

	if (rfs_precall_flts(rinfo_old->rchain, &rcont_old, &rargs))
		goto skip;

	if (rfs_precall_flts_rename(rinfo_new, &rcont_new, &rargs))
		goto skip;

	if (rinode_old->op_old && rinode_old->op_old->rename)
		rargs.rv.rv_int = rinode_old->op_old->rename(
				rargs.args.i_rename.old_dir,
				rargs.args.i_rename.old_dentry,
				rargs.args.i_rename.new_dir,
				rargs.args.i_rename.new_dentry);
	else
		rargs.rv.rv_int = -ENOSYS;
	
skip:
	if (!rargs.rv.rv_int)
		rargs.rv.rv_int = rfs_fsrename(
				rargs.args.i_rename.old_dir,
				rargs.args.i_rename.old_dentry,
				rargs.args.i_rename.new_dir,
				rargs.args.i_rename.new_dentry);

	rfs_postcall_flts_rename(rinfo_new, &rcont_new, &rargs);
	rfs_postcall_flts(rinfo_old->rchain, &rcont_old, &rargs);

	rfs_context_deinit(&rcont_old);
	rfs_context_deinit(&rcont_new);
	rfs_inode_put(rinode_old);
	rfs_inode_put(rinode_new);
	rfs_info_put(rinfo_old);
	rfs_info_put(rinfo_new);
	return rargs.rv.rv_int;
}


static void rfs_inode_set_ops_reg(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_REG_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_REG_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_dir(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_UNLINK, unlink);
	RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_RMDIR, rmdir);
	RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_SETATTR, setattr);

	RFS_SET_IOP_MGT(rinode, create);
	RFS_SET_IOP_MGT(rinode, link);
	RFS_SET_IOP_MGT(rinode, mknod);
	RFS_SET_IOP_MGT(rinode, symlink);

	rinode->op_new.lookup = rfs_lookup;
	rinode->op_new.mkdir = rfs_mkdir;
}

static void rfs_inode_set_ops_lnk(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_LNK_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_LNK_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_chr(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_CHR_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_CHR_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_blk(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_BLK_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_BLK_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_fifo(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_FIFO_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_FIFO_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_sock(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_SOCK_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_SOCK_IOP_SETATTR, setattr);
}

static void rfs_inode_set_aops_reg(struct rfs_inode *rinode)
{
}

void rfs_inode_set_ops(struct rfs_inode *rinode)
{
	umode_t mode = rinode->inode->i_mode;

	spin_lock(&rinode->lock);

	if (S_ISREG(mode)) {
		rfs_inode_set_ops_reg(rinode);
		rfs_inode_set_aops_reg(rinode);

	} else if (S_ISDIR(mode))
		rfs_inode_set_ops_dir(rinode);

	else if (S_ISLNK(mode))
		rfs_inode_set_ops_lnk(rinode);

	else if (S_ISCHR(mode))
		rfs_inode_set_ops_chr(rinode);

	else if (S_ISBLK(mode))
		rfs_inode_set_ops_blk(rinode);

	else if (S_ISFIFO(mode))
		rfs_inode_set_ops_fifo(rinode);

	else if (S_ISSOCK(mode))
		rfs_inode_set_ops_sock(rinode);

	spin_unlock(&rinode->lock);
}

driver/redirfs/rfs_flt.c0000644000076400007640000001333312112622747015153 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static LIST_HEAD(rfs_flt_list);
RFS_DEFINE_MUTEX(rfs_flt_list_mutex);

struct rfs_flt *rfs_flt_alloc(struct redirfs_filter_info *flt_info)
{
	struct rfs_flt *rflt;
	char *name;
	int len;
	
	len = strlen(flt_info->name);
	name = kzalloc(len + 1, GFP_KERNEL);
	if (!name)
		return ERR_PTR(-ENOMEM);

	strncpy(name, flt_info->name, len);

	rflt = kzalloc(sizeof(struct rfs_flt), GFP_KERNEL);
	if (!rflt) {
		kfree(name);
		return ERR_PTR(-ENOMEM);
	}

	INIT_LIST_HEAD(&rflt->list);
	rflt->name = name;
	rflt->priority = flt_info->priority;
	rflt->owner = flt_info->owner;
	rflt->ops = flt_info->ops;
	atomic_set(&rflt->count, 1);
	spin_lock_init(&rflt->lock);
	try_module_get(rflt->owner);

	if (flt_info->active)
		atomic_set(&rflt->active, 1);
	else
		atomic_set(&rflt->active, 0);

	return rflt;
}

struct rfs_flt *rfs_flt_get(struct rfs_flt *rflt)
{
	if (!rflt || IS_ERR(rflt))
		return NULL;

	BUG_ON(!atomic_read(&rflt->count));
	atomic_inc(&rflt->count);

	return rflt;
}

void rfs_flt_put(struct rfs_flt *rflt)
{
	if (!rflt || IS_ERR(rflt))
		return;

	BUG_ON(!atomic_read(&rflt->count));
	if (!atomic_dec_and_test(&rflt->count))
		return;

	kfree(rflt->name);
	kfree(rflt);
}

void rfs_flt_release(struct kobject *kobj)
{
	struct rfs_flt *rflt = rfs_kobj_to_rflt(kobj);

	rfs_flt_put(rflt);
}

static int rfs_flt_exist(const char *name, int priority)
{
	struct rfs_flt *rflt;

	list_for_each_entry(rflt, &rfs_flt_list, list) {
		if (rflt->priority == priority)
			return 1;

		if (!strcmp(rflt->name, name))
			return 1;
	}

	return 0;
}

redirfs_filter redirfs_register_filter(struct redirfs_filter_info *info)
{
	struct rfs_flt *rflt;
	int rv;

	might_sleep();

	if (!info)
		return ERR_PTR(-EINVAL);

	rfs_mutex_lock(&rfs_flt_list_mutex);

	if (rfs_flt_exist(info->name, info->priority)) {
		rfs_mutex_unlock(&rfs_flt_list_mutex);
		return ERR_PTR(-EEXIST);
	}

	rflt = rfs_flt_alloc(info);
	if (IS_ERR(rflt)) {
		rfs_mutex_unlock(&rfs_flt_list_mutex);
		return (redirfs_filter)rflt;
	}

	rv = rfs_flt_sysfs_init(rflt);
	if (rv) {
		rfs_flt_put(rflt);
		return ERR_PTR(rv);
	}

	list_add_tail(&rflt->list, &rfs_flt_list);
	rfs_flt_get(rflt);

	rfs_mutex_unlock(&rfs_flt_list_mutex);

	return (redirfs_filter)rflt;
}

int redirfs_unregister_filter(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	might_sleep();

	if (!rflt || IS_ERR(rflt))
		return -EINVAL;

	spin_lock(&rflt->lock);

	/*
	 * Check if the unregistration is already in progress.
	 */
	if (atomic_read(&rflt->count) < 3) {
		spin_unlock(&rflt->lock);
		return 0;
	}

	/*
	 * Filter can be unregistered only if the reference counter is equal to
	 * three. This means no one else is using it except the following.
	 *
	 *    - sysfs interface
	 *    - internal filter list
	 *    - handler returned to filter after registration
	 */
	if (atomic_read(&rflt->count) != 3) {
		spin_unlock(&rflt->lock);
		return -EBUSY;
	}

	rfs_flt_put(rflt);
	spin_unlock(&rflt->lock);

	rfs_mutex_lock(&rfs_flt_list_mutex);
	list_del_init(&rflt->list);
	rfs_mutex_unlock(&rfs_flt_list_mutex);

	module_put(rflt->owner);

	return 0;
}

void redirfs_delete_filter(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || IS_ERR(rflt))
		return;

	BUG_ON(atomic_read(&rflt->count) != 2);

	rfs_flt_sysfs_exit(rflt);
	rfs_flt_put(rflt);
}

static int rfs_flt_set_ops(struct rfs_flt *rflt)
{
	struct rfs_root *rroot;
	struct rfs_info *rinfo;
	int rv;

	list_for_each_entry(rroot, &rfs_root_list, list) {
		if (rfs_chain_find(rroot->rinfo->rchain, rflt) == -1)
			continue;

		rinfo = rfs_info_alloc(rroot, rroot->rinfo->rchain);
		if (IS_ERR(rinfo))
			return PTR_ERR(rinfo);

		rv = rfs_info_reset(rroot->dentry, rinfo);
		if (rv) {
			rfs_info_put(rinfo);
			return rv;
		}

		rfs_info_put(rroot->rinfo);
		rroot->rinfo = rinfo;
	}

	return 0;
}

int redirfs_set_operations(redirfs_filter filter, struct redirfs_op_info ops[])
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;
	int i = 0;
	int rv = 0;

	might_sleep();

	if (!rflt || IS_ERR(rflt))
		return -EINVAL;

	while (ops[i].op_id != REDIRFS_OP_END) {
		rflt->cbs[ops[i].op_id].pre_cb = ops[i].pre_cb;
		rflt->cbs[ops[i].op_id].post_cb = ops[i].post_cb;
		i++;
	}

	rfs_mutex_lock(&rfs_path_mutex);
	rv = rfs_flt_set_ops(rflt);
	rfs_mutex_unlock(&rfs_path_mutex);

	return rv;
}

int redirfs_activate_filter(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || IS_ERR(rflt))
		return -EINVAL;

	atomic_set(&rflt->active, 1);

	return 0;
}

int redirfs_deactivate_filter(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || IS_ERR(rflt))
		return -EINVAL;

	atomic_set(&rflt->active, 0);

	return 0;
}

EXPORT_SYMBOL(redirfs_register_filter);
EXPORT_SYMBOL(redirfs_unregister_filter);
EXPORT_SYMBOL(redirfs_delete_filter);
EXPORT_SYMBOL(redirfs_set_operations);
EXPORT_SYMBOL(redirfs_activate_filter);
EXPORT_SYMBOL(redirfs_deactivate_filter);

driver/redirfs/rfs_data.c0000644000076400007640000002424612112622747015304 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

void rfs_data_remove(struct list_head *head)
{
	struct redirfs_data *data;
	struct redirfs_data *tmp;

	list_for_each_entry_safe(data, tmp, head, list) {
		list_del_init(&data->list);
		if (data->detach)
			data->detach(data);
		redirfs_put_data(data);
	}
}

int redirfs_init_data(struct redirfs_data *data, redirfs_filter filter,
		void (*free)(struct redirfs_data *),
		void (*detach)(struct redirfs_data *))
{
	if (!data || !filter || IS_ERR(filter) || !free)
		return -EINVAL;

	INIT_LIST_HEAD(&data->list);
	atomic_set(&data->cnt, 1);
	data->free = free;
	data->detach = detach;
	data->filter = rfs_flt_get(filter);

	return 0;
}

struct redirfs_data *redirfs_get_data(struct redirfs_data *data)
{
	if (!data || IS_ERR(data))
		return NULL;
	
	BUG_ON(!atomic_read(&data->cnt));

	atomic_inc(&data->cnt);

	return data;
}

void redirfs_put_data(struct redirfs_data *data)
{
	if (!data || IS_ERR(data))
		return;

	BUG_ON(!atomic_read(&data->cnt));
	
	if (!atomic_dec_and_test(&data->cnt))
		return;

	rfs_flt_put(data->filter);
	data->free(data);
}

static struct redirfs_data *rfs_find_data(struct list_head *head,
		redirfs_filter filter)
{
	struct redirfs_data *data;

	list_for_each_entry(data, head, list) {
		if (data->filter == filter)
			return redirfs_get_data(data);
	}

	return NULL;
}

struct redirfs_data *redirfs_attach_data_file(redirfs_filter filter,
		struct file *file, struct redirfs_data *data)
{
	struct rfs_file *rfile;
	struct redirfs_data *rv = NULL;

	if (!filter || IS_ERR(filter) || !file || !data)
		return NULL;

	rfile = rfs_file_find(file);
	if (!rfile)
		return NULL;

	spin_lock(&rfile->rdentry->lock);
	spin_lock(&rfile->lock);

	if (rfs_chain_find(rfile->rdentry->rinfo->rchain, filter) == -1)
		goto exit;

	rv = rfs_find_data(&rfile->data, filter);
	if (rv)
		goto exit;

	list_add_tail(&data->list, &rfile->data); 
	redirfs_get_data(data);
	rv = redirfs_get_data(data);
exit:
	spin_unlock(&rfile->lock);
	spin_unlock(&rfile->rdentry->lock);
	rfs_file_put(rfile);
	return rv;
}

struct redirfs_data *redirfs_detach_data_file(redirfs_filter filter,
		struct file *file)
{
	struct rfs_file *rfile;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !file)
		return NULL;

	rfile = rfs_file_find(file);
	if (!rfile)
		return NULL;

	spin_lock(&rfile->lock);

	data = rfs_find_data(&rfile->data, filter);
	if (data)
		list_del(&data->list);

	spin_unlock(&rfile->lock);
	redirfs_put_data(data);
	rfs_file_put(rfile);
	return data;
}

struct redirfs_data *redirfs_get_data_file(redirfs_filter filter,
		struct file *file)
{
	struct rfs_file *rfile;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !file)
		return NULL;

	rfile = rfs_file_find(file);
	if (!rfile)
		return NULL;

	spin_lock(&rfile->lock);

	data = rfs_find_data(&rfile->data, filter);

	spin_unlock(&rfile->lock);
	rfs_file_put(rfile);
	return data;
}

struct redirfs_data *redirfs_attach_data_dentry(redirfs_filter filter,
		struct dentry *dentry, struct redirfs_data *data)
{
	struct rfs_dentry *rdentry;
	struct redirfs_data *rv = NULL;

	if (!filter || IS_ERR(filter) || !dentry || !data)
		return NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	spin_lock(&rdentry->lock);

	if (rfs_chain_find(rdentry->rinfo->rchain, filter) == -1)
		goto exit;

	rv = rfs_find_data(&rdentry->data, filter);
	if (rv)
		goto exit;

	list_add_tail(&data->list, &rdentry->data); 
	redirfs_get_data(data);
	rv = redirfs_get_data(data);
exit:
	spin_unlock(&rdentry->lock);
	rfs_dentry_put(rdentry);
	return rv;
}

struct redirfs_data *redirfs_detach_data_dentry(redirfs_filter filter,
		struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !dentry)
		return NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	spin_lock(&rdentry->lock);

	data = rfs_find_data(&rdentry->data, filter);
	if (data)
		list_del(&data->list);

	spin_unlock(&rdentry->lock);
	redirfs_put_data(data);
	rfs_dentry_put(rdentry);
	return data;
}

struct redirfs_data *redirfs_get_data_dentry(redirfs_filter filter,
		struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !dentry)
		return NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	spin_lock(&rdentry->lock);

	data = rfs_find_data(&rdentry->data, filter);

	spin_unlock(&rdentry->lock);
	rfs_dentry_put(rdentry);
	return data;
}

struct redirfs_data *redirfs_attach_data_inode(redirfs_filter filter,
		struct inode *inode, struct redirfs_data *data)
{
	struct rfs_inode *rinode;
	struct redirfs_data *rv = NULL;

	if (!filter || IS_ERR(filter) || !inode || !data)
		return NULL;

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return NULL;

	spin_lock(&rinode->lock);

	if (rfs_chain_find(rinode->rinfo->rchain, filter) == -1)
		goto exit;

	rv = rfs_find_data(&rinode->data, filter);
	if (rv)
		goto exit;

	list_add_tail(&data->list, &rinode->data); 
	redirfs_get_data(data);
	rv = redirfs_get_data(data);
exit:
	spin_unlock(&rinode->lock);
	rfs_inode_put(rinode);
	return rv;
}

struct redirfs_data *redirfs_detach_data_inode(redirfs_filter filter,
		struct inode *inode)
{
	struct rfs_inode *rinode;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !inode)
		return NULL;

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return NULL;

	spin_lock(&rinode->lock);

	data = rfs_find_data(&rinode->data, filter);
	if (data)
		list_del(&data->list);

	spin_unlock(&rinode->lock);
	redirfs_put_data(data);
	rfs_inode_put(rinode);
	return data;
}

struct redirfs_data *redirfs_get_data_inode(redirfs_filter filter,
		struct inode *inode)
{
	struct rfs_inode *rinode;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !inode)
		return NULL;

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return NULL;

	spin_lock(&rinode->lock);

	data = rfs_find_data(&rinode->data, filter);

	spin_unlock(&rinode->lock);
	rfs_inode_put(rinode);
	return data;
}

void rfs_context_init(struct rfs_context *rcont, int start)
{
	INIT_LIST_HEAD(&rcont->data);
	rcont->idx_start = start;
	rcont->idx = 0;
}

void rfs_context_deinit(struct rfs_context *rcont)
{
	rfs_data_remove(&rcont->data);
}

struct redirfs_data *redirfs_attach_data_context(redirfs_filter filter,
		redirfs_context context, struct redirfs_data *data)
{
	struct rfs_context *rcont = (struct rfs_context *)context;
	struct redirfs_data *rv;

	if (!filter || IS_ERR(filter) || !context || !data)
		return NULL;

	rv = rfs_find_data(&rcont->data, filter);
	if (rv)
		return rv;

	list_add_tail(&data->list, &rcont->data); 
	redirfs_get_data(data);

	return redirfs_get_data(data);
}

struct redirfs_data *redirfs_detach_data_context(redirfs_filter filter,
		redirfs_context context)
{
	struct rfs_context *rcont = (struct rfs_context *)context;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !context)
		return NULL;

	data = rfs_find_data(&rcont->data, filter);
	if (data)
		list_del(&data->list);

	redirfs_put_data(data);
	return data;
}

struct redirfs_data *redirfs_get_data_context(redirfs_filter filter,
		redirfs_context context)
{
	struct rfs_context *rcont = (struct rfs_context *)context;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter)|| !context)
		return NULL;

	data = rfs_find_data(&rcont->data, filter);

	return data;
}

struct redirfs_data *redirfs_attach_data_root(redirfs_filter filter,
		redirfs_root root, struct redirfs_data *data)
{
	struct rfs_root *rroot = (struct rfs_root *)root;
	struct redirfs_data *rv = NULL;
	int found = 0;

	if (!filter || IS_ERR(filter) || !root || !data)
		return NULL;

	spin_lock(&rroot->lock);

	if (rfs_chain_find(rroot->rinch, filter) != -1)
		found = 1;

	else if (rfs_chain_find(rroot->rexch, filter) != -1)
		found = 1;

	if (!found)
		goto exit;

	rv = rfs_find_data(&rroot->data, filter);
	if (rv)
		goto exit;

	list_add_tail(&data->list, &rroot->data); 
	redirfs_get_data(data);
	rv = redirfs_get_data(data);
exit:
	spin_unlock(&rroot->lock);
	return rv;
}

struct redirfs_data *redirfs_detach_data_root(redirfs_filter filter,
		redirfs_root root)
{
	struct rfs_root *rroot = (struct rfs_root *)root;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !root)
		return NULL;

	spin_lock(&rroot->lock);

	data = rfs_find_data(&rroot->data, filter);
	if (data)
		list_del(&data->list);

	spin_unlock(&rroot->lock);
	redirfs_put_data(data);

	return data;
}

struct redirfs_data *redirfs_get_data_root(redirfs_filter filter,
		redirfs_root root)
{
	struct rfs_root *rroot = (struct rfs_root *)root;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !root)
		return NULL;

	spin_lock(&rroot->lock);

	data = rfs_find_data(&rroot->data, filter);

	spin_unlock(&rroot->lock);

	return data;
}

EXPORT_SYMBOL(redirfs_init_data);
EXPORT_SYMBOL(redirfs_get_data);
EXPORT_SYMBOL(redirfs_put_data);
EXPORT_SYMBOL(redirfs_attach_data_file);
EXPORT_SYMBOL(redirfs_detach_data_file);
EXPORT_SYMBOL(redirfs_get_data_file);
EXPORT_SYMBOL(redirfs_attach_data_dentry);
EXPORT_SYMBOL(redirfs_detach_data_dentry);
EXPORT_SYMBOL(redirfs_get_data_dentry);
EXPORT_SYMBOL(redirfs_attach_data_inode);
EXPORT_SYMBOL(redirfs_detach_data_inode);
EXPORT_SYMBOL(redirfs_get_data_inode);
EXPORT_SYMBOL(redirfs_attach_data_context);
EXPORT_SYMBOL(redirfs_detach_data_context);
EXPORT_SYMBOL(redirfs_get_data_context);
EXPORT_SYMBOL(redirfs_attach_data_root);
EXPORT_SYMBOL(redirfs_detach_data_root);
EXPORT_SYMBOL(redirfs_get_data_root);

driver/redirfs/Makefile0000644000076400007640000000027112112622747015005 0ustar  comodocomodoobj-m += redirfs.o
redirfs-objs := rfs_path.o rfs_root.o rfs_info.o rfs_file.o rfs_dentry.o \
	rfs_inode.o rfs_dcache.o rfs_chain.o rfs_ops.o rfs_data.o \
	rfs_flt.o rfs_sysfs.o rfs.o

driver/redirfs/.svn/0000755000076400007640000000000012112622747014231 5ustar  comodocomododriver/redirfs/.svn/text-base/0000755000076400007640000000000012112622747016125 5ustar  comodocomododriver/redirfs/.svn/text-base/rfs_inode.c.svn-base0000644000076400007640000006540512112622747021770 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static rfs_kmem_cache_t *rfs_inode_cache = NULL;

static struct rfs_inode *rfs_inode_alloc(struct inode *inode)
{
	struct rfs_inode *rinode;

	rinode = kmem_cache_zalloc(rfs_inode_cache, GFP_KERNEL);
	if (IS_ERR(rinode))
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rinode->rdentries);
	INIT_LIST_HEAD(&rinode->data);
	rinode->inode = inode;
	rinode->op_old = inode->i_op;
	rinode->fop_old = inode->i_fop;
	spin_lock_init(&rinode->lock);
	rfs_mutex_init(&rinode->mutex);
	atomic_set(&rinode->count, 1);
	atomic_set(&rinode->nlink, 1);
	rinode->rdentries_nr = 0;

	if (inode->i_op)
		memcpy(&rinode->op_new, inode->i_op,
				sizeof(struct inode_operations));

	rinode->op_new.rename = rfs_rename;

	return rinode;
}

struct rfs_inode *rfs_inode_get(struct rfs_inode *rinode)
{
	if (!rinode || IS_ERR(rinode))
		return NULL;

	BUG_ON(!atomic_read(&rinode->count));
	atomic_inc(&rinode->count);

	return rinode;
}

void rfs_inode_put(struct rfs_inode *rinode)
{
	if (!rinode || IS_ERR(rinode))
		return;

	BUG_ON(!atomic_read(&rinode->count));
	if (!atomic_dec_and_test(&rinode->count))
		return;

	rfs_info_put(rinode->rinfo);
	rfs_data_remove(&rinode->data);
	kmem_cache_free(rfs_inode_cache, rinode);
}

struct rfs_inode *rfs_inode_add(struct inode *inode, struct rfs_info *rinfo)
{
	struct rfs_inode *ri_new;
	struct rfs_inode *ri;

	if (!inode)
		return NULL;

	ri_new = rfs_inode_alloc(inode);
	if (IS_ERR(ri_new))
		return ri_new;

	spin_lock(&inode->i_lock);

	ri = rfs_inode_find(inode);
	if (!ri) {
		ri_new->rinfo = rfs_info_get(rinfo);
		if (!S_ISSOCK(inode->i_mode))
			inode->i_fop = &rfs_file_ops;

		inode->i_op = &ri_new->op_new;
		rfs_inode_get(ri_new);
		ri = rfs_inode_get(ri_new);
	} else
		atomic_inc(&ri->nlink);

	spin_unlock(&inode->i_lock);

	rfs_inode_put(ri_new);

	return ri;
}

void rfs_inode_del(struct rfs_inode *rinode)
{
	if (!atomic_dec_and_test(&rinode->nlink))
		return;

	if (!S_ISSOCK(rinode->inode->i_mode))
		rinode->inode->i_fop = rinode->fop_old;

	rinode->inode->i_op = rinode->op_old;
	rfs_inode_put(rinode);
}

void rfs_inode_add_rdentry(struct rfs_inode *rinode, struct rfs_dentry *rdentry)
{
	rfs_mutex_lock(&rinode->mutex);
	rinode->rdentries_nr++;
	list_add_tail(&rdentry->rinode_list, &rinode->rdentries);
	rfs_mutex_unlock(&rinode->mutex);
	rfs_dentry_get(rdentry);
}

void rfs_inode_rem_rdentry(struct rfs_inode *rinode, struct rfs_dentry *rdentry)
{
	rfs_mutex_lock(&rinode->mutex);
	if (list_empty(&rdentry->rinode_list)) {
		rfs_mutex_unlock(&rinode->mutex);
		return;
	}
	rinode->rdentries_nr--;
	list_del_init(&rdentry->rinode_list);
	rfs_mutex_unlock(&rinode->mutex);
	rfs_dentry_put(rdentry);
}

static struct rfs_chain *rfs_inode_join_rchains(struct rfs_inode *rinode)
{
	struct rfs_dentry *rdentry = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_chain *rchain = NULL;
	struct rfs_chain *rchain_old = NULL;

	list_for_each_entry(rdentry, &rinode->rdentries, rinode_list) {
		spin_lock(&rdentry->lock);
		rinfo = rfs_info_get(rdentry->rinfo);
		spin_unlock(&rdentry->lock);

		rchain = rfs_chain_join(rinfo->rchain, rchain_old);

		rfs_info_put(rinfo);
		rfs_chain_put(rchain_old);

		if (IS_ERR(rchain))
			return rchain;

		rchain_old = rchain;
	}

	return rchain;
}

static int rfs_inode_set_rinfo_fast(struct rfs_inode *rinode)
{
	struct rfs_dentry *rdentry;

	if (!rinode->rdentries_nr)
		return 0;

	if (rinode->rdentries_nr > 1)
		return -1;

	rdentry = list_entry(rinode->rdentries.next, struct rfs_dentry, rinode_list);

	spin_lock(&rdentry->lock);
	spin_lock(&rinode->lock);
	rfs_info_put(rinode->rinfo);
	rinode->rinfo = rfs_info_get(rdentry->rinfo);
	spin_unlock(&rinode->lock);
	spin_unlock(&rdentry->lock);

	return 0;
}

struct rfs_info *rfs_inode_get_rinfo(struct rfs_inode *rinode)
{
	struct rfs_info *rinfo;

	spin_lock(&rinode->lock);
	rinfo = rfs_info_get(rinode->rinfo);
	spin_unlock(&rinode->lock);

	return rinfo;
}

int rfs_inode_set_rinfo(struct rfs_inode *rinode)
{
	struct rfs_chain *rchain;
	struct rfs_info *rinfo;
	struct rfs_ops *rops;
	int rv;

	if (!rinode)
		return 0;

	rfs_mutex_lock(&rinode->mutex);
	rv = rfs_inode_set_rinfo_fast(rinode);
	rfs_mutex_unlock(&rinode->mutex);
	if (!rv)
		return 0;

	rinfo = rfs_info_alloc(NULL, NULL);
	if (IS_ERR(rinfo))
		return PTR_ERR(rinfo);

	rops = rfs_ops_alloc();
	if (IS_ERR(rops)) {
		rfs_info_put(rinfo);
		return PTR_ERR(rops);
	}

	rinfo->rops = rops;

	rfs_mutex_lock(&rinode->mutex);
	rv = rfs_inode_set_rinfo_fast(rinode);
	if (!rv) {
		rfs_mutex_unlock(&rinode->mutex);
		rfs_info_put(rinfo);
		return 0;
	}

	rchain = rfs_inode_join_rchains(rinode);
	if (IS_ERR(rchain)) {
		rfs_mutex_unlock(&rinode->mutex);
		rfs_info_put(rinfo);
		return PTR_ERR(rchain);
	}

	rinfo->rchain = rchain;

	if (!rinfo->rchain) {
		rfs_info_put(rinfo);
		rinfo = rfs_info_get(rfs_info_none);
	}

	rfs_chain_ops(rinfo->rchain, rinfo->rops);
	spin_lock(&rinode->lock);
	rfs_info_put(rinode->rinfo);
	rinode->rinfo = rinfo;
	spin_unlock(&rinode->lock);
	rfs_mutex_unlock(&rinode->mutex);

	return 0;
}

int rfs_inode_cache_create(void)
{
	rfs_inode_cache = rfs_kmem_cache_create("rfs_inode_cache",
			sizeof(struct rfs_inode));

	if (!rfs_inode_cache)
		return -ENOMEM;

	return 0;
}

void rfs_inode_cache_destroy(void)
{
	kmem_cache_destroy(rfs_inode_cache);
}

static struct dentry *rfs_lookup(struct inode *dir, struct dentry *dentry,
		struct nameidata *nd)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	struct dentry *dadd = dentry;

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_LOOKUP;
	else
		return ERR_PTR(-ENOTDIR);

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	rargs.args.i_lookup.dir = dir;
	rargs.args.i_lookup.dentry = dentry;
	rargs.args.i_lookup.nd = nd;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->lookup)
			rargs.rv.rv_dentry = rinode->op_old->lookup(
					rargs.args.i_lookup.dir,
					rargs.args.i_lookup.dentry,
					rargs.args.i_lookup.nd);
		else
			rargs.rv.rv_dentry = ERR_PTR(-ENOSYS);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (IS_ERR(rargs.rv.rv_dentry))
		goto exit;

	if (rargs.rv.rv_dentry)
		dadd = rargs.rv.rv_dentry;

	if (rfs_dcache_rdentry_add(dadd, rinfo))
		BUG();
exit:
	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_dentry;
}

static int rfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_MKDIR;
	else
		BUG();

	rargs.args.i_mkdir.dir = dir;
	rargs.args.i_mkdir.dentry = dentry;
	rargs.args.i_mkdir.mode = mode;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->mkdir)
			rargs.rv.rv_int = rinode->op_old->mkdir(
					rargs.args.i_mkdir.dir,
					rargs.args.i_mkdir.dentry,
					rargs.args.i_mkdir.mode);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_create(struct inode *dir, struct dentry *dentry, int mode,
		struct nameidata *nd)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_CREATE;
	else
		BUG();

	rargs.args.i_create.dir = dir;
	rargs.args.i_create.dentry = dentry;
	rargs.args.i_create.mode = mode;
	rargs.args.i_create.nd = nd;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->create)
			rargs.rv.rv_int = rinode->op_old->create(
					rargs.args.i_create.dir,
					rargs.args.i_create.dentry,
					rargs.args.i_create.mode,
					rargs.args.i_create.nd);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_link(struct dentry *old_dentry, struct inode *dir,
		struct dentry *dentry)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_LINK;
	else
		BUG();

	rargs.args.i_link.old_dentry = old_dentry;
	rargs.args.i_link.dir = dir;
	rargs.args.i_link.dentry = dentry;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->link)
			rargs.rv.rv_int = rinode->op_old->link(
					rargs.args.i_link.old_dentry,
					rargs.args.i_link.dir,
					rargs.args.i_link.dentry);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_symlink(struct inode *dir, struct dentry *dentry,
		const char *oldname)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_SYMLINK;
	else
		BUG();

	rargs.args.i_symlink.dir = dir;
	rargs.args.i_symlink.dentry = dentry;
	rargs.args.i_symlink.oldname = oldname;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->symlink)
			rargs.rv.rv_int = rinode->op_old->symlink(
					rargs.args.i_symlink.dir,
					rargs.args.i_symlink.dentry,
					rargs.args.i_symlink.oldname);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_mknod(struct inode * dir, struct dentry *dentry, int mode,
		dev_t rdev)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dir);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_MKNOD;
	else
		BUG();

	rargs.args.i_mknod.dir = dir;
	rargs.args.i_mknod.dentry = dentry;
	rargs.args.i_mknod.mode = mode;
	rargs.args.i_mknod.rdev = rdev;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->mknod)
			rargs.rv.rv_int = rinode->op_old->mknod(
					rargs.args.i_mknod.dir,
					rargs.args.i_mknod.dentry,
					rargs.args.i_mknod.mode,
					rargs.args.i_mknod.rdev);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (!rargs.rv.rv_int) {
		if (rfs_dcache_rdentry_add(dentry, rinfo))
			BUG();
	}

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_unlink(struct inode *inode, struct dentry *dentry)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_UNLINK;
	else
		BUG();

	rargs.args.i_unlink.dir = inode;
	rargs.args.i_unlink.dentry = dentry;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->unlink)
			rargs.rv.rv_int = rinode->op_old->unlink(
					rargs.args.i_unlink.dir,
					rargs.args.i_unlink.dentry);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_rmdir(struct inode *inode, struct dentry *dentry)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_RMDIR;
	else
		BUG();

	rargs.args.i_unlink.dir = inode;
	rargs.args.i_unlink.dentry = dentry;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->rmdir)
			rargs.rv.rv_int = rinode->op_old->rmdir(
					rargs.args.i_unlink.dir,
					rargs.args.i_unlink.dentry);
		else
			rargs.rv.rv_int = -ENOSYS;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)

static int rfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	int submask;

	submask = mask & ~MAY_APPEND;
	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_PERMISSION;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_PERMISSION;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_PERMISSION;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_PERMISSION;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_PERMISSION;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION;

	rargs.args.i_permission.inode = inode;
	rargs.args.i_permission.mask = mask;
	rargs.args.i_permission.nd = nd;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->permission)
			rargs.rv.rv_int = rinode->op_old->permission(
					rargs.args.i_permission.inode,
					rargs.args.i_permission.mask,
					rargs.args.i_permission.nd);
		else
			rargs.rv.rv_int = generic_permission(inode, submask,
					NULL);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)

static int rfs_permission(struct inode *inode, int mask)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	int submask;

	submask = mask & ~MAY_APPEND;
	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_PERMISSION;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_PERMISSION;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_PERMISSION;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_PERMISSION;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_PERMISSION;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION;

	rargs.args.i_permission.inode = inode;
	rargs.args.i_permission.mask = mask;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->permission)
			rargs.rv.rv_int = rinode->op_old->permission(
					rargs.args.i_permission.inode,
					rargs.args.i_permission.mask);
		else
			rargs.rv.rv_int = generic_permission(inode, submask,
					NULL);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)

static int rfs_permission(struct inode *inode, int mask, unsigned int flags)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	int submask;

	submask = mask & ~MAY_APPEND;
	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_PERMISSION;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_PERMISSION;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_PERMISSION;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_PERMISSION;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_PERMISSION;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION;

	rargs.args.i_permission.inode = inode;
	rargs.args.i_permission.mask = mask;
	rargs.args.i_permission.flags = flags;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->permission)
			rargs.rv.rv_int = rinode->op_old->permission(
					rargs.args.i_permission.inode,
					rargs.args.i_permission.mask,
					rargs.args.i_permission.flags);
		else
			rargs.rv.rv_int = generic_permission(inode, submask,
					flags, NULL);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#else

static int rfs_permission(struct inode *inode, int mask)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;
	int submask;

	submask = mask & ~MAY_APPEND;
	rinode = rfs_inode_find(inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_PERMISSION;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_PERMISSION;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_PERMISSION;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_PERMISSION;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_PERMISSION;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION;

	rargs.args.i_permission.inode = inode;
	rargs.args.i_permission.mask = mask;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->permission)
			rargs.rv.rv_int = rinode->op_old->permission(
					rargs.args.i_permission.inode,
					rargs.args.i_permission.mask);
		else
			rargs.rv.rv_int = generic_permission(inode, submask);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

#endif

static int rfs_setattr_default(struct dentry *dentry, struct iattr *iattr)
{
	struct inode *inode = dentry->d_inode;
	int rv;

	rv = inode_change_ok(inode, iattr);
	if (rv)
		return rv;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)
	if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
	    (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid))
		return rfs_dq_transfer(inode, iattr) ? -EDQUOT : 0;
#endif

	return rfs_inode_setattr(inode, iattr);
}

static int rfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(dentry->d_inode);
	rinfo = rfs_inode_get_rinfo(rinode);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_REG_IOP_SETATTR;
	else if (S_ISDIR(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_SETATTR;
	else if (S_ISLNK(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_LNK_IOP_SETATTR;
	else if (S_ISCHR(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_CHR_IOP_SETATTR;
	else if (S_ISBLK(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_BLK_IOP_SETATTR;
	else if (S_ISFIFO(dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_IOP_SETATTR;
	else 
		rargs.type.id = REDIRFS_SOCK_IOP_SETATTR;

	rargs.args.i_setattr.dentry = dentry;
	rargs.args.i_setattr.iattr = iattr;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->op_old && rinode->op_old->setattr)
			rargs.rv.rv_int = rinode->op_old->setattr(
					rargs.args.i_setattr.dentry,
					rargs.args.i_setattr.iattr);
		else 
			rargs.rv.rv_int = rfs_setattr_default(dentry, iattr);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_precall_flts_rename(struct rfs_info *rinfo,
		struct rfs_context *rcont, struct redirfs_args *rargs)
{
	struct redirfs_filter_operations *ops;
	enum redirfs_rv (*rop)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv rv;

	if (!rinfo)
		return 0;

	if (!rinfo->rchain)
		return 0;

	rargs->type.call = REDIRFS_PRECALL;

	rcont->idx = rcont->idx_start;

	for (; rcont->idx < rinfo->rchain->rflts_nr; rcont->idx++) {
		if (!atomic_read(&rinfo->rchain->rflts[rcont->idx]->active))
			continue;

		ops = rinfo->rchain->rflts[rcont->idx]->ops;
		if (!ops)
			continue;
		rop = ops->pre_rename;
		if (!rop)
			continue;

		rv = rop(rcont, rargs);
		if (rv == REDIRFS_STOP)
			return -1;
	}

	rcont->idx--;

	return 0;
}

static void rfs_postcall_flts_rename(struct rfs_info *rinfo,
		struct rfs_context *rcont, struct redirfs_args *rargs)
{
	struct redirfs_filter_operations *ops;
	enum redirfs_rv (*rop)(redirfs_context, struct redirfs_args *);

	if (!rinfo)
		return;

	if (!rinfo->rchain)
		return;

	rargs->type.call = REDIRFS_POSTCALL;

	for (; rcont->idx >= rcont->idx_start; rcont->idx--) {
		if (!atomic_read(&rinfo->rchain->rflts[rcont->idx]->active))
			continue;

		ops = rinfo->rchain->rflts[rcont->idx]->ops;
		if (!ops)
			continue;
		rop = ops->post_rename;
		if (rop) 
			rop(rcont, rargs);
	}

	rcont->idx++;
}

int rfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
	struct rfs_inode *rinode_old;
	struct rfs_inode *rinode_new;
	struct rfs_info *rinfo_old;
	struct rfs_info *rinfo_new;
	struct rfs_context rcont_old;
	struct rfs_context rcont_new;
	struct redirfs_args rargs;

	rfs_context_init(&rcont_old, 0);
	rinode_old = rfs_inode_find(old_dir);
	rinfo_old = rfs_inode_get_rinfo(rinode_old);

	rfs_context_init(&rcont_new, 0);
	rinode_new = rfs_inode_find(new_dir);

	if (rinode_new)
		rinfo_new = rfs_inode_get_rinfo(rinode_new);
	else
		rinfo_new = NULL;

	if (S_ISDIR(old_dir->i_mode))
		rargs.type.id = REDIRFS_DIR_IOP_RENAME;
	else
		BUG();

	rargs.args.i_rename.old_dir = old_dir;
	rargs.args.i_rename.old_dentry = old_dentry;
	rargs.args.i_rename.new_dir = new_dir;
	rargs.args.i_rename.new_dentry = new_dentry;

	if (rfs_precall_flts(rinfo_old->rchain, &rcont_old, &rargs))
		goto skip;

	if (rfs_precall_flts_rename(rinfo_new, &rcont_new, &rargs))
		goto skip;

	if (rinode_old->op_old && rinode_old->op_old->rename)
		rargs.rv.rv_int = rinode_old->op_old->rename(
				rargs.args.i_rename.old_dir,
				rargs.args.i_rename.old_dentry,
				rargs.args.i_rename.new_dir,
				rargs.args.i_rename.new_dentry);
	else
		rargs.rv.rv_int = -ENOSYS;
	
skip:
	if (!rargs.rv.rv_int)
		rargs.rv.rv_int = rfs_fsrename(
				rargs.args.i_rename.old_dir,
				rargs.args.i_rename.old_dentry,
				rargs.args.i_rename.new_dir,
				rargs.args.i_rename.new_dentry);

	rfs_postcall_flts_rename(rinfo_new, &rcont_new, &rargs);
	rfs_postcall_flts(rinfo_old->rchain, &rcont_old, &rargs);

	rfs_context_deinit(&rcont_old);
	rfs_context_deinit(&rcont_new);
	rfs_inode_put(rinode_old);
	rfs_inode_put(rinode_new);
	rfs_info_put(rinfo_old);
	rfs_info_put(rinfo_new);
	return rargs.rv.rv_int;
}


static void rfs_inode_set_ops_reg(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_REG_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_REG_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_dir(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_UNLINK, unlink);
	RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_RMDIR, rmdir);
	RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_SETATTR, setattr);

	RFS_SET_IOP_MGT(rinode, create);
	RFS_SET_IOP_MGT(rinode, link);
	RFS_SET_IOP_MGT(rinode, mknod);
	RFS_SET_IOP_MGT(rinode, symlink);

	rinode->op_new.lookup = rfs_lookup;
	rinode->op_new.mkdir = rfs_mkdir;
}

static void rfs_inode_set_ops_lnk(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_LNK_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_LNK_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_chr(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_CHR_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_CHR_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_blk(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_BLK_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_BLK_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_fifo(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_FIFO_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_FIFO_IOP_SETATTR, setattr);
}

static void rfs_inode_set_ops_sock(struct rfs_inode *rinode)
{
	RFS_SET_IOP(rinode, REDIRFS_SOCK_IOP_PERMISSION, permission);
	RFS_SET_IOP(rinode, REDIRFS_SOCK_IOP_SETATTR, setattr);
}

static void rfs_inode_set_aops_reg(struct rfs_inode *rinode)
{
}

void rfs_inode_set_ops(struct rfs_inode *rinode)
{
	umode_t mode = rinode->inode->i_mode;

	spin_lock(&rinode->lock);

	if (S_ISREG(mode)) {
		rfs_inode_set_ops_reg(rinode);
		rfs_inode_set_aops_reg(rinode);

	} else if (S_ISDIR(mode))
		rfs_inode_set_ops_dir(rinode);

	else if (S_ISLNK(mode))
		rfs_inode_set_ops_lnk(rinode);

	else if (S_ISCHR(mode))
		rfs_inode_set_ops_chr(rinode);

	else if (S_ISBLK(mode))
		rfs_inode_set_ops_blk(rinode);

	else if (S_ISFIFO(mode))
		rfs_inode_set_ops_fifo(rinode);

	else if (S_ISSOCK(mode))
		rfs_inode_set_ops_sock(rinode);

	spin_unlock(&rinode->lock);
}

driver/redirfs/.svn/text-base/rfs_info.c.svn-base0000644000076400007640000002136512112622747021622 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static int rfs_info_add_ops(struct rfs_info *rinfo, struct rfs_chain *rchain)
{
	struct rfs_ops *rops;

	if (!rchain) {
		rinfo->rops = NULL;
		return 0;
	}

	rops = rfs_ops_alloc();
	if (IS_ERR(rops))
		return PTR_ERR(rops);

	rfs_chain_ops(rchain, rops);
	rinfo->rops = rops;

	return 0;
}

struct rfs_info *rfs_info_alloc(struct rfs_root *rroot,
		struct rfs_chain *rchain)
{
	struct rfs_info *rinfo;
	int rv;

	rinfo = kzalloc(sizeof(struct rfs_info), GFP_KERNEL);
	if (!rinfo)
		return ERR_PTR(-ENOMEM);

	rv = rfs_info_add_ops(rinfo, rchain);
	if (rv) {
		kfree(rinfo);
		return ERR_PTR(rv);
	}

	rinfo->rchain = rfs_chain_get(rchain);
	rinfo->rroot = rfs_root_get(rroot);
	atomic_set(&rinfo->count, 1);

	return rinfo;
}

struct rfs_info *rfs_info_get(struct rfs_info *rinfo)
{
	if (!rinfo || IS_ERR(rinfo))
		return NULL;

	BUG_ON(!atomic_read(&rinfo->count));
	atomic_inc(&rinfo->count);

	return rinfo;
}

void rfs_info_put(struct rfs_info *rinfo)
{
	if (!rinfo || IS_ERR(rinfo))
		return;

	BUG_ON(!atomic_read(&rinfo->count));
	if (!atomic_dec_and_test(&rinfo->count))
		return;

	rfs_chain_put(rinfo->rchain);
	rfs_ops_put(rinfo->rops);
	rfs_root_put(rinfo->rroot);
	kfree(rinfo);
}

static struct rfs_info *rfs_info_dentry(struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	rinfo = rfs_info_get(rdentry->rinfo);

	rfs_dentry_put(rdentry);

	return rinfo;
}

struct rfs_info *rfs_info_parent(struct dentry *dentry)
{
	struct dentry *dparent = NULL;
	struct rfs_info *rinfo = NULL;

	dparent = dget_parent(dentry);
	if (dparent != dentry)
		rinfo = rfs_info_dentry(dparent);
	dput(dparent);

	return rinfo;
}

static int rfs_info_rdentry_add(struct rfs_info *rinfo)
{
	struct rfs_dentry *rdentry;

	rdentry = rfs_dentry_add(rinfo->rroot->dentry, rinfo);
	if (IS_ERR(rdentry))
		return PTR_ERR(rdentry);

	rfs_dentry_set_rinfo(rdentry, rinfo);
	rfs_dentry_put(rdentry);
	return 0;
}

static void rfs_info_rdentry_rem(struct dentry *dentry)
{
	struct rfs_dentry *rdentry;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return;

	spin_lock(&rdentry->lock);
	rfs_info_put(rdentry->rinfo);
	rdentry->rinfo = rfs_info_get(rfs_info_none);
	spin_unlock(&rdentry->lock);

	rfs_dentry_put(rdentry);
}

int rfs_info_add(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt)
{
	struct rfs_dcache_data *rdata = NULL;
	int rv = 0;

	rdata = rfs_dcache_data_alloc(dentry, rinfo, rflt);
	if (IS_ERR(rdata))
		return PTR_ERR(rdata);

	rv = rfs_dcache_walk(dentry, rfs_dcache_add, rdata);
	rfs_dcache_data_free(rdata);

	if (!rv)
		rv = rfs_root_walk(rfs_root_add_flt, rflt);

	return rv;
}

int rfs_info_rem(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt)
{
	struct rfs_dcache_data *rdata = NULL;
	int rv = 0;

	rdata = rfs_dcache_data_alloc(dentry, rinfo, rflt);
	if (IS_ERR(rdata))
		return PTR_ERR(rdata);

	rv = rfs_dcache_walk(dentry, rfs_dcache_rem, rdata);
	rfs_dcache_data_free(rdata);

	if (!rv)
		rv = rfs_root_walk(rfs_root_rem_flt, rflt);

	return rv;
}

int rfs_info_set(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt)
{
	struct rfs_dcache_data *rdata = NULL;
	int rv = 0;

	rdata = rfs_dcache_data_alloc(dentry, rinfo, rflt);
	if (IS_ERR(rdata))
		return PTR_ERR(rdata);

	if (rflt->ops && rflt->ops->move_begin)
		rflt->ops->move_begin();

	rv = rfs_dcache_walk(dentry, rfs_dcache_set, rdata);

	if (rflt->ops && rflt->ops->move_end)
		rflt->ops->move_end();

	rfs_dcache_data_free(rdata);

	return rv;
}

int rfs_info_reset(struct dentry *dentry, struct rfs_info *rinfo)
{
	struct rfs_dcache_data *rdata = NULL;
	int rv = 0;

	rdata = rfs_dcache_data_alloc(dentry, rinfo, NULL);
	if (IS_ERR(rdata))
		return PTR_ERR(rdata);

	rv = rfs_dcache_walk(dentry, rfs_dcache_reset, rdata);
	rfs_dcache_data_free(rdata);

	return rv;
}

int rfs_info_add_include(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_info *rinfo = NULL;
	struct rfs_info *rinfo_old = NULL;
	struct rfs_chain *rchain = NULL;
	int rv = 0;

	if (rroot->rinfo && rfs_chain_find(rroot->rinfo->rchain, rflt) != -1)
		return 0;

	rinfo_old = rfs_info_get(rroot->rinfo);
	if (!rinfo_old)
		rinfo_old = rfs_info_dentry(rroot->dentry);

	if (rinfo_old) 
		rchain = rfs_chain_add(rinfo_old->rchain, rflt);
	else
		rchain = rfs_chain_add(NULL, rflt);

	if (IS_ERR(rchain)) {
		rv = PTR_ERR(rchain);
		goto exit;
	}

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	if (rinfo_old && rfs_chain_find(rinfo_old->rchain, rflt) != -1)
		rv = rfs_info_set(rroot->dentry, rinfo, rflt);
	else
		rv = rfs_info_add(rroot->dentry, rinfo, rflt);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_info_put(rinfo_old);
	rfs_info_put(rinfo);
	rfs_chain_put(rchain);
	return rv;
}

int rfs_info_add_exclude(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_info *rinfo = NULL;
	struct rfs_info *rinfo_old = NULL;
	struct rfs_chain *rchain = NULL;
	int rv = 0;

	if (rroot->rinfo && rfs_chain_find(rroot->rinfo->rchain, rflt) == -1)
		return 0;

	rinfo_old = rfs_info_get(rroot->rinfo);
	if (!rinfo_old)
		rinfo_old = rfs_info_dentry(rroot->dentry);

	if (rinfo_old) 
		rchain = rfs_chain_rem(rinfo_old->rchain, rflt);

	if (IS_ERR(rchain)) {
		rv = PTR_ERR(rchain);
		goto exit;
	}

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	if (rinfo_old) {
		if (rfs_chain_find(rinfo_old->rchain, rflt) == -1)
			rv = rfs_info_set(rroot->dentry, rinfo, rflt);
		else
			rv = rfs_info_rem(rroot->dentry, rinfo, rflt);
	} else
		rv = rfs_info_rdentry_add(rinfo);

	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_info_put(rinfo);
	rfs_info_put(rinfo_old);
	rfs_chain_put(rchain);
	return rv;
}

int rfs_info_rem_include(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_info *prinfo = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_chain *rchain = NULL;
	int rv = 0;

	rchain = rfs_chain_rem(rroot->rinfo->rchain, rflt);
	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	prinfo = rfs_info_parent(rroot->dentry);

	if (rroot->rinch->rflts_nr == 1 && !rroot->rexch) {
		if (prinfo && rfs_chain_find(prinfo->rchain, rflt) != -1)
			rv = rfs_info_set(rroot->dentry, prinfo, rflt);
		else if (prinfo && prinfo->rchain)
			rv = rfs_info_rem(rroot->dentry, prinfo, rflt);
		else
			rv = rfs_info_rem(rroot->dentry, rinfo, rflt);

		if (!rv)
			rfs_root_set_rinfo(rroot, NULL);

		goto exit;
	}

	if (prinfo && rfs_chain_find(prinfo->rchain, rflt) != -1)
		goto exit;

	rv = rfs_info_rem(rroot->dentry, rinfo, rflt);
	if (rv)
		goto exit;

	rv = rfs_info_rdentry_add(rinfo);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_info_put(prinfo);
	rfs_info_put(rinfo);
	rfs_chain_put(rchain);
	return rv;
}

int rfs_info_rem_exclude(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_info *prinfo = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_chain *rchain = NULL;
	int rv = 0;

	prinfo = rfs_info_parent(rroot->dentry);

	if (rroot->rexch->rflts_nr == 1 && !rroot->rinch) {
		if (prinfo && rfs_chain_find(prinfo->rchain, rflt) != -1)
			rv = rfs_info_add(rroot->dentry, prinfo, rflt);
		else if (prinfo && prinfo->rchain)
			rv = rfs_info_set(rroot->dentry, prinfo, rflt);
		else  
			rfs_info_rdentry_rem(rroot->dentry);

		if (!rv)
			rfs_root_set_rinfo(rroot, NULL);

		goto exit;
	}

	if (!prinfo || rfs_chain_find(prinfo->rchain, rflt) == -1)
		goto exit;

	rchain = rfs_chain_add(rroot->rinfo->rchain, rflt);
	if (IS_ERR(rchain)) {
		rv = PTR_ERR(rchain);
		goto exit;
	}

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	rv = rfs_info_add(rroot->dentry, rinfo, rflt);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_info_put(prinfo);
	rfs_info_put(rinfo);
	rfs_chain_put(rchain);
	return rv;
}

driver/redirfs/.svn/text-base/rfs_data.c.svn-base0000644000076400007640000002424612112622747021601 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

void rfs_data_remove(struct list_head *head)
{
	struct redirfs_data *data;
	struct redirfs_data *tmp;

	list_for_each_entry_safe(data, tmp, head, list) {
		list_del_init(&data->list);
		if (data->detach)
			data->detach(data);
		redirfs_put_data(data);
	}
}

int redirfs_init_data(struct redirfs_data *data, redirfs_filter filter,
		void (*free)(struct redirfs_data *),
		void (*detach)(struct redirfs_data *))
{
	if (!data || !filter || IS_ERR(filter) || !free)
		return -EINVAL;

	INIT_LIST_HEAD(&data->list);
	atomic_set(&data->cnt, 1);
	data->free = free;
	data->detach = detach;
	data->filter = rfs_flt_get(filter);

	return 0;
}

struct redirfs_data *redirfs_get_data(struct redirfs_data *data)
{
	if (!data || IS_ERR(data))
		return NULL;
	
	BUG_ON(!atomic_read(&data->cnt));

	atomic_inc(&data->cnt);

	return data;
}

void redirfs_put_data(struct redirfs_data *data)
{
	if (!data || IS_ERR(data))
		return;

	BUG_ON(!atomic_read(&data->cnt));
	
	if (!atomic_dec_and_test(&data->cnt))
		return;

	rfs_flt_put(data->filter);
	data->free(data);
}

static struct redirfs_data *rfs_find_data(struct list_head *head,
		redirfs_filter filter)
{
	struct redirfs_data *data;

	list_for_each_entry(data, head, list) {
		if (data->filter == filter)
			return redirfs_get_data(data);
	}

	return NULL;
}

struct redirfs_data *redirfs_attach_data_file(redirfs_filter filter,
		struct file *file, struct redirfs_data *data)
{
	struct rfs_file *rfile;
	struct redirfs_data *rv = NULL;

	if (!filter || IS_ERR(filter) || !file || !data)
		return NULL;

	rfile = rfs_file_find(file);
	if (!rfile)
		return NULL;

	spin_lock(&rfile->rdentry->lock);
	spin_lock(&rfile->lock);

	if (rfs_chain_find(rfile->rdentry->rinfo->rchain, filter) == -1)
		goto exit;

	rv = rfs_find_data(&rfile->data, filter);
	if (rv)
		goto exit;

	list_add_tail(&data->list, &rfile->data); 
	redirfs_get_data(data);
	rv = redirfs_get_data(data);
exit:
	spin_unlock(&rfile->lock);
	spin_unlock(&rfile->rdentry->lock);
	rfs_file_put(rfile);
	return rv;
}

struct redirfs_data *redirfs_detach_data_file(redirfs_filter filter,
		struct file *file)
{
	struct rfs_file *rfile;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !file)
		return NULL;

	rfile = rfs_file_find(file);
	if (!rfile)
		return NULL;

	spin_lock(&rfile->lock);

	data = rfs_find_data(&rfile->data, filter);
	if (data)
		list_del(&data->list);

	spin_unlock(&rfile->lock);
	redirfs_put_data(data);
	rfs_file_put(rfile);
	return data;
}

struct redirfs_data *redirfs_get_data_file(redirfs_filter filter,
		struct file *file)
{
	struct rfs_file *rfile;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !file)
		return NULL;

	rfile = rfs_file_find(file);
	if (!rfile)
		return NULL;

	spin_lock(&rfile->lock);

	data = rfs_find_data(&rfile->data, filter);

	spin_unlock(&rfile->lock);
	rfs_file_put(rfile);
	return data;
}

struct redirfs_data *redirfs_attach_data_dentry(redirfs_filter filter,
		struct dentry *dentry, struct redirfs_data *data)
{
	struct rfs_dentry *rdentry;
	struct redirfs_data *rv = NULL;

	if (!filter || IS_ERR(filter) || !dentry || !data)
		return NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	spin_lock(&rdentry->lock);

	if (rfs_chain_find(rdentry->rinfo->rchain, filter) == -1)
		goto exit;

	rv = rfs_find_data(&rdentry->data, filter);
	if (rv)
		goto exit;

	list_add_tail(&data->list, &rdentry->data); 
	redirfs_get_data(data);
	rv = redirfs_get_data(data);
exit:
	spin_unlock(&rdentry->lock);
	rfs_dentry_put(rdentry);
	return rv;
}

struct redirfs_data *redirfs_detach_data_dentry(redirfs_filter filter,
		struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !dentry)
		return NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	spin_lock(&rdentry->lock);

	data = rfs_find_data(&rdentry->data, filter);
	if (data)
		list_del(&data->list);

	spin_unlock(&rdentry->lock);
	redirfs_put_data(data);
	rfs_dentry_put(rdentry);
	return data;
}

struct redirfs_data *redirfs_get_data_dentry(redirfs_filter filter,
		struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !dentry)
		return NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	spin_lock(&rdentry->lock);

	data = rfs_find_data(&rdentry->data, filter);

	spin_unlock(&rdentry->lock);
	rfs_dentry_put(rdentry);
	return data;
}

struct redirfs_data *redirfs_attach_data_inode(redirfs_filter filter,
		struct inode *inode, struct redirfs_data *data)
{
	struct rfs_inode *rinode;
	struct redirfs_data *rv = NULL;

	if (!filter || IS_ERR(filter) || !inode || !data)
		return NULL;

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return NULL;

	spin_lock(&rinode->lock);

	if (rfs_chain_find(rinode->rinfo->rchain, filter) == -1)
		goto exit;

	rv = rfs_find_data(&rinode->data, filter);
	if (rv)
		goto exit;

	list_add_tail(&data->list, &rinode->data); 
	redirfs_get_data(data);
	rv = redirfs_get_data(data);
exit:
	spin_unlock(&rinode->lock);
	rfs_inode_put(rinode);
	return rv;
}

struct redirfs_data *redirfs_detach_data_inode(redirfs_filter filter,
		struct inode *inode)
{
	struct rfs_inode *rinode;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !inode)
		return NULL;

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return NULL;

	spin_lock(&rinode->lock);

	data = rfs_find_data(&rinode->data, filter);
	if (data)
		list_del(&data->list);

	spin_unlock(&rinode->lock);
	redirfs_put_data(data);
	rfs_inode_put(rinode);
	return data;
}

struct redirfs_data *redirfs_get_data_inode(redirfs_filter filter,
		struct inode *inode)
{
	struct rfs_inode *rinode;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !inode)
		return NULL;

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return NULL;

	spin_lock(&rinode->lock);

	data = rfs_find_data(&rinode->data, filter);

	spin_unlock(&rinode->lock);
	rfs_inode_put(rinode);
	return data;
}

void rfs_context_init(struct rfs_context *rcont, int start)
{
	INIT_LIST_HEAD(&rcont->data);
	rcont->idx_start = start;
	rcont->idx = 0;
}

void rfs_context_deinit(struct rfs_context *rcont)
{
	rfs_data_remove(&rcont->data);
}

struct redirfs_data *redirfs_attach_data_context(redirfs_filter filter,
		redirfs_context context, struct redirfs_data *data)
{
	struct rfs_context *rcont = (struct rfs_context *)context;
	struct redirfs_data *rv;

	if (!filter || IS_ERR(filter) || !context || !data)
		return NULL;

	rv = rfs_find_data(&rcont->data, filter);
	if (rv)
		return rv;

	list_add_tail(&data->list, &rcont->data); 
	redirfs_get_data(data);

	return redirfs_get_data(data);
}

struct redirfs_data *redirfs_detach_data_context(redirfs_filter filter,
		redirfs_context context)
{
	struct rfs_context *rcont = (struct rfs_context *)context;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !context)
		return NULL;

	data = rfs_find_data(&rcont->data, filter);
	if (data)
		list_del(&data->list);

	redirfs_put_data(data);
	return data;
}

struct redirfs_data *redirfs_get_data_context(redirfs_filter filter,
		redirfs_context context)
{
	struct rfs_context *rcont = (struct rfs_context *)context;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter)|| !context)
		return NULL;

	data = rfs_find_data(&rcont->data, filter);

	return data;
}

struct redirfs_data *redirfs_attach_data_root(redirfs_filter filter,
		redirfs_root root, struct redirfs_data *data)
{
	struct rfs_root *rroot = (struct rfs_root *)root;
	struct redirfs_data *rv = NULL;
	int found = 0;

	if (!filter || IS_ERR(filter) || !root || !data)
		return NULL;

	spin_lock(&rroot->lock);

	if (rfs_chain_find(rroot->rinch, filter) != -1)
		found = 1;

	else if (rfs_chain_find(rroot->rexch, filter) != -1)
		found = 1;

	if (!found)
		goto exit;

	rv = rfs_find_data(&rroot->data, filter);
	if (rv)
		goto exit;

	list_add_tail(&data->list, &rroot->data); 
	redirfs_get_data(data);
	rv = redirfs_get_data(data);
exit:
	spin_unlock(&rroot->lock);
	return rv;
}

struct redirfs_data *redirfs_detach_data_root(redirfs_filter filter,
		redirfs_root root)
{
	struct rfs_root *rroot = (struct rfs_root *)root;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !root)
		return NULL;

	spin_lock(&rroot->lock);

	data = rfs_find_data(&rroot->data, filter);
	if (data)
		list_del(&data->list);

	spin_unlock(&rroot->lock);
	redirfs_put_data(data);

	return data;
}

struct redirfs_data *redirfs_get_data_root(redirfs_filter filter,
		redirfs_root root)
{
	struct rfs_root *rroot = (struct rfs_root *)root;
	struct redirfs_data *data;

	if (!filter || IS_ERR(filter) || !root)
		return NULL;

	spin_lock(&rroot->lock);

	data = rfs_find_data(&rroot->data, filter);

	spin_unlock(&rroot->lock);

	return data;
}

EXPORT_SYMBOL(redirfs_init_data);
EXPORT_SYMBOL(redirfs_get_data);
EXPORT_SYMBOL(redirfs_put_data);
EXPORT_SYMBOL(redirfs_attach_data_file);
EXPORT_SYMBOL(redirfs_detach_data_file);
EXPORT_SYMBOL(redirfs_get_data_file);
EXPORT_SYMBOL(redirfs_attach_data_dentry);
EXPORT_SYMBOL(redirfs_detach_data_dentry);
EXPORT_SYMBOL(redirfs_get_data_dentry);
EXPORT_SYMBOL(redirfs_attach_data_inode);
EXPORT_SYMBOL(redirfs_detach_data_inode);
EXPORT_SYMBOL(redirfs_get_data_inode);
EXPORT_SYMBOL(redirfs_attach_data_context);
EXPORT_SYMBOL(redirfs_detach_data_context);
EXPORT_SYMBOL(redirfs_get_data_context);
EXPORT_SYMBOL(redirfs_attach_data_root);
EXPORT_SYMBOL(redirfs_detach_data_root);
EXPORT_SYMBOL(redirfs_get_data_root);

driver/redirfs/.svn/text-base/COPYING.svn-base0000644000076400007640000010451312112622747020701 0ustar  comodocomodo                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
driver/redirfs/.svn/text-base/rfs_dcache.c.svn-base0000644000076400007640000002163312112622747022074 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

struct rfs_dcache_data *rfs_dcache_data_alloc(struct dentry *dentry,
		struct rfs_info *rinfo, struct rfs_flt *rflt)
{
	struct rfs_dcache_data *rdata;

	rdata = kzalloc(sizeof(struct rfs_dcache_data), GFP_KERNEL);
	if (!rdata)
		return ERR_PTR(-ENOMEM);

	rdata->rinfo = rinfo;
	rdata->rflt = rflt;
	rdata->droot = dentry;

	return rdata;
}

void rfs_dcache_data_free(struct rfs_dcache_data *rdata)
{
	if (!rdata || IS_ERR(rdata))
		return;

	kfree(rdata);
}

static struct rfs_dcache_entry *rfs_dcache_entry_alloc_locked(
		struct dentry *dentry, struct list_head *list)
{
	struct rfs_dcache_entry *entry;

	entry = kzalloc(sizeof(struct rfs_dcache_entry), GFP_ATOMIC);
	if (!entry)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&entry->list);
	entry->dentry = rfs_dget_locked(dentry);
	list_add_tail(&entry->list, list);

	return entry;
}

static struct rfs_dcache_entry *rfs_dcache_entry_alloc(struct dentry *dentry,
		struct list_head *list)
{
	struct rfs_dcache_entry *entry;

	entry = kzalloc(sizeof(struct rfs_dcache_entry), GFP_KERNEL);
	if (!entry)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&entry->list);
	entry->dentry = dget(dentry);
	list_add_tail(&entry->list, list);

	return entry;
}

static void rfs_dcache_entry_free(struct rfs_dcache_entry *entry)
{
	if (!entry)
		return;

	list_del_init(&entry->list);
	dput(entry->dentry);
	kfree(entry);
}

static int rfs_dcache_get_subs_atomic(struct dentry *dir,
		struct list_head *sibs)
{
	struct rfs_dcache_entry *sib;
	struct dentry *dentry;
	int rv = 0;

	rfs_dcache_lock(dir);

	rfs_for_each_d_child(dentry, &dir->d_subdirs) {

		sib = rfs_dcache_entry_alloc_locked(dentry, sibs);
		if (IS_ERR(sib)) {
			rv = PTR_ERR(sib);
			break;
		}
	}

	rfs_dcache_unlock(dir);

	return rv;
}

static int rfs_dcache_get_subs_kernel(struct dentry *dir,
		struct list_head *sibs)
{
	LIST_HEAD(pool);
	int pool_size = 32;
	int pool_small;
	struct rfs_dcache_entry *sib;
	struct dentry *dentry;
	int i;

again:
	pool_small = 0;

	for (i = 0; i < pool_size; i++) {
		sib = rfs_dcache_entry_alloc(NULL, &pool);
		if (IS_ERR(sib)) {
			rfs_dcache_entry_free_list(&pool);
			return PTR_ERR(sib);
		}
	}

	rfs_dcache_lock(dir);

	rfs_for_each_d_child(dentry, &dir->d_subdirs) {
		if (list_empty(&pool)) {
			pool_small = 1;
			break;
		}
		
		sib = list_entry(pool.next, struct rfs_dcache_entry, list);
		sib->dentry = rfs_dget_locked(dentry);
		list_move(&sib->list, sibs);
	}

	rfs_dcache_unlock(dir);

	rfs_dcache_entry_free_list(&pool);

	if (pool_small) {
		rfs_dcache_entry_free_list(sibs);
		pool_size *= 2;
		goto again;
	}

	return 0;
}

int rfs_dcache_get_subs(struct dentry *dir, struct list_head *sibs)
{
	int rv;

	rv = rfs_dcache_get_subs_atomic(dir, sibs);
	if (!rv)
		return rv;

	rfs_dcache_entry_free_list(sibs);
	
	rv = rfs_dcache_get_subs_kernel(dir, sibs);

	return rv;
}

void rfs_dcache_entry_free_list(struct list_head *head)
{
	struct rfs_dcache_entry *entry;
	struct rfs_dcache_entry *tmp;

	list_for_each_entry_safe(entry, tmp, head, list) {
		rfs_dcache_entry_free(entry);
	}
}

static int rfs_dcache_get_subs_mutex(struct dentry *dir, struct list_head *sibs)
{
	int rv = 0;

	if (!dir || !dir->d_inode)
		return 0;

	rfs_inode_mutex_lock(dir->d_inode);
	rv = rfs_dcache_get_subs(dir, sibs);
	rfs_inode_mutex_unlock(dir->d_inode);

	return rv;
}

static int rfs_dcache_get_dirs(struct list_head *dirs, struct list_head *sibs)
{
	struct rfs_dcache_entry *entry;
	struct rfs_dcache_entry *dir;
	struct rfs_dcache_entry *tmp;

	list_for_each_entry_safe(entry, tmp, sibs, list) {
		if (!entry->dentry->d_inode)
			continue;

		if (!S_ISDIR(entry->dentry->d_inode->i_mode))
			continue;

		dir = rfs_dcache_entry_alloc(entry->dentry, dirs);
		if (IS_ERR(dir))
			return PTR_ERR(dir);

		rfs_dcache_entry_free(entry);
	}

	return 0;
}

int rfs_dcache_walk(struct dentry *root, int (*cb)(struct dentry *, void *),
		void *data)
{
	LIST_HEAD(dirs);
	LIST_HEAD(sibs);
	struct rfs_dcache_entry *dir;
	struct rfs_dcache_entry *sib;
	int rv = 0;

	dir = rfs_dcache_entry_alloc(root, &dirs);
	if (IS_ERR(dir))
		return PTR_ERR(dir);

	while (!list_empty(&dirs)) {
		dir = list_entry(dirs.next, struct rfs_dcache_entry, list);

		rv = cb(dir->dentry, data);
		if (rv < 0)
			goto exit;

		if (rv > 0 || !dir->dentry->d_inode) {
			rfs_dcache_entry_free(dir);
			rv = 0;
			continue;
		}

		rv = rfs_dcache_get_subs_mutex(dir->dentry, &sibs);
		if (rv)
			goto exit;

		rv = rfs_dcache_get_dirs(&dirs, &sibs);
		if (rv)
			goto exit;

		list_for_each_entry(sib, &sibs, list) {
			rv = cb(sib->dentry, data);
			if (rv < 0)
				goto exit;
		}
		rfs_dcache_entry_free_list(&sibs);
		rfs_dcache_entry_free(dir);
	}
exit:
	list_splice(&sibs, &dirs);
	rfs_dcache_entry_free_list(&dirs);

	return rv;
}

static int rfs_dcache_skip(struct dentry *dentry, struct rfs_dcache_data *rdata)
{
	struct rfs_dentry *rdentry = NULL;
	int rv = 0;

	if (dentry == rdata->droot)
		return 0;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return 0;

	if (!rdentry->rinfo)
		goto exit;

	if (!rdentry->rinfo->rroot)
		goto exit;

	if (rdentry->rinfo->rroot->dentry != dentry)
		goto exit;

	rv = 1;
exit:
	rfs_dentry_put(rdentry);
	return rv;
}

int rfs_dcache_rdentry_add(struct dentry *dentry, struct rfs_info *rinfo)
{
	struct rfs_dentry *rdentry = NULL;
	int rv = 0;

	rdentry = rfs_dentry_add(dentry, rinfo);
	if (IS_ERR(rdentry))
		return PTR_ERR(rdentry);

	rfs_dentry_set_rinfo(rdentry, rinfo);

	rv = rfs_dentry_add_rinode(rdentry, rinfo);
	if (rv)
		goto exit;

	rv = rfs_inode_set_rinfo(rdentry->rinode);
	if (rv)
		goto exit;

	rfs_dentry_set_ops(rdentry);
exit:
	rfs_dentry_put(rdentry);
	return rv;
}

int rfs_dcache_rinode_del(struct rfs_dentry *rdentry, struct inode *inode)
{
	struct rfs_inode *rinode = NULL;
	int rv = 0;

	rfs_dentry_rem_rinode(rdentry);

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return 0;

	rv = rfs_inode_set_rinfo(rinode);
	if (rv) {
		rfs_inode_put(rinode);
		return rv;
	}

	rfs_inode_set_ops(rinode);
	rfs_inode_put(rinode);

	return 0;
}

static int rfs_dcache_rdentry_del(struct dentry *dentry, struct rfs_info *rinfo)
{
	struct rfs_dentry *rdentry = NULL;
	int rv = 0;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return 0;

	rfs_dentry_set_rinfo(rdentry, rinfo);
	rv = rfs_inode_set_rinfo(rdentry->rinode);
	if (rv)
		goto exit;

	rfs_dentry_set_ops(rdentry);
exit:
	rfs_dentry_put(rdentry);
	return rv;
}

int rfs_dcache_add_dir(struct dentry *dentry, void *data)
{
	if (!dentry->d_inode)
		return 0;

	if (!S_ISDIR(dentry->d_inode->i_mode))
		return 0;

	return rfs_dcache_rdentry_add(dentry, rfs_info_none);
}

int rfs_dcache_add(struct dentry *dentry, void *data)
{
	struct rfs_dcache_data *rdata = data;

	if (rfs_dcache_skip(dentry, rdata)) {
		rfs_root_add_walk(dentry);
		return 1;
	}

	return rfs_dcache_rdentry_add(dentry, rdata->rinfo);
}

int rfs_dcache_rem(struct dentry *dentry, void *data)
{
	struct rfs_dcache_data *rdata = data;
	int rv;

	if (rfs_dcache_skip(dentry, rdata)) {
		rfs_root_add_walk(dentry);
		return 1;
	}

	if (rdata->rinfo->rchain)
		return rfs_dcache_rdentry_add(dentry, rdata->rinfo);

	rv = rfs_dcache_rdentry_del(dentry, rfs_info_none);
	if (rv)
		return rv;

	rfs_dentry_rem_data(dentry, rdata->rflt);
	return 0;
}

int rfs_dcache_set(struct dentry *dentry, void *data)
{
	struct rfs_dcache_data *rdata = data;
	struct rfs_dentry *rdentry = NULL;
	struct rfs_root *rroot = NULL;
	int rv = 0;

	if (rfs_dcache_skip(dentry, rdata))
		return 1;

	if (!rdata->rinfo->rchain)
		return rfs_dcache_rdentry_del(dentry, rfs_info_none);

	rdentry = rfs_dentry_find(dentry);
	if (rdentry)
		rroot = rfs_root_get(rdentry->rinfo->rroot);

	rv = rfs_dcache_rdentry_add(dentry, rdata->rinfo);
	if (rv)
		goto exit;

	if (!rroot)
		goto exit;

	if (rroot == rdata->rinfo->rroot)
		goto exit;

	rv = rfs_dentry_move(dentry, rdata->rflt, rroot, rdata->rinfo->rroot);
exit:
	rfs_dentry_put(rdentry);
	rfs_root_put(rroot);
	return rv;
}

int rfs_dcache_reset(struct dentry *dentry, void *data)
{
	struct rfs_dcache_data *rdata = data;

	if (rfs_dcache_skip(dentry, rdata))
		return 1;

	if (!rdata->rinfo->rchain)
		return rfs_dcache_rdentry_del(dentry, rfs_info_none);

	return rfs_dcache_rdentry_add(dentry, rdata->rinfo);
}

driver/redirfs/.svn/text-base/TODO.svn-base0000644000076400007640000000031712112622747020333 0ustar  comodocomodo		================================
		RedirFS - Redirecting FileSystem
			      TODO 
		================================

* support for address space operations
* allow redirect all operations in VFS objects
driver/redirfs/.svn/text-base/INSTALL.svn-base0000644000076400007640000000204012112622747020667 0ustar  comodocomodo			======================================
				 Installing RedirFS
			======================================

1. Requirements
	
	* Running Linux kernel version 2.6.16 and higher
	* Source code and configuration for running Linux kernel
	  - at least make scripts and make prepare
	* Linux kernel compiled with modules support

2. Download
	
	* Get the latest stable version at
	  http://www.redirfs.org/packages/redirfs-x.y.tar.gz

3. Compilation
	
	* Unpack package
		$ tar -xvzf redirfs-x.y.tar.gz

	* Change to the redirfs-x.y directory
		$ cd redirfs-x.y

	* Run make command
		$ make -C /lib/modules/`uname -r`/build M=`pwd` modules

4. Inserting module

	* Change user to root
		$ su

	* Install module
		# make -C /lib/modules/`uname -r`/build M=`pwd` modules_install

	* Update module dependencies
		# depmod -a

	* Load redirfs.ko module
		# modprobe redirfs

5. Problems & Bugs

	* RedirFS's bugzilla
	  http://www.redirfs.org/cgi-bin/bugzilla/index.cgi
	
	* RedirFS's mailing lists
	  http://www.redirfs.org/tiki-index.php?page=redirfs_maillists
driver/redirfs/.svn/text-base/rfs.h.svn-base0000644000076400007640000004067612112622747020622 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _RFS_H
#define _RFS_H

#include <linux/mount.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
#include "redirfs.h"

#define RFS_ADD_OP(ops_new, op) \
	(ops_new.op = rfs_##op)

#define RFS_REM_OP(ops_new, ops_old, op) \
	(ops_new.op = ops_old ? ops_old->op : NULL)

#define RFS_SET_OP(arr, id, ops_new, ops_old, op) \
	(arr[id] ? \
	 	RFS_ADD_OP(ops_new, op) : \
	 	RFS_REM_OP(ops_new, ops_old, op) \
	)

#define RFS_SET_FOP(rf, id, op) \
	(rf->rdentry->rinfo->rops ? \
		RFS_SET_OP(rf->rdentry->rinfo->rops->arr, id, rf->op_new, \
			rf->op_old, op) : \
	 	RFS_REM_OP(rf->op_new, rf->op_old, op) \
	)

#define RFS_SET_DOP(rd, id, op) \
	(rd->rinfo->rops ? \
		RFS_SET_OP(rd->rinfo->rops->arr, id, rd->op_new,\
			rd->op_old, op) : \
	 	RFS_REM_OP(rd->op_new, rd->op_old, op) \
	)

#define RFS_SET_IOP_MGT(ri, op) \
	(ri->rinfo->rops ? \
	 	RFS_ADD_OP(ri->op_new, op) : \
	 	RFS_REM_OP(ri->op_new, ri->op_old, op) \
	)

#define RFS_SET_IOP(ri, id, op) \
	(ri->rinfo->rops ? \
	 	RFS_SET_OP(ri->rinfo->rops->arr, id, ri->op_new, \
			ri->op_old, op) : \
	 	RFS_REM_OP(ri->op_new, ri->op_old, op) \
	)

struct rfs_file;

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
#define rfs_mutex_t semaphore
#define RFS_DEFINE_MUTEX(mutex) DECLARE_MUTEX(mutex)
#define rfs_mutex_init(mutex) init_MUTEX(mutex)
#define rfs_mutex_lock(mutex) down(mutex)
#define rfs_mutex_unlock(mutex) up(mutex)
#define rfs_for_each_d_child(pos, head) list_for_each_entry(pos, head, d_child)
inline static void rfs_inode_mutex_lock(struct inode *inode)
{
	down(&inode->i_sem);
}
inline static void rfs_inode_mutex_unlock(struct inode *inode)
{
	up(&inode->i_sem);
}
#else
#define rfs_mutex_t mutex
#define RFS_DEFINE_MUTEX(mutex) DEFINE_MUTEX(mutex)
#define rfs_mutex_init(mutex) mutex_init(mutex)
#define rfs_mutex_lock(mutex) mutex_lock(mutex)
#define rfs_mutex_unlock(mutex) mutex_unlock(mutex)
#define rfs_for_each_d_child(pos, head) list_for_each_entry(pos, head, d_u.d_child)
inline static void rfs_inode_mutex_lock(struct inode *inode)
{
	mutex_lock(&inode->i_mutex);
}
inline static void rfs_inode_mutex_unlock(struct inode *inode)
{
	mutex_unlock(&inode->i_mutex);
}
#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
#define rfs_kmem_cache_t kmem_cache_t
#else
#define rfs_kmem_cache_t struct kmem_cache
#endif

struct rfs_op_info {
	enum redirfs_rv (*pre_cb)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv (*post_cb)(redirfs_context, struct redirfs_args *);
};

struct rfs_flt {
	struct list_head list;
	struct rfs_op_info cbs[REDIRFS_OP_END];
	struct module *owner;
	struct kobject kobj;
	char *name;
	int priority;
	int paths_nr;
	spinlock_t lock;
	atomic_t active;
	atomic_t count;
	struct redirfs_filter_operations *ops;
};

void rfs_flt_put(struct rfs_flt *rflt);
struct rfs_flt *rfs_flt_get(struct rfs_flt *rflt);
void rfs_flt_release(struct kobject *kobj);

struct rfs_path {
	struct list_head list;
	struct list_head rfst_list;
	struct list_head rroot_list;
	struct rfs_root *rroot;
	struct rfs_chain *rinch;
	struct rfs_chain *rexch;
	struct vfsmount *mnt;
	struct dentry *dentry;
	atomic_t count;
	int id;
};

extern struct rfs_mutex_t rfs_path_mutex;

struct rfs_path *rfs_path_get(struct rfs_path *rpath);
void rfs_path_put(struct rfs_path *rpath);
struct rfs_path *rfs_path_find_id(int id);
int rfs_path_get_info(struct rfs_flt *rflt, char *buf, int size);
int rfs_fsrename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry);

struct rfs_root {
	struct list_head list;
	struct list_head walk_list;
	struct list_head rpaths;
	struct list_head data;
	struct rfs_chain *rinch;
	struct rfs_chain *rexch;
	struct rfs_info *rinfo;
	struct dentry *dentry;
	int paths_nr;
	spinlock_t lock;
	atomic_t count;
};

extern struct list_head rfs_root_list;
extern struct list_head rfs_root_walk_list;

struct rfs_root *rfs_root_get(struct rfs_root *rroot);
void rfs_root_put(struct rfs_root *rroot);
void rfs_root_add_rpath(struct rfs_root *rroot, struct rfs_path *rpath);
void rfs_root_rem_rpath(struct rfs_root *rroot, struct rfs_path *rpath);
struct rfs_root *rfs_root_add(struct dentry *dentry);
int rfs_root_add_include(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_root_add_exclude(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_root_rem_include(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_root_rem_exclude(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_root_add_flt(struct rfs_root *rroot, void *data);
int rfs_root_rem_flt(struct rfs_root *rroot, void *data);
int rfs_root_walk(int (*cb)(struct rfs_root*, void *), void *data);
void rfs_root_add_walk(struct dentry *dentry);
void rfs_root_set_rinfo(struct rfs_root *rroot, struct rfs_info *rinfo);

struct rfs_ops {
	char *arr;
	atomic_t count;
	int flags;
};

struct rfs_ops *rfs_ops_alloc(void);
struct rfs_ops *rfs_ops_get(struct rfs_ops *rops);
void rfs_ops_put(struct rfs_ops *rops);

struct rfs_chain {
	struct rfs_flt **rflts;
	int rflts_nr;
	atomic_t count;
};

struct rfs_chain *rfs_chain_get(struct rfs_chain *rchain);
void rfs_chain_put(struct rfs_chain *rchain);
int rfs_chain_find(struct rfs_chain *rchain, struct rfs_flt *rflt);
struct rfs_chain *rfs_chain_add(struct rfs_chain *rchain, struct rfs_flt *rflt);
struct rfs_chain *rfs_chain_rem(struct rfs_chain *rchain, struct rfs_flt *rflt);
void rfs_chain_ops(struct rfs_chain *rchain, struct rfs_ops *ops);
int rfs_chain_cmp(struct rfs_chain *rch1, struct rfs_chain *rch2);
struct rfs_chain *rfs_chain_join(struct rfs_chain *rch1,
		struct rfs_chain *rch2);
struct rfs_chain *rfs_chain_diff(struct rfs_chain *rch1,
		struct rfs_chain *rch2);

struct rfs_info {
	struct rfs_chain *rchain;
	struct rfs_ops *rops;
	struct rfs_root *rroot;
	atomic_t count;
};

extern struct rfs_info *rfs_info_none;

struct rfs_info *rfs_info_alloc(struct rfs_root *rroot,
		struct rfs_chain *rchain);
struct rfs_info *rfs_info_get(struct rfs_info *rinfo);
void rfs_info_put(struct rfs_info *rinfo);
struct rfs_info *rfs_info_parent(struct dentry *dentry);
int rfs_info_add_include(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_info_add_exclude(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_info_rem_include(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_info_rem_exclude(struct rfs_root *rroot, struct rfs_flt *rflt);
int rfs_info_add(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt);
int rfs_info_rem(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt);
int rfs_info_set(struct dentry *dentry, struct rfs_info *rinfo,
		struct rfs_flt *rflt);
int rfs_info_reset(struct dentry *dentry, struct rfs_info *rinfo);

struct rfs_dentry {
	struct list_head rinode_list;
	struct list_head rfiles;
	struct list_head data;
	struct dentry *dentry;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
	const struct dentry_operations *op_old;
#else
	struct dentry_operations *op_old;
#endif
	struct dentry_operations op_new;
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	spinlock_t lock;
	atomic_t count;
};

#define rfs_dentry_find(dentry) \
	(dentry && dentry->d_op && dentry->d_op->d_iput == rfs_d_iput ? \
	 rfs_dentry_get(container_of(dentry->d_op, struct rfs_dentry, op_new)) : \
	 NULL)

void rfs_d_iput(struct dentry *dentry, struct inode *inode);
struct rfs_dentry *rfs_dentry_get(struct rfs_dentry *rdentry);
void rfs_dentry_put(struct rfs_dentry *rdentry);
struct rfs_dentry *rfs_dentry_add(struct dentry *dentry,
		struct rfs_info *rinfo);
void rfs_dentry_del(struct rfs_dentry *rdentry);
int rfs_dentry_add_rinode(struct rfs_dentry *rdentry, struct rfs_info *rinfo);
void rfs_dentry_rem_rinode(struct rfs_dentry *rdentry);
struct rfs_info *rfs_dentry_get_rinfo(struct rfs_dentry *rdentry);
void rfs_dentry_set_rinfo(struct rfs_dentry *rdentry, struct rfs_info *rinfo);
void rfs_dentry_add_rfile(struct rfs_dentry *rdentry, struct rfs_file *rfile);
void rfs_dentry_rem_rfile(struct rfs_file *rfile);
void rfs_dentry_rem_rfiles(struct rfs_dentry *rdentry);
void rfs_dentry_set_ops(struct rfs_dentry *dentry);
int rfs_dentry_cache_create(void);
void rfs_dentry_cache_destory(void);
void rfs_dentry_rem_data(struct dentry *dentry, struct rfs_flt *rflt);
int rfs_dentry_move(struct dentry *dentry, struct rfs_flt *rflt,
		struct rfs_root *src, struct rfs_root *dst);

struct rfs_inode {
	struct list_head rdentries; /* mutex */
	struct list_head data;
	struct inode *inode;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17))
	const struct inode_operations *op_old;
	const struct file_operations *fop_old;
#else
	struct inode_operations *op_old;
	struct file_operations *fop_old;
#endif
	struct inode_operations op_new;
	struct rfs_info *rinfo;
	struct rfs_mutex_t mutex;
	spinlock_t lock;
	atomic_t count;
	atomic_t nlink;
	int rdentries_nr; /* mutex */
};

#define rfs_inode_find(inode) \
	(inode && inode->i_op && inode->i_op->rename == rfs_rename ? \
	 rfs_inode_get(container_of(inode->i_op, struct rfs_inode, op_new)) : \
	 NULL)

int rfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry);
struct rfs_inode *rfs_inode_get(struct rfs_inode *rinode);
void rfs_inode_put(struct rfs_inode *rinode);
struct rfs_inode *rfs_inode_add(struct inode *inode, struct rfs_info *rinfo);
void rfs_inode_del(struct rfs_inode *rinode);
void rfs_inode_add_rdentry(struct rfs_inode *rinode,
		struct rfs_dentry *rdentry);
void rfs_inode_rem_rdentry(struct rfs_inode *rinode,
		struct rfs_dentry *rdentry);
struct rfs_info *rfs_inode_get_rinfo(struct rfs_inode *rinode);
int rfs_inode_set_rinfo(struct rfs_inode *rinode);
void rfs_inode_set_ops(struct rfs_inode *rinode);
int rfs_inode_cache_create(void);
void rfs_inode_cache_destroy(void);

struct rfs_file {
	struct list_head rdentry_list;
	struct list_head data;
	struct file *file;
	struct rfs_dentry *rdentry;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17))
	const struct file_operations *op_old;
#else
	struct file_operations *op_old;
#endif
	struct file_operations op_new;
	spinlock_t lock;
	atomic_t count;
};

#define rfs_file_find(file) \
	(file && file->f_op && file->f_op->open == rfs_open ? \
	 rfs_file_get(container_of(file->f_op, struct rfs_file, op_new)) : \
	 NULL)
	 
extern struct file_operations rfs_file_ops;

int rfs_open(struct inode *inode, struct file *file);
struct rfs_file *rfs_file_get(struct rfs_file *rfile);
void rfs_file_put(struct rfs_file *rfile);
void rfs_file_set_ops(struct rfs_file *rfile);
int rfs_file_cache_create(void);
void rfs_file_cache_destory(void);

struct rfs_dcache_data {
	struct rfs_info *rinfo;
	struct rfs_flt *rflt;
	struct dentry *droot;
};

struct rfs_dcache_data *rfs_dcache_data_alloc(struct dentry *dentry,
		struct rfs_info *rinfo, struct rfs_flt *rflt);
void rfs_dcache_data_free(struct rfs_dcache_data *rdata);

struct rfs_dcache_entry {
	struct list_head list;
	struct dentry *dentry;
};

int rfs_dcache_walk(struct dentry *root, int (*cb)(struct dentry *, void *),
		void *data);
int rfs_dcache_add_dir(struct dentry *dentry, void *data);
int rfs_dcache_add(struct dentry *dentry, void *data);
int rfs_dcache_rem(struct dentry *dentry, void *data);
int rfs_dcache_set(struct dentry *dentry, void *data);
int rfs_dcache_reset(struct dentry *dentry, void *data);
int rfs_dcache_rdentry_add(struct dentry *dentry, struct rfs_info *rinfo);
int rfs_dcache_rinode_del(struct rfs_dentry *rdentry, struct inode *inode);
int rfs_dcache_get_subs(struct dentry *dir, struct list_head *sibs);
void rfs_dcache_entry_free_list(struct list_head *head);

struct rfs_context {
	struct list_head data;
	int idx;
	int idx_start;
};

void rfs_context_init(struct rfs_context *rcont, int start);
void rfs_context_deinit(struct rfs_context *rcont);

int rfs_precall_flts(struct rfs_chain *rchain, struct rfs_context *rcont,
		struct redirfs_args *rargs);
void rfs_postcall_flts(struct rfs_chain *rchain, struct rfs_context *rcont,
		struct redirfs_args *rargs);

#define rfs_kobj_to_rflt(__kobj) container_of(__kobj, struct rfs_flt, kobj)
int rfs_flt_sysfs_init(struct rfs_flt *rflt);
void rfs_flt_sysfs_exit(struct rfs_flt *rflt);
void rfs_kobject_init(struct kobject *kobj);

int rfs_sysfs_create(void);

void rfs_data_remove(struct list_head *head);



#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16))

#define rfs_rename_lock(sb) down(&sb->s_vfs_rename_sem)
#define rfs_rename_unlock(sb) up(&sb->s_vfs_rename_sem)

#  if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14))
typedef unsigned gfp_t;

static inline void *kzalloc(size_t size, gfp_t flags)
{
	void *p;
	
	p = kmalloc(size, flags);
	if (!p)
		return NULL;

	memset(p, 0, size);

	return p;
}

#  endif

static inline void *kmem_cache_zalloc(kmem_cache_t *cache, gfp_t flags)
{
	void *obj;

	obj = kmem_cache_alloc(cache, flags);
	if (!obj)
		return NULL;

	memset(obj, 0, kmem_cache_size(cache));

	return obj;
}       

#else

#define rfs_rename_lock(sb) mutex_lock(&sb->s_vfs_rename_mutex)
#define rfs_rename_unlock(sb) mutex_unlock(&sb->s_vfs_rename_mutex)

#endif

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23))

static inline rfs_kmem_cache_t *rfs_kmem_cache_create(const char *n, size_t s)
{
	return kmem_cache_create(n, s, 0, SLAB_RECLAIM_ACCOUNT, NULL);
}

#else

static inline rfs_kmem_cache_t *rfs_kmem_cache_create(const char *n, size_t s)
{
	return kmem_cache_create(n, s, 0, SLAB_RECLAIM_ACCOUNT, NULL, NULL);
}

#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))

static inline void rfs_nameidata_put(struct nameidata *nd)
{
	path_release(nd);
}

static inline struct dentry *rfs_nameidata_dentry(struct nameidata *nd)
{
	return nd->dentry;
}

static inline struct vfsmount *rfs_nameidata_mnt(struct nameidata *nd)
{
	return nd->mnt;
}

#else

static inline void rfs_nameidata_put(struct nameidata *nd)
{
	path_put(&nd->path);
}

static inline struct dentry *rfs_nameidata_dentry(struct nameidata *nd)
{
	return nd->path.dentry;
}

static inline struct vfsmount *rfs_nameidata_mnt(struct nameidata *nd)
{
	return nd->path.mnt;
}

#endif

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
#define rfs_dq_transfer vfs_dq_transfer
#else
#define rfs_dq_transfer DQUOT_TRANSFER
#endif

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))

static inline int rfs_follow_up(struct vfsmount **mnt, struct dentry **dentry)
{
	struct path path;
	int rv;

	path.mnt = *mnt;
	path.dentry = *dentry;

	rv = follow_up(&path);

	*mnt = path.mnt;
	*dentry = path.dentry;

	return rv;
}

#else

static inline int rfs_follow_up(struct vfsmount **mnt, struct dentry **dentry)
{
	return follow_up(mnt, dentry);
}

#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))

static inline void rfs_dcache_lock(struct dentry *d)
{
	spin_lock(&dcache_lock);
}

static inline void rfs_dcache_unlock(struct dentry *d)
{
	spin_unlock(&dcache_lock);
}

static inline struct dentry *rfs_dget_locked(struct dentry *d)
{
	return dget_locked(d);
}

#else

static inline void rfs_dcache_lock(struct dentry *d)
{
	spin_lock(&d->d_lock);
}

static inline void rfs_dcache_unlock(struct dentry *d)
{
	spin_unlock(&d->d_lock);
}

static inline struct dentry *rfs_dget_locked(struct dentry *d)
{
	return dget_dlock(d);
}

#endif


#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))

static inline int rfs_path_lookup(const char *name, struct nameidata *nd)
{
	return path_lookup(name, LOOKUP_FOLLOW, nd);
}

#else

static inline int rfs_path_lookup(const char *name, struct nameidata *nd)
{
	struct path path;
	int rv;

	rv = kern_path(name, LOOKUP_FOLLOW, &path);
	if (rv)
		return rv;

	nd->path = path;
	return 0;
}

#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36))

static inline int rfs_inode_setattr(struct inode *inode, const struct iattr *attr)
{
	return inode_setattr(inode, attr);
}

#else

static inline int rfs_inode_setattr(struct inode *inode, const struct iattr *attr)
{
	setattr_copy(inode, attr);
	mark_inode_dirty(inode);
	return 0;
}

#endif

#endif

driver/redirfs/.svn/text-base/rfs_ops.c.svn-base0000644000076400007640000000305212112622747021461 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

struct rfs_ops *rfs_ops_alloc(void)
{
	struct rfs_ops *rops;
	char *arr;

	rops = kzalloc(sizeof(struct rfs_ops), GFP_KERNEL);
	arr = kzalloc(sizeof(char) * REDIRFS_OP_END, GFP_KERNEL);

	if (!rops || !arr) {
		kfree(rops);
		kfree(arr);
		return ERR_PTR(-ENOMEM);
	}

	rops->arr = arr;
	atomic_set(&rops->count, 1);

	return rops;
}

struct rfs_ops *rfs_ops_get(struct rfs_ops *rops)
{
	if (!rops || IS_ERR(rops))
		return NULL;

	BUG_ON(!atomic_read(&rops->count));
	atomic_inc(&rops->count);
	return rops;
}

void rfs_ops_put(struct rfs_ops *rops)
{
	if (!rops || IS_ERR(rops))
		return;

	BUG_ON(!atomic_read(&rops->count));
	if (!atomic_dec_and_test(&rops->count))
		return;

	kfree(rops->arr);
	kfree(rops);
}

driver/redirfs/.svn/text-base/README.svn-base0000644000076400007640000000234112112622747020522 0ustar  comodocomodo		================================
		RedirFS - Redirecting FileSystem
			    README
		================================

This software is distributed under the GNU General Public License Version 3.

1. Introduction

	Redirecting FileSystem or RedirFS project aims to be general, fast,
	flexible and open source framework allowing to redirect native 
	filesystem calls in the VFS layer. It is implemented as a 
	LKM(Linux Kernel Module) and provides well defined interface for other
	LKMs which are called Filters. Filters can set pre and post call-back 
	functions for selected filesystem operations(e.g. permission, open). 
	Filters can also select for which file system paths will be their
	call-back functions called and even which file system paths will be
	excluded. Each Filter is specified by a name and unique number which
	represents Filter's priority. RedirFS manages all registered Filters and
	calls their call-back functions in specific order defined by their
	priorities.

	For an overview of the RedirFS project, visit 

		http://www.redirfs.org

2. Installation

	See the INSTALL file.

3. Documentation

	http://www.redirfs.org/tiki-index.php?page=redirfs_doc

4. Problems & Bugs
	
	http://www.redirfs.org/cgi-bin/bugzilla/index.cgi
driver/redirfs/.svn/text-base/rfs_dentry.c.svn-base0000644000076400007640000003753612112622747022203 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static rfs_kmem_cache_t *rfs_dentry_cache = NULL;

static struct rfs_dentry *rfs_dentry_alloc(struct dentry *dentry)
{
	struct rfs_dentry *rdentry;

	rdentry = kmem_cache_zalloc(rfs_dentry_cache, GFP_KERNEL);
	if (!rdentry)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rdentry->rinode_list);
	INIT_LIST_HEAD(&rdentry->rfiles);
	INIT_LIST_HEAD(&rdentry->data);
	rdentry->dentry = dentry;
	rdentry->op_old = dentry->d_op;
	spin_lock_init(&rdentry->lock);
	atomic_set(&rdentry->count, 1);

	if (dentry->d_op)
		memcpy(&rdentry->op_new, dentry->d_op,
				sizeof(struct dentry_operations));

	rdentry->op_new.d_iput = rfs_d_iput;

	return rdentry;
}

struct rfs_dentry *rfs_dentry_get(struct rfs_dentry *rdentry)
{
	if (!rdentry || IS_ERR(rdentry))
		return NULL;

	BUG_ON(!atomic_read(&rdentry->count));
	atomic_inc(&rdentry->count);

	return rdentry;
}

void rfs_dentry_put(struct rfs_dentry *rdentry)
{
	if (!rdentry || IS_ERR(rdentry))
		return;

	BUG_ON(!atomic_read(&rdentry->count));
	if (!atomic_dec_and_test(&rdentry->count))
		return;

	rfs_inode_put(rdentry->rinode);
	rfs_info_put(rdentry->rinfo);

	rfs_data_remove(&rdentry->data);
	kmem_cache_free(rfs_dentry_cache, rdentry);
}

struct rfs_dentry *rfs_dentry_add(struct dentry *dentry, struct rfs_info *rinfo)
{
	struct rfs_dentry *rd_new;
	struct rfs_dentry *rd;

	if (!dentry)
		return NULL;

	rd_new = rfs_dentry_alloc(dentry);
	if (IS_ERR(rd_new))
		return rd_new;

	spin_lock(&dentry->d_lock);

	rd = rfs_dentry_find(dentry);

	/*
	 * Workaround for the isofs_lookup function. It assigns
	 * dentry operations for the new dentry from the root dentry.
	 * This leads to the situation when one rdentry object can be
	 * found for more dentry objects.
	 *
	 * isofs_lookup: dentry->d_op = dir->i_sb->s_root->d_op;
	 */
	if (rd && (rd->dentry != dentry)) {
		rd_new->op_old = rd->op_old;
		rfs_dentry_put(rd);
		rd = NULL;
	}

	if (!rd) {
		rd_new->rinfo = rfs_info_get(rinfo);
		dentry->d_op = &rd_new->op_new;
		rfs_dentry_get(rd_new);
		rd = rfs_dentry_get(rd_new);
	}

	spin_unlock(&dentry->d_lock);

	rfs_dentry_put(rd_new);

	return rd;
}

void rfs_dentry_del(struct rfs_dentry *rdentry)
{
	rdentry->dentry->d_op = rdentry->op_old;
	rfs_dentry_put(rdentry);
}

int rfs_dentry_add_rinode(struct rfs_dentry *rdentry, struct rfs_info *rinfo)
{
	struct rfs_inode *rinode;

	if (!rdentry->dentry->d_inode)
		return 0;

	spin_lock(&rdentry->lock);
	if (rdentry->rinode) {
		spin_unlock(&rdentry->lock);
		return 0;
	}
	spin_unlock(&rdentry->lock);

	rinode = rfs_inode_add(rdentry->dentry->d_inode, rinfo);
	if (IS_ERR(rinode))
		return PTR_ERR(rinode);

	spin_lock(&rdentry->lock);
	if (rdentry->rinode) {
		spin_unlock(&rdentry->lock);
		rfs_inode_del(rinode);
		rfs_inode_put(rinode);
		return 0;
	}

	rdentry->rinode = rfs_inode_get(rinode);
	spin_unlock(&rdentry->lock);

	rfs_inode_add_rdentry(rinode, rdentry);
	rfs_inode_put(rinode);
	return 0;
}

void rfs_dentry_rem_rinode(struct rfs_dentry *rdentry)
{
	if (!rdentry->rinode)
		return;

	rfs_inode_rem_rdentry(rdentry->rinode, rdentry);
	rfs_inode_del(rdentry->rinode);
	rfs_inode_put(rdentry->rinode);
	rdentry->rinode = NULL;
}

struct rfs_info *rfs_dentry_get_rinfo(struct rfs_dentry *rdentry)
{
	struct rfs_info *rinfo;

	spin_lock(&rdentry->lock);
	rinfo = rfs_info_get(rdentry->rinfo);
	spin_unlock(&rdentry->lock);

	return rinfo;
}

void rfs_dentry_set_rinfo(struct rfs_dentry *rdentry, struct rfs_info *rinfo)
{
	spin_lock(&rdentry->lock);
	rfs_info_put(rdentry->rinfo);
	rdentry->rinfo = rfs_info_get(rinfo);
	spin_unlock(&rdentry->lock);
}

void rfs_dentry_add_rfile(struct rfs_dentry *rdentry, struct rfs_file *rfile)
{
	spin_lock(&rdentry->lock);
	list_add_tail(&rfile->rdentry_list, &rdentry->rfiles);
	spin_unlock(&rdentry->lock);
	rfs_file_get(rfile);
}

void rfs_dentry_rem_rfile(struct rfs_file *rfile)
{
	spin_lock(&rfile->rdentry->lock);
	list_del_init(&rfile->rdentry_list);
	spin_unlock(&rfile->rdentry->lock);
	rfs_file_put(rfile);
}

int rfs_dentry_cache_create(void)
{
	rfs_dentry_cache = rfs_kmem_cache_create("rfs_dentry_cache",
			sizeof(struct rfs_dentry));

	if (!rfs_dentry_cache)
		return -ENOMEM;

	return 0;
}

void rfs_dentry_cache_destory(void)
{
	kmem_cache_destroy(rfs_dentry_cache);
}

void rfs_d_iput(struct dentry *dentry, struct inode *inode)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_DOP_D_IPUT;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_DOP_D_IPUT;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_DOP_D_IPUT;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_DOP_D_IPUT;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_DOP_D_IPUT;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_DOP_D_IPUT;
	else
		rargs.type.id = REDIRFS_SOCK_DOP_D_IPUT;

	rargs.args.d_iput.dentry = dentry;
	rargs.args.d_iput.inode = inode;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		BUG_ON(rfs_dcache_rinode_del(rdentry, inode));

		if (rdentry->op_old && rdentry->op_old->d_iput)
			rdentry->op_old->d_iput(rargs.args.d_iput.dentry,
					rargs.args.d_iput.inode);
		else
			iput(inode);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);
}

static void rfs_d_release(struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);
	rargs.type.id = REDIRFS_NONE_DOP_D_RELEASE;
	rargs.args.d_release.dentry = dentry;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rdentry->op_old && rdentry->op_old->d_release)
			rdentry->op_old->d_release(rargs.args.d_release.dentry);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_del(rdentry);
	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);
}

static inline int rfs_d_compare_default(const struct qstr *name1,
		const struct qstr *name2)
{
	if (name1->len != name2->len)
		return 1;
	if (memcmp(name1->name, name2->name, name1->len))
		return 1;

	return 0;
}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))

static int rfs_d_compare(struct dentry *dentry, struct qstr *name1,
		struct qstr *name2)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);

	if (dentry->d_inode) {
		if (S_ISREG(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_REG_DOP_D_COMPARE;
		else if (S_ISDIR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_DIR_DOP_D_COMPARE;
		else if (S_ISLNK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_LNK_DOP_D_COMPARE;
		else if (S_ISCHR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_CHR_DOP_D_COMPARE;
		else if (S_ISBLK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_BLK_DOP_D_COMPARE;
		else if (S_ISFIFO(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_FIFO_DOP_D_COMPARE;
		else
			rargs.type.id = REDIRFS_SOCK_DOP_D_COMPARE;
	} else
		rargs.type.id = REDIRFS_NONE_DOP_D_COMPARE;

	rargs.args.d_compare.dentry = dentry;
	rargs.args.d_compare.name1 = name1;
	rargs.args.d_compare.name2 = name2;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rdentry->op_old && rdentry->op_old->d_compare)
			rargs.rv.rv_int = rdentry->op_old->d_compare(
					rargs.args.d_compare.dentry,
					rargs.args.d_compare.name1,
					rargs.args.d_compare.name2);
		else
			rargs.rv.rv_int = rfs_d_compare_default(
					rargs.args.d_compare.name1,
					rargs.args.d_compare.name2);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);

	return rargs.rv.rv_int;
}

#else

static int rfs_d_compare(const struct dentry *parent, const struct inode *inode,
		const struct dentry *dentry, const struct inode *d_inode,
		unsigned int tlen, const char *tname,
		const struct qstr *name)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);

	if (dentry->d_inode) {
		if (S_ISREG(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_REG_DOP_D_COMPARE;
		else if (S_ISDIR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_DIR_DOP_D_COMPARE;
		else if (S_ISLNK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_LNK_DOP_D_COMPARE;
		else if (S_ISCHR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_CHR_DOP_D_COMPARE;
		else if (S_ISBLK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_BLK_DOP_D_COMPARE;
		else if (S_ISFIFO(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_FIFO_DOP_D_COMPARE;
		else
			rargs.type.id = REDIRFS_SOCK_DOP_D_COMPARE;
	} else
		rargs.type.id = REDIRFS_NONE_DOP_D_COMPARE;

	rargs.args.d_compare.parent = parent;
	rargs.args.d_compare.inode = inode;
	rargs.args.d_compare.dentry = dentry;
	rargs.args.d_compare.d_inode = d_inode;
	rargs.args.d_compare.tlen = tlen;
	rargs.args.d_compare.tname = tname;
	rargs.args.d_compare.name = name;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rdentry->op_old && rdentry->op_old->d_compare)
			rargs.rv.rv_int = rdentry->op_old->d_compare(
					rargs.args.d_compare.parent,
					rargs.args.d_compare.inode,
					rargs.args.d_compare.dentry,
					rargs.args.d_compare.d_inode,
					rargs.args.d_compare.tlen,
					rargs.args.d_compare.tname,
					rargs.args.d_compare.name);
		else
			rargs.rv.rv_int = rfs_d_compare_default(
					&rargs.args.d_compare.dentry->d_name,
					rargs.args.d_compare.name);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);

	return rargs.rv.rv_int;
}

#endif

static int rfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rdentry = rfs_dentry_find(dentry);
	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_context_init(&rcont, 0);

	if (dentry->d_inode) {
		if (S_ISREG(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_REG_DOP_D_REVALIDATE;
		else if (S_ISDIR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_DIR_DOP_D_REVALIDATE;
		else if (S_ISLNK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_LNK_DOP_D_REVALIDATE;
		else if (S_ISCHR(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_CHR_DOP_D_REVALIDATE;
		else if (S_ISBLK(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_BLK_DOP_D_REVALIDATE;
		else if (S_ISFIFO(dentry->d_inode->i_mode))
			rargs.type.id = REDIRFS_FIFO_DOP_D_REVALIDATE;
		else
			rargs.type.id = REDIRFS_SOCK_DOP_D_REVALIDATE;
	} else
		rargs.type.id = REDIRFS_NONE_DOP_D_REVALIDATE;

	rargs.args.d_revalidate.dentry = dentry;
	rargs.args.d_revalidate.nd = nd;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rdentry->op_old && rdentry->op_old->d_revalidate)
			rargs.rv.rv_int = rdentry->op_old->d_revalidate(
					rargs.args.d_revalidate.dentry,
					rargs.args.d_revalidate.nd);
		else
			rargs.rv.rv_int = 1;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_dentry_put(rdentry);
	rfs_info_put(rinfo);

	return rargs.rv.rv_int;
}

static void rfs_dentry_set_ops_none(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_NONE_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_NONE_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_reg(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_REG_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_REG_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_dir(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_DIR_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_DIR_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_lnk(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_LNK_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_LNK_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_chr(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_CHR_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_CHR_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_blk(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_BLK_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_BLK_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_fifo(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_FIFO_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_FIFO_DOP_D_REVALIDATE, d_revalidate);
}

static void rfs_dentry_set_ops_sock(struct rfs_dentry *rdentry)
{
	RFS_SET_DOP(rdentry, REDIRFS_SOCK_DOP_D_COMPARE, d_compare);
	RFS_SET_DOP(rdentry, REDIRFS_SOCK_DOP_D_REVALIDATE, d_revalidate);
}

void rfs_dentry_set_ops(struct rfs_dentry *rdentry)
{
	struct rfs_file *rfile;
	umode_t mode;

	spin_lock(&rdentry->lock);

	rdentry->op_new.d_release = rfs_d_release;

	if (!rdentry->rinode) {
		rfs_dentry_set_ops_none(rdentry);
		spin_unlock(&rdentry->lock);
		return;
	}

	list_for_each_entry(rfile, &rdentry->rfiles, rdentry_list) {
		rfs_file_set_ops(rfile);
	}

	mode = rdentry->rinode->inode->i_mode;

	if (S_ISREG(mode))
		rfs_dentry_set_ops_reg(rdentry);

	else if (S_ISDIR(mode))
		rfs_dentry_set_ops_dir(rdentry);

	else if (S_ISLNK(mode))
		rfs_dentry_set_ops_lnk(rdentry);

	else if (S_ISCHR(mode))
		rfs_dentry_set_ops_chr(rdentry);

	else if (S_ISBLK(mode))
		rfs_dentry_set_ops_blk(rdentry);

	else if (S_ISFIFO(mode))
		rfs_dentry_set_ops_fifo(rdentry);

	else if (S_ISSOCK(mode))
		rfs_dentry_set_ops_sock(rdentry);

	spin_unlock(&rdentry->lock);
	rfs_inode_set_ops(rdentry->rinode);
}

void rfs_dentry_rem_data(struct dentry *dentry, struct rfs_flt *rflt)
{
	struct redirfs_data *data;
	struct rfs_dentry *rdentry;
	struct rfs_file *rfile;
	
	data = redirfs_detach_data_dentry(rflt, dentry);
	if (data && data->detach)
		data->detach(data);
	redirfs_put_data(data);

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return;

	spin_lock(&rdentry->lock);

	list_for_each_entry(rfile, &rdentry->rfiles, rdentry_list) {
		data = redirfs_detach_data_file(rflt, rfile->file);
		if (data && data->detach)
			data->detach(data);
		redirfs_put_data(data);
	}

	spin_unlock(&rdentry->lock);

	if (!dentry->d_inode) {
		rfs_dentry_put(rdentry);
		return;
	}

	data = redirfs_detach_data_inode(rflt, dentry->d_inode);
	if (data && data->detach)
		data->detach(data);
	redirfs_put_data(data);

	rfs_dentry_put(rdentry);
}

int rfs_dentry_move(struct dentry *dentry, struct rfs_flt *rflt,
		struct rfs_root *src, struct rfs_root *dst)
{
	int rv = 0;

	if (!rflt->ops)
		return 0;

	if (rflt->ops->dentry_moved)
		rv = rflt->ops->dentry_moved(src, dst, dentry);

	if (rv)
		return rv;

	if (!dentry->d_inode)
		return 0;

	if (rflt->ops->inode_moved)
		rv = rflt->ops->inode_moved(src, dst, dentry->d_inode);

	return rv;
}

driver/redirfs/.svn/text-base/rfs_path.c.svn-base0000644000076400007640000004462512112622747021627 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static LIST_HEAD(rfs_path_list);
RFS_DEFINE_MUTEX(rfs_path_mutex);

static struct rfs_path *rfs_path_alloc(struct vfsmount *mnt,
		struct dentry *dentry)
{
	struct rfs_path *rpath;

	rpath = kzalloc(sizeof(struct rfs_path), GFP_KERNEL);
	if (!rpath)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rpath->list);
	INIT_LIST_HEAD(&rpath->rroot_list);
	rpath->mnt = mntget(mnt);
	rpath->dentry = dget(dentry);
	atomic_set(&rpath->count, 1);

	return rpath;
}

struct rfs_path *rfs_path_get(struct rfs_path *rpath)
{
	if (!rpath || IS_ERR(rpath))
		return NULL;

	BUG_ON(!atomic_read(&rpath->count));
	atomic_inc(&rpath->count);

	return rpath;
}

void rfs_path_put(struct rfs_path *rpath)
{
	if (!rpath || IS_ERR(rpath))
		return;

	BUG_ON(!atomic_read(&rpath->count));
	if (!atomic_dec_and_test(&rpath->count))
		return;

	dput(rpath->dentry);
	mntput(rpath->mnt);
	kfree(rpath);
}

static struct rfs_path *rfs_path_find(struct vfsmount *mnt,
		struct dentry *dentry)
{
	struct rfs_path *rpath = NULL;
	struct rfs_path *found = NULL;

	list_for_each_entry(rpath, &rfs_path_list, list) {
		if (rpath->mnt != mnt) 
			continue;

		if (rpath->dentry != dentry)
			continue;

		found = rfs_path_get(rpath);
		break;
	}

	return found;
}

struct rfs_path *rfs_path_find_id(int id)
{
	struct rfs_path *rpath = NULL;
	struct rfs_path *found = NULL;

	list_for_each_entry(rpath, &rfs_path_list, list) {
		if (rpath->id != id)
			continue;

		found = rfs_path_get(rpath);
		break;
	}

	return found;
}

static int rfs_path_add_rroot(struct rfs_path *rpath)
{
	struct rfs_root *rroot;

	rroot = rfs_root_add(rpath->dentry);
	if (IS_ERR(rroot))
		return PTR_ERR(rroot);
	
	rfs_root_add_rpath(rroot, rpath);
	rpath->rroot = rroot;

	return 0;
}

static void rfs_path_rem_rroot(struct rfs_path *rpath)
{
	rfs_root_rem_rpath(rpath->rroot, rpath);
	rfs_root_put(rpath->rroot);
	rpath->rroot = NULL;
}

static void rfs_path_list_add(struct rfs_path *rpath)
{
	list_add_tail(&rpath->list, &rfs_path_list);
	rfs_path_get(rpath);
}

static void rfs_path_list_rem(struct rfs_path *rpath)
{
	list_del_init(&rpath->list);
	rfs_path_put(rpath);
}

static int rfs_path_get_id(void)
{
	struct rfs_path *rpath = NULL;
	int i = 0;

mainloop:
	while (i < INT_MAX) {
		list_for_each_entry(rpath, &rfs_path_list, list) {
			if (rpath->id == i) {
				i++;
				goto mainloop;
			}
		}
		return i;
	}

	return -1;
}

static struct rfs_path *rfs_path_add(struct vfsmount *mnt,
		struct dentry *dentry)
{
	struct rfs_path *rpath;
	int id;
	int rv;

	rpath = rfs_path_find(mnt, dentry);
	if (rpath)
		return rpath;

	id = rfs_path_get_id();
	if (id < 0)
		return ERR_PTR(-EBUSY);

	rpath = rfs_path_alloc(mnt, dentry);
	if (IS_ERR(rpath))
		return rpath;

	rpath->id = id;

	rv = rfs_path_add_rroot(rpath);
	if (rv) {
		rfs_path_put(rpath);
		return ERR_PTR(rv);
	}

	rfs_path_list_add(rpath);

	return rpath;
}

static void rfs_path_rem(struct rfs_path *rpath)
{
	if (rpath->rinch || rpath->rexch)
		return;

	rfs_path_rem_rroot(rpath);
	rfs_path_list_rem(rpath);
}

static int rfs_path_add_dirs(struct dentry *dentry)
{
	struct rfs_inode *rinode;

	rinode = rfs_inode_find(dentry->d_inode);
	if (rinode) {
		rfs_inode_put(rinode);
		return 0;
	}

	return rfs_dcache_walk(dentry, rfs_dcache_add_dir, NULL);
}

static int rfs_path_check_fs(struct file_system_type *type)
{
	if (!strcmp("cifs", type->name))
		goto notsup;

	return 0;
notsup:
	printk(KERN_ERR "redirfs does not support '%s' file system\n",
			type->name);
	return -1;
}

static int rfs_path_add_include(struct rfs_path *rpath, struct rfs_flt *rflt)
{
	struct rfs_chain *rinch;
	int rv;

	if (rfs_chain_find(rpath->rinch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rpath->rexch, rflt) != -1)
		return -EEXIST;

	rv = rfs_path_add_dirs(rpath->dentry->d_sb->s_root);
	if (rv)
		return rv;

	rinch = rfs_chain_add(rpath->rinch, rflt);
	if (IS_ERR(rinch))
		return PTR_ERR(rinch);

	rv = rfs_root_add_include(rpath->rroot, rflt);
	if (rv) {
		rfs_chain_put(rinch);
		return rv;
	}

	rfs_chain_put(rpath->rinch);
	rpath->rinch = rinch;
	rflt->paths_nr++;

	return 0;
}
	
static int rfs_path_add_exclude(struct rfs_path *rpath, struct rfs_flt *rflt)
{
	struct rfs_chain *rexch;
	int rv;

	if (rfs_chain_find(rpath->rexch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rpath->rinch, rflt) != -1)
		return -EEXIST;

	rexch = rfs_chain_add(rpath->rexch, rflt);
	if (IS_ERR(rexch))
		return PTR_ERR(rexch);

	rv = rfs_root_add_exclude(rpath->rroot, rflt);
	if (rv) {
		rfs_chain_put(rexch);
		return rv;
	}

	rfs_chain_put(rpath->rexch);
	rpath->rexch = rexch;
	rflt->paths_nr++;

	return 0;
}

static int rfs_path_rem_include(struct rfs_path *rpath, struct rfs_flt *rflt)
{
	struct rfs_chain *rinch;
	int rv;

	if (rfs_chain_find(rpath->rinch, rflt) == -1)
		return 0;

	rinch = rfs_chain_rem(rpath->rinch, rflt);
	if (IS_ERR(rinch))
		return PTR_ERR(rinch);

	rv = rfs_root_rem_include(rpath->rroot, rflt);
	if (rv) {
		rfs_chain_put(rinch);
		return rv;
	}

	rfs_chain_put(rpath->rinch);
	rpath->rinch = rinch;
	rflt->paths_nr--;

	return 0;
}

static int rfs_path_rem_exclude(struct rfs_path *rpath, struct rfs_flt *rflt)
{
	struct rfs_chain *rexch;
	int rv;

	if (rfs_chain_find(rpath->rexch, rflt) == -1)
		return 0;

	rexch = rfs_chain_rem(rpath->rexch, rflt);
	if (IS_ERR(rexch))
		return PTR_ERR(rexch);

	rv = rfs_root_rem_exclude(rpath->rroot, rflt);
	if (rv) {
		rfs_chain_put(rexch);
		return rv;
	}

	rfs_chain_put(rpath->rexch);
	rpath->rexch = rexch;
	rflt->paths_nr--;

	return 0;
}

redirfs_path redirfs_add_path(redirfs_filter filter,
		struct redirfs_path_info *info)
{
	struct rfs_path *rpath;
	int rv;

	might_sleep();

	if (!filter || IS_ERR(filter) || !info)
		return ERR_PTR(-EINVAL);

	if (!info->mnt || !info->dentry || !info->flags)
		return ERR_PTR(-EINVAL);

	if (rfs_path_check_fs(info->dentry->d_inode->i_sb->s_type))
		return ERR_PTR(-EPERM);

	rfs_rename_lock(info->dentry->d_inode->i_sb);
	rfs_mutex_lock(&rfs_path_mutex);

	rpath = rfs_path_add(info->mnt, info->dentry);
	if (IS_ERR(rpath))
		goto exit;

	if (info->flags == REDIRFS_PATH_INCLUDE)
		rv = rfs_path_add_include(rpath, filter);

	else if (info->flags == REDIRFS_PATH_EXCLUDE)
		rv = rfs_path_add_exclude(rpath, filter);

	else
		rv = -EINVAL;

	rfs_path_rem(rpath);

	if (rv) {
		rfs_path_put(rpath);
		rpath = ERR_PTR(rv);
	}
exit:
	rfs_mutex_unlock(&rfs_path_mutex);
	rfs_rename_unlock(info->dentry->d_inode->i_sb);
	return rpath;
}

int redirfs_rem_path(redirfs_filter filter, redirfs_path path)
{
	struct rfs_path *rpath = (struct rfs_path *)path;
	int rv;

	might_sleep();

	if (!filter || IS_ERR(filter) || !path)
		return -EINVAL;

	rfs_rename_lock(rpath->dentry->d_inode->i_sb);
	rfs_mutex_lock(&rfs_path_mutex);

	if (rfs_chain_find(rpath->rinch, filter) != -1)
		rv = rfs_path_rem_include(path, filter);

	else if (rfs_chain_find(rpath->rexch, filter) != -1)
		rv = rfs_path_rem_exclude(path, filter);

	else
		rv = -EINVAL;

	rfs_path_rem(rpath);

	rfs_mutex_unlock(&rfs_path_mutex);
	rfs_rename_unlock(rpath->dentry->d_inode->i_sb);

	return rv;
}

int redirfs_get_id_path(redirfs_path path)
{
	struct rfs_path *rpath = path;

	if (!path || IS_ERR(path))
		return -EINVAL;

	return rpath->id;
}

redirfs_path redirfs_get_path_id(int id)
{
	struct rfs_path *rpath;

	might_sleep();

	rfs_mutex_lock(&rfs_path_mutex);
	rpath = rfs_path_find_id(id);
	rfs_mutex_unlock(&rfs_path_mutex);

	return rpath;
}

redirfs_path redirfs_get_path(redirfs_path path)
{
	return rfs_path_get(path);
}

void redirfs_put_path(redirfs_path path)
{
	rfs_path_put(path);
}

redirfs_path* redirfs_get_paths_root(redirfs_filter filter, redirfs_root root)
{
	struct rfs_root *rroot = (struct rfs_root *)root;
	struct rfs_path *rpath;
	redirfs_path *paths;
	int i = 0;

	if (!filter || IS_ERR(filter) || !root)
		return ERR_PTR(-EINVAL);

	rfs_mutex_lock(&rfs_path_mutex);
	paths = kzalloc(sizeof(redirfs_path) * (rroot->paths_nr + 1),
			GFP_KERNEL);
	if (!paths) {
		rfs_mutex_unlock(&rfs_path_mutex);
		return ERR_PTR(-ENOMEM);
	}

	list_for_each_entry(rpath, &rroot->rpaths, rroot_list) {
		if (rfs_chain_find(rroot->rinch, filter) != -1)
			paths[i++] = rfs_path_get(rpath);

		else if (rfs_chain_find(rroot->rexch, filter) != -1)
			paths[i++] = rfs_path_get(rpath);

	}

	rfs_mutex_unlock(&rfs_path_mutex);
	paths[i] = NULL;

	return paths;
}

redirfs_path* redirfs_get_paths(redirfs_filter filter)
{
	struct rfs_flt *rflt = filter;
	struct rfs_path *rpath;
	redirfs_path *paths;
	int i = 0;

	might_sleep();

	if (!filter || IS_ERR(filter))
		return ERR_PTR(-EINVAL);

	rfs_mutex_lock(&rfs_path_mutex);

	paths = kzalloc(sizeof(redirfs_path) * (rflt->paths_nr + 1),
			GFP_KERNEL);
	if (!paths) {
		rfs_mutex_unlock(&rfs_path_mutex);
		return ERR_PTR(-ENOMEM);
	}

	list_for_each_entry(rpath, &rfs_path_list, list) {
		if (rfs_chain_find(rpath->rinch, filter) != -1)
			paths[i++] = rfs_path_get(rpath);

		else if (rfs_chain_find(rpath->rexch, filter) != -1)
			paths[i++] = rfs_path_get(rpath);
	}

	rfs_mutex_unlock(&rfs_path_mutex);
	paths[i] = NULL;

	return paths;
}

void redirfs_put_paths(redirfs_path *paths)
{
	int i = 0;

	if (!paths)
		return;

	while (paths[i]) {
		redirfs_put_path(paths[i]);
		i++;
	}

	kfree(paths);
}

struct redirfs_path_info *redirfs_get_path_info(redirfs_filter filter,
		redirfs_path path)
{
	struct rfs_path *rpath = path;
	struct redirfs_path_info *info;

	might_sleep();

	if (!filter || IS_ERR(filter) || !path)
		return ERR_PTR(-EINVAL);

	info = kzalloc(sizeof(struct redirfs_path_info), GFP_KERNEL);
	if (!info)
		return ERR_PTR(-ENOMEM);

	rfs_mutex_lock(&rfs_path_mutex);

	if (rfs_chain_find(rpath->rinch, filter) != -1)
		info->flags = REDIRFS_PATH_INCLUDE;

	else if (rfs_chain_find(rpath->rexch, filter) != -1)
		info->flags = REDIRFS_PATH_EXCLUDE;

	rfs_mutex_unlock(&rfs_path_mutex);

	if (!info->flags) {
		kfree(info);
		return ERR_PTR(-ENODATA);
	}

	info->mnt = mntget(rpath->mnt);
	info->dentry = dget(rpath->dentry);

	return info;
}

void redirfs_put_path_info(struct redirfs_path_info *info)
{
	if (!info)
		return;

	mntput(info->mnt);
	dput(info->dentry);
	kfree(info);
}

int redirfs_rem_paths(redirfs_filter filter)
{
	redirfs_path *paths;
	int rv = 0;
	int i = 0;

	if (!filter || IS_ERR(filter))
		return -EINVAL;

	paths = redirfs_get_paths(filter);
	if (IS_ERR(paths))
		return PTR_ERR(paths);

	while (paths[i]) {
		rv = redirfs_rem_path(filter, paths[i]);
		if (rv)
			break;
		i++;
	}

	redirfs_put_paths(paths);

	return rv;
}

int rfs_path_get_info(struct rfs_flt *rflt, char *buf, int size)
{
	struct rfs_path *rpath;
	char *path;
	char type;
	int len = 0;
	int rv;

	path = kzalloc(sizeof(char) * PAGE_SIZE, GFP_KERNEL);
	if (!path)
		return -ENOMEM;

	rfs_mutex_lock(&rfs_path_mutex);

	list_for_each_entry(rpath, &rfs_path_list, list) {
		if (rfs_chain_find(rpath->rinch, rflt) != -1)
			type = 'i';

		else if (rfs_chain_find(rpath->rexch, rflt) != -1)
			type = 'e';

		else
			continue;

		rv = redirfs_get_filename(rpath->mnt, rpath->dentry, path,
				PAGE_SIZE);

		if (rv) {
			rfs_mutex_unlock(&rfs_path_mutex);
			kfree(path);
			return rv;
		}

		len += snprintf(buf + len, size - len,"%c:%d:%s",
				type, rpath->id, path) + 1;

		if (len >= size) {
			len = size;
			break;
		}
	}

	rfs_mutex_unlock(&rfs_path_mutex);
	kfree(path);

	return len;
}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))

int redirfs_get_filename(struct vfsmount *mnt, struct dentry *dentry, char *buf,
		int size)
{
	char *fn;
	size_t len;

	fn = d_path(dentry, mnt, buf, size);
	if (IS_ERR(fn))
		return PTR_ERR(fn);

	len = strlen(fn);
	memmove(buf, fn, len);
	buf[len] = 0;
	return 0;
}

#else

int redirfs_get_filename(struct vfsmount *mnt, struct dentry *dentry, char *buf,
		int size)
{
	struct path path;
	char *fn;	
	size_t len;

	path.mnt = mnt;
	path.dentry = dentry;
	fn = d_path(&path, buf, size);
	if (IS_ERR(fn))
		return PTR_ERR(fn);

	len = strlen(fn);
	memmove(buf, fn, len);
	buf[len] = 0;
	return 0;
}

#endif

static int rfs_fsrename_rem_rroot(struct rfs_root *rroot,
		struct rfs_chain *rchain)
{
	int rv;
	int i;

	if (!rchain)
		return 0;

	for (i = 0; i < rchain->rflts_nr; i++) {
		rv = rfs_root_rem_flt(rroot, rchain->rflts[i]);
		if (rv)
			return rv;

		rv = rfs_root_walk(rfs_root_rem_flt, rchain->rflts[i]);
		if (rv)
			return rv;
	}

	return 0;
}

static int rfs_fsrename_rem_dentry(struct rfs_root *rroot,
		struct rfs_chain *rchain, struct dentry *dentry)
{
	struct rfs_chain *rchnew = NULL;
	struct rfs_chain *rchrem = NULL;
	struct rfs_info *rinfo = NULL;
	int rv = 0;
	int i;

	if (!rchain)
		return 0;

	rchrem = rfs_chain_get(rroot->rinfo->rchain);

	for (i = 0; i < rchain->rflts_nr; i++) {
		rchnew = rfs_chain_rem(rchrem, rchain->rflts[i]);
		if (IS_ERR(rchnew)) {
			rv = PTR_ERR(rchnew);
			goto exit;
		}

		rfs_chain_put(rchrem);
		rchrem = rchnew;
		rinfo = rfs_info_alloc(rroot, rchnew);
		if (IS_ERR(rinfo)) {
			rv = PTR_ERR(rinfo);
			goto exit;
		}

		rv = rfs_info_rem(dentry, rinfo, rchain->rflts[i]);
		rfs_info_put(rinfo);
		if (rv)
			goto exit;
	}
exit:
	rfs_chain_put(rchrem);
	return rv;
}

static int rfs_fsrename_rem(struct rfs_root *rroot_src,
		struct rfs_root *rroot_dst, struct dentry *dentry)
{
	struct rfs_chain *rchain = NULL;
	int rv;

	if (!rroot_src)
		return 0;

	if (!rroot_dst)
		rchain = rfs_chain_get(rroot_src->rinfo->rchain);
	else
		rchain = rfs_chain_diff(rroot_src->rinfo->rchain,
				rroot_dst->rinfo->rchain);

	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	if (rroot_src->dentry == dentry) 
		rv = rfs_fsrename_rem_rroot(rroot_src, rchain);
	else
		rv = rfs_fsrename_rem_dentry(rroot_src, rchain, dentry);

	rfs_chain_put(rchain);
	return rv;
}

static int rfs_fsrename_add_rroot(struct rfs_root *rroot,
		struct rfs_chain *rchain)
{
	int rv;
	int i;

	if (!rchain)
		return 0;

	for (i = 0; i < rchain->rflts_nr; i++) {
		rv = rfs_root_add_flt(rroot, rchain->rflts[i]);
		if (rv)
			return rv;

		rv = rfs_root_walk(rfs_root_add_flt, rchain->rflts[i]);
		if (rv)
			return rv;
	}

	return 0;
}

static int rfs_fsrename_add_dentry(struct rfs_root *rroot,
		struct rfs_chain *rchain, struct dentry *dentry)
{
	struct rfs_chain *rchnew = NULL;
	struct rfs_chain *rchadd = NULL;
	struct rfs_dentry *rdentry = NULL;
	struct rfs_info *rinfo = NULL;
	int rv = 0;
	int i;

	if (!rchain)
		return rfs_info_reset(dentry, rroot->rinfo);

	rdentry = rfs_dentry_find(dentry);
	if (rdentry)
		rchadd = rfs_chain_get(rdentry->rinfo->rchain);

	for (i = 0; i < rchain->rflts_nr; i++) {
		rchnew = rfs_chain_add(rchadd, rchain->rflts[i]);
		if (IS_ERR(rchnew)) {
			rv = PTR_ERR(rchnew);
			goto exit;
		}

		rfs_chain_put(rchadd);
		rchadd = rchnew;
		rinfo = rfs_info_alloc(rroot, rchnew);
		if (IS_ERR(rinfo)) {
			rv = PTR_ERR(rinfo);
			goto exit;
		}

		rv = rfs_info_add(dentry, rinfo, rchain->rflts[i]);
		rfs_info_put(rinfo);
		if (rv)
			goto exit;
	}

	rv = rfs_info_reset(dentry, rroot->rinfo);
exit:
	rfs_dentry_put(rdentry);
	rfs_chain_put(rchadd);
	return rv;
}

static int rfs_fsrename_add(struct rfs_root *rroot_src,
		struct rfs_root *rroot_dst, struct dentry *dentry)
{
	struct rfs_chain *rchain = NULL;
	int rv;

	if (!rroot_dst)
		return 0;

	if (!rroot_src)
		rchain = rfs_chain_get(rroot_dst->rinfo->rchain);
	else
		rchain = rfs_chain_diff(rroot_dst->rinfo->rchain,
				rroot_src->rinfo->rchain);

	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	if (rroot_src && rroot_src->dentry == dentry) 
		rv = rfs_fsrename_add_rroot(rroot_src, rchain);
	else
		rv = rfs_fsrename_add_dentry(rroot_dst, rchain, dentry);

	rfs_chain_put(rchain);
	return rv;
}

static int rfs_fsrename_set(struct rfs_root *rroot_src,
		struct rfs_root *rroot_dst, struct dentry *dentry)
{
	struct rfs_dentry *rdentry;
	struct rfs_chain *rchain_src;
	struct rfs_chain *rchain_dst;
	struct rfs_info *rinfo;
	int rv = 0;
	int i;

	if (!rroot_src || !rroot_dst)
		return 0;

	if (rroot_src->dentry == dentry) 
		return 0;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return 0;

	rchain_src = rdentry->rinfo->rchain;
	rchain_dst = rroot_dst->rinfo->rchain;

	for (i = 0; i < rchain_src->rflts_nr; i++) {
		if (rfs_chain_find(rchain_dst, rchain_src->rflts[i]) == -1)
			continue;

		rinfo = rfs_info_alloc(rroot_dst, rchain_src);
		if (IS_ERR(rinfo)) {
			rv = PTR_ERR(rinfo);
			goto exit;
		}

		rv = rfs_info_set(dentry, rinfo, rchain_src->rflts[i]);
		rfs_info_put(rinfo);
		if (rv)
			goto exit;
	}
exit:
	rfs_dentry_put(rdentry);
	return rv;
}

int rfs_fsrename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
	struct rfs_root *rroot_src = NULL;
	struct rfs_root *rroot_dst = NULL;
	struct rfs_inode *rinode = NULL;
	struct rfs_dentry *rdentry = NULL;
	int rv = 0;

	if (old_dir == new_dir)
		return 0;

	rfs_mutex_lock(&rfs_path_mutex);

	rinode = rfs_inode_find(new_dir);
	rdentry = rfs_dentry_find(old_dentry);

	if (rinode->rinfo->rchain)
		rroot_dst = rfs_root_get(rinode->rinfo->rroot);

	if (rdentry && rdentry->rinfo->rchain)
		rroot_src = rfs_root_get(rdentry->rinfo->rroot);

	if (rroot_src == rroot_dst) 
		goto exit;

	rv = rfs_fsrename_rem(rroot_src, rroot_dst, old_dentry);
	if (rv)
		goto exit;

	rv = rfs_fsrename_set(rroot_src, rroot_dst, old_dentry);
	if (rv)
		goto exit;

	rv = rfs_fsrename_add(rroot_src, rroot_dst, old_dentry);
exit:
	rfs_mutex_unlock(&rfs_path_mutex);
	rfs_root_put(rroot_src);
	rfs_root_put(rroot_dst);
	rfs_inode_put(rinode);
	rfs_dentry_put(rdentry);
	return rv;
}

EXPORT_SYMBOL(redirfs_get_path);
EXPORT_SYMBOL(redirfs_put_path);
EXPORT_SYMBOL(redirfs_get_paths);
EXPORT_SYMBOL(redirfs_get_paths_root);
EXPORT_SYMBOL(redirfs_put_paths);
EXPORT_SYMBOL(redirfs_get_path_info);
EXPORT_SYMBOL(redirfs_put_path_info);
EXPORT_SYMBOL(redirfs_add_path);
EXPORT_SYMBOL(redirfs_rem_path);
EXPORT_SYMBOL(redirfs_rem_paths);
EXPORT_SYMBOL(redirfs_get_filename);
EXPORT_SYMBOL(redirfs_get_id_path);
EXPORT_SYMBOL(redirfs_get_path_id);

driver/redirfs/.svn/text-base/rfs_sysfs.c.svn-base0000644000076400007640000003175712112622747022044 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

#define rfs_kattr_to_rattr(__kattr) \
	container_of(__kattr, struct redirfs_filter_attribute, attr)

static struct rfs_flt *rfs_sysfs_flt_get(struct rfs_flt *rflt)
{
	spin_lock(&rflt->lock);

	if (atomic_read(&rflt->count) < 3) {
		spin_unlock(&rflt->lock);
		return ERR_PTR(-ENOENT);
	}

	rfs_flt_get(rflt);

	spin_unlock(&rflt->lock);

	return rflt;
}

static ssize_t rfs_flt_show(struct kobject *kobj, struct attribute *attr,
		char *buf)
{
	struct rfs_flt *rflt = rfs_kobj_to_rflt(kobj);
	struct redirfs_filter_attribute *rattr = rfs_kattr_to_rattr(attr);
	ssize_t rv;

	rflt = rfs_sysfs_flt_get(rflt);
	if (IS_ERR(rflt))
		return PTR_ERR(rflt);

	rv = rattr->show(rflt, rattr, buf);

	rfs_flt_put(rflt);

	return rv;
}

static ssize_t rfs_flt_store(struct kobject *kobj, struct attribute *attr,
		const char *buf, size_t count)
{
	struct rfs_flt *rflt = rfs_kobj_to_rflt(kobj);
	struct redirfs_filter_attribute *rattr = rfs_kattr_to_rattr(attr);
	ssize_t rv;

	if (strcmp(attr->name, "unregister") == 0)
		return rattr->store(rflt, rattr, buf, count);

	rflt = rfs_sysfs_flt_get(rflt);
	if (IS_ERR(rflt))
		return PTR_ERR(rflt);

	rv = rattr->store(rflt, rattr, buf, count);

	rfs_flt_put(rflt);

	return rv;
}

static ssize_t rfs_flt_priority_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	struct rfs_flt *rflt = filter;

	return snprintf(buf, PAGE_SIZE, "%d", rflt->priority);
}

static ssize_t rfs_flt_active_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	struct rfs_flt *rflt = filter;

	return snprintf(buf, PAGE_SIZE, "%d",
			atomic_read(&rflt->active));
}

static ssize_t rfs_flt_active_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	int act;
	int rv;

	if (sscanf(buf, "%d", &act) != 1)
		return -EINVAL;

	if (act) {
		if (rflt->ops && rflt->ops->activate)
			rv = rflt->ops->activate();
		else
			rv = redirfs_activate_filter(filter);

	} else {
		if (rflt->ops && rflt->ops->deactivate)
			rv = rflt->ops->deactivate();
		else
			rv = redirfs_deactivate_filter(filter);
	}

	if (rv)
		return rv;

	return count;
}

static ssize_t rfs_flt_paths_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	struct rfs_flt *rflt = filter;
	
	return rfs_path_get_info(rflt, buf, PAGE_SIZE);
}

static int rfs_flt_paths_add(redirfs_filter filter, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	struct rfs_path *rpath;
	struct redirfs_path_info info;
	struct nameidata nd;
	char *path;
	char type;
	int rv;

	path = kzalloc(sizeof(char) * PAGE_SIZE, GFP_KERNEL);
	if (!path)
		return -ENOMEM;

	if (sscanf(buf, "a:%c:%s", &type, path) != 2) {
		kfree(path);
		return -EINVAL;
	}

	if (type == 'i')
		info.flags = REDIRFS_PATH_INCLUDE;

	else if (type == 'e')
		info.flags = REDIRFS_PATH_EXCLUDE;

	else {
		kfree(path);
		return -EINVAL;
	}

	rv = rfs_path_lookup(path, &nd);
	if (rv) {
		kfree(path);
		return rv;
	}

	info.dentry = rfs_nameidata_dentry(&nd);
	info.mnt = rfs_nameidata_mnt(&nd);

	if (!rflt->ops || !rflt->ops->add_path) {
		rpath = redirfs_add_path(filter, &info);
		if (IS_ERR(rpath))
			rv = PTR_ERR(rpath);
		rfs_path_put(rpath);

	} else
		rv = rflt->ops->add_path(&info);

	rfs_nameidata_put(&nd);
	kfree(path);

	return rv;
}

static int rfs_flt_paths_rem(redirfs_filter filter, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	struct rfs_path *rpath;
	int id;
	int rv;

	if (sscanf(buf, "r:%d", &id) != 1)
		return -EINVAL;

	rfs_mutex_lock(&rfs_path_mutex);
	rpath = rfs_path_find_id(id);
	if (!rpath) {
		rfs_mutex_unlock(&rfs_path_mutex);
		return -ENOENT;
	}
	rfs_mutex_unlock(&rfs_path_mutex);
	
	if (rflt->ops && rflt->ops->rem_path)
		rv = rflt->ops->rem_path(rpath);
	else
		rv = redirfs_rem_path(filter, rpath);

	rfs_path_put(rpath);

	return rv;
}

static int rfs_flt_paths_clean(redirfs_filter filter, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	char clean;
	int rv;

	if (sscanf(buf, "%c", &clean) != 1)
		return -EINVAL;

	if (clean != 'c')
		return -EINVAL;

	if (rflt->ops && rflt->ops->rem_paths)
		rv = rflt->ops->rem_paths();
	else
		rv = redirfs_rem_paths(filter);

	return rv;
}

static ssize_t rfs_flt_paths_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	int rv;

	if (count < 2)
		return -EINVAL;

	if (*buf == 'a')
		rv = rfs_flt_paths_add(filter, buf, count);

	else if (*buf == 'r')
		rv = rfs_flt_paths_rem(filter, buf, count);

	else if (*buf == 'c')
		rv = rfs_flt_paths_clean(filter, buf, count);

	else
		rv = -EINVAL;

	if (rv)
		return rv;

	return count;
}

static ssize_t rfs_flt_unregister_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	struct rfs_flt *rflt = filter;
	int unreg;
	int rv;

	if (sscanf(buf, "%d", &unreg) != 1)
		return -EINVAL;

	if (unreg != 1)
		return -EINVAL;

	if (rflt->ops && rflt->ops->unregister)
		rv = rflt->ops->unregister();
	else
		rv = redirfs_unregister_filter(filter);

	if (rv)
		return rv;

	return count;
}

static struct redirfs_filter_attribute rfs_flt_priority_attr =
	REDIRFS_FILTER_ATTRIBUTE(priority, 0444, rfs_flt_priority_show, NULL);

static struct redirfs_filter_attribute rfs_flt_active_attr = 
	REDIRFS_FILTER_ATTRIBUTE(active, 0644, rfs_flt_active_show,
			rfs_flt_active_store);

static struct redirfs_filter_attribute rfs_flt_paths_attr = 
	REDIRFS_FILTER_ATTRIBUTE(paths, 0644, rfs_flt_paths_show,
			rfs_flt_paths_store);

static struct redirfs_filter_attribute rfs_flt_unregister_attr = 
	REDIRFS_FILTER_ATTRIBUTE(unregister, 0200, NULL,
			rfs_flt_unregister_store);

static struct attribute *rfs_flt_attrs[] = {
	&rfs_flt_priority_attr.attr,
	&rfs_flt_active_attr.attr,
	&rfs_flt_paths_attr.attr,
	&rfs_flt_unregister_attr.attr,
	NULL
};

static struct kset *rfs_flt_kset;

static struct sysfs_ops rfs_sysfs_ops = {
	.show = rfs_flt_show,
	.store = rfs_flt_store
};

struct kobj_type rfs_flt_ktype = {
	.sysfs_ops = &rfs_sysfs_ops,
	.release = rfs_flt_release,
	.default_attrs = rfs_flt_attrs
};

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
static struct kobject *rfs_fs_kobj;
static struct kobject *rfs_kobj;

static inline void rfs_kobj_release(struct kobject *kobj)
{
	kfree(kobj);
}

static struct kobj_type rfs_kobj_ktype = {
	.release = rfs_kobj_release
};

int rfs_sysfs_create(void)
{
	int rv;

	rfs_fs_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
	if (!rfs_fs_kobj)
		return -ENOMEM;

	kobject_init(rfs_fs_kobj);
	rfs_fs_kobj->ktype = &rfs_kobj_ktype;
	rv = kobject_set_name(rfs_fs_kobj, "%s", "fs");
	if (rv) {
		kobject_put(rfs_fs_kobj);
		return rv;
	}

	rv = kobject_register(rfs_fs_kobj);
	if (rv) {
		kobject_put(rfs_fs_kobj);
		return rv;
	}

	rv = -ENOMEM;
	rfs_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
	if (!rfs_kobj) 
		goto err_fs_kobj;

	kobject_init(rfs_kobj);
	rfs_kobj->ktype = &rfs_kobj_ktype;
	rfs_kobj->parent = rfs_fs_kobj;
	rv = kobject_set_name(rfs_kobj, "%s", "redirfs");
	if (rv) {
		kobject_put(rfs_kobj);
		goto err_fs_kobj;
	}

	rv = kobject_register(rfs_kobj);
	if (rv) {
		kobject_put(rfs_kobj);
		goto err_fs_kobj;
	}

	rv = -ENOMEM;
	rfs_flt_kset = kzalloc(sizeof(struct kset), GFP_KERNEL);
	if (!rfs_flt_kset)
		goto err_rfs_kobj;

	kobject_init(&rfs_flt_kset->kobj);
	rfs_flt_kset->kobj.ktype = &rfs_kobj_ktype;
	rfs_flt_kset->kobj.parent = rfs_kobj;
	rv = kobject_set_name(&rfs_flt_kset->kobj, "%s", "filters");
	if (rv) 
		goto err_kset;

	rv = kset_register(rfs_flt_kset);
	if (rv)
		goto err_kset;

	return 0;

err_kset:
	kset_put(rfs_flt_kset);
err_rfs_kobj:
	kobject_unregister(rfs_kobj);
err_fs_kobj:
	kobject_unregister(rfs_fs_kobj);
	return rv;
}
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
static struct kobject *rfs_kobj;

static inline void rfs_kobj_release(struct kobject *kobj)
{
	kfree(kobj);
}

static struct kobj_type rfs_kobj_ktype = {
	.release = rfs_kobj_release
};

int rfs_sysfs_create(void)
{
	int rv;

	rfs_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
	if (!rfs_kobj)
		return -ENOMEM;

	kobject_init(rfs_kobj);
	rfs_kobj->ktype = &rfs_kobj_ktype;
	rfs_kobj->parent = &fs_subsys.kset.kobj;
	rv = kobject_set_name(rfs_kobj, "%s", "redirfs");
	if (rv) {
		kobject_put(rfs_kobj);
		return rv;
	}

	rv = kobject_register(rfs_kobj);
	if (rv) {
		kobject_put(rfs_kobj);
		return rv;
	}

	rv = -ENOMEM;
	rfs_flt_kset = kzalloc(sizeof(struct kset), GFP_KERNEL);
	if (!rfs_flt_kset)
		goto err_kobj;

	kobject_init(&rfs_flt_kset->kobj);
	rfs_flt_kset->kobj.ktype = &rfs_kobj_ktype;
	rfs_flt_kset->kobj.parent = rfs_kobj;
	rv = kobject_set_name(&rfs_flt_kset->kobj, "%s", "filters");
	if (rv) 
		goto err_kset;

	rv = kset_register(rfs_flt_kset);
	if (rv)
		goto err_kset;

	return 0;

err_kset:
	kset_put(rfs_flt_kset);
err_kobj:
	kobject_unregister(rfs_kobj);
	return rv;
}
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
static struct kobject *rfs_kobj;

static inline void rfs_kobj_release(struct kobject *kobj)
{
	kfree(kobj);
}

static struct kobj_type rfs_kobj_ktype = {
	.release = rfs_kobj_release
};

int rfs_sysfs_create(void)
{
	int rv;

	rfs_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
	if (!rfs_kobj)
		return -ENOMEM;

	kobject_init(rfs_kobj);
	rfs_kobj->ktype = &rfs_kobj_ktype;
	rfs_kobj->parent = &fs_subsys.kobj;
	rv = kobject_set_name(rfs_kobj, "%s", "redirfs");
	if (rv) {
		kobject_put(rfs_kobj);
		return rv;
	}

	rv = kobject_register(rfs_kobj);
	if (rv) {
		kobject_put(rfs_kobj);
		return rv;
	}

	rv = -ENOMEM;
	rfs_flt_kset = kzalloc(sizeof(struct kset), GFP_KERNEL);
	if (!rfs_flt_kset)
		goto err_kobj;

	kobject_init(&rfs_flt_kset->kobj);
	rfs_flt_kset->kobj.ktype = &rfs_kobj_ktype;
	rfs_flt_kset->kobj.parent = rfs_kobj;
	rv = kobject_set_name(&rfs_flt_kset->kobj, "%s", "filters");
	if (rv) 
		goto err_kset;

	rv = kset_register(rfs_flt_kset);
	if (rv)
		goto err_kset;

	return 0;

err_kset:
	kset_put(rfs_flt_kset);
err_kobj:
	kobject_unregister(rfs_kobj);
	return rv;
}
#else
static struct kobject *rfs_kobj;

int rfs_sysfs_create(void)
{
	rfs_kobj = kobject_create_and_add("redirfs", fs_kobj);
	if (!rfs_kobj)
		return -ENOMEM;

	rfs_flt_kset = kset_create_and_add("filters", NULL, rfs_kobj);
	if (!rfs_flt_kset) {
		kobject_put(rfs_kobj);
		return -ENOMEM;
	}

	return 0;
}
#endif

int redirfs_create_attribute(redirfs_filter filter,
		struct redirfs_filter_attribute *attr)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || !attr)
		return -EINVAL;

	return sysfs_create_file(&rflt->kobj, &attr->attr);
}

int redirfs_remove_attribute(redirfs_filter filter,
		struct redirfs_filter_attribute *attr)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || !attr)
		return -EINVAL;

	sysfs_remove_file(&rflt->kobj, &attr->attr);

	return 0;
}

struct kobject *redirfs_filter_kobject(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || IS_ERR(rflt))
		return ERR_PTR(-EINVAL);

	return &rflt->kobj;
}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
int rfs_flt_sysfs_init(struct rfs_flt *rflt)
{
	int rv;

	rflt->kobj.ktype = &rfs_flt_ktype;
	rflt->kobj.kset = rfs_flt_kset;
	kobject_init(&rflt->kobj);

	rv = kobject_set_name(&rflt->kobj, rflt->name);
	if (rv)
		return rv;

	rv = kobject_add(&rflt->kobj);
	if (rv)
		return rv;

	kobject_uevent(&rflt->kobj, KOBJ_ADD, NULL);

	rfs_flt_get(rflt);

	return 0;
}
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
int rfs_flt_sysfs_init(struct rfs_flt *rflt)
{
	int rv;

	rflt->kobj.ktype = &rfs_flt_ktype;
	rflt->kobj.kset = rfs_flt_kset;
	kobject_init(&rflt->kobj);

	rv = kobject_set_name(&rflt->kobj, rflt->name);
	if (rv)
		return rv;

	rv = kobject_add(&rflt->kobj);
	if (rv)
		return rv;

	kobject_uevent(&rflt->kobj, KOBJ_ADD);

	rfs_flt_get(rflt);

	return 0;
}
#else
int rfs_flt_sysfs_init(struct rfs_flt *rflt)
{
	int rv;

	rflt->kobj.kset = rfs_flt_kset;
	kobject_init(&rflt->kobj, &rfs_flt_ktype);

	rv = kobject_add(&rflt->kobj, NULL, "%s", rflt->name);
	if (rv)
		return rv;

	kobject_uevent(&rflt->kobj, KOBJ_ADD);

	rfs_flt_get(rflt);

	return 0;
}
#endif

void rfs_flt_sysfs_exit(struct rfs_flt *rflt)
{
	kobject_del(&rflt->kobj);
}

EXPORT_SYMBOL(redirfs_create_attribute);
EXPORT_SYMBOL(redirfs_remove_attribute);
EXPORT_SYMBOL(redirfs_filter_kobject);

driver/redirfs/.svn/text-base/Makefile.svn-base0000644000076400007640000000027112112622747021302 0ustar  comodocomodoobj-m += redirfs.o
redirfs-objs := rfs_path.o rfs_root.o rfs_info.o rfs_file.o rfs_dentry.o \
	rfs_inode.o rfs_dcache.o rfs_chain.o rfs_ops.o rfs_data.o \
	rfs_flt.o rfs_sysfs.o rfs.o

driver/redirfs/.svn/text-base/rfs_file.c.svn-base0000644000076400007640000001776312112622747021615 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static rfs_kmem_cache_t *rfs_file_cache = NULL;

struct file_operations rfs_file_ops = {
	.open = rfs_open
};

static struct rfs_file *rfs_file_alloc(struct file *file)
{
	struct rfs_file *rfile;

	rfile = kmem_cache_zalloc(rfs_file_cache, GFP_KERNEL);
	if (!rfile)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rfile->rdentry_list);
	INIT_LIST_HEAD(&rfile->data);
	rfile->file = file;
	spin_lock_init(&rfile->lock);
	atomic_set(&rfile->count, 1);
	rfile->op_old = fops_get(file->f_op);

	if (rfile->op_old)
		memcpy(&rfile->op_new, rfile->op_old,
				sizeof(struct file_operations));

	rfile->op_new.open = rfs_open;

	return rfile;
}

struct rfs_file *rfs_file_get(struct rfs_file *rfile)
{
	if (!rfile || IS_ERR(rfile))
		return NULL;

	BUG_ON(!atomic_read(&rfile->count));
	atomic_inc(&rfile->count);

	return rfile;
}

void rfs_file_put(struct rfs_file *rfile)
{
	if (!rfile || IS_ERR(rfile))
		return;

	BUG_ON(!atomic_read(&rfile->count));
	if (!atomic_dec_and_test(&rfile->count))
		return;

	rfs_dentry_put(rfile->rdentry);
	fops_put(rfile->op_old);

	rfs_data_remove(&rfile->data);
	kmem_cache_free(rfs_file_cache, rfile);
}

static struct rfs_file *rfs_file_add(struct file *file)
{
	struct rfs_file *rfile;

	rfile = rfs_file_alloc(file);
	if (IS_ERR(rfile))
		return rfile;

	rfile->rdentry = rfs_dentry_find(file->f_dentry);
	rfs_dentry_add_rfile(rfile->rdentry, rfile);
	fops_put(file->f_op);
	file->f_op = &rfile->op_new;
	rfs_file_get(rfile);
	spin_lock(&rfile->rdentry->lock);
	rfs_file_set_ops(rfile);
	spin_unlock(&rfile->rdentry->lock);

	return rfile;
}

static void rfs_file_del(struct rfs_file *rfile)
{
	rfs_dentry_rem_rfile(rfile);
	rfile->file->f_op = fops_get(rfile->op_old);
	rfs_file_put(rfile);
}

int rfs_file_cache_create(void)
{
	rfs_file_cache = rfs_kmem_cache_create("rfs_file_cache",
			sizeof(struct rfs_file));

	if (!rfs_file_cache)
		return -ENOMEM;

	return 0;
}

void rfs_file_cache_destory(void)
{
	kmem_cache_destroy(rfs_file_cache);
}

int rfs_open(struct inode *inode, struct file *file)
{
	struct rfs_file *rfile;
	struct rfs_dentry *rdentry;
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rinode = rfs_inode_find(inode);
	fops_put(file->f_op);
	file->f_op = fops_get(rinode->fop_old);

	rdentry = rfs_dentry_find(file->f_dentry);
	if (!rdentry) {
		rfs_inode_put(rinode);
		if (file->f_op && file->f_op->open)
			return file->f_op->open(inode, file);

		return 0;
	}

	rinfo = rfs_dentry_get_rinfo(rdentry);
	rfs_dentry_put(rdentry);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_FOP_OPEN;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_FOP_OPEN;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_FOP_OPEN;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_FOP_OPEN;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_FOP_OPEN;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_FOP_OPEN;

	rargs.args.f_open.inode = inode;
	rargs.args.f_open.file = file;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rinode->fop_old && rinode->fop_old->open)
			rargs.rv.rv_int = rinode->fop_old->open(
					rargs.args.f_open.inode,
					rargs.args.f_open.file);
		else
			rargs.rv.rv_int = 0;
	}

	if (!rargs.rv.rv_int) {
		rfile = rfs_file_add(file);
		if (IS_ERR(rfile))
			BUG();
		rfs_file_put(rfile);
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_inode_put(rinode);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_release(struct inode *inode, struct file *file)
{
	struct rfs_file *rfile;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct redirfs_args rargs;

	rfile = rfs_file_find(file);
	rinfo = rfs_dentry_get_rinfo(rfile->rdentry);
	rfs_context_init(&rcont, 0);

	if (S_ISREG(inode->i_mode))
		rargs.type.id = REDIRFS_REG_FOP_RELEASE;
	else if (S_ISDIR(inode->i_mode))
		rargs.type.id = REDIRFS_DIR_FOP_RELEASE;
	else if (S_ISLNK(inode->i_mode))
		rargs.type.id = REDIRFS_LNK_FOP_RELEASE;
	else if (S_ISCHR(inode->i_mode))
		rargs.type.id = REDIRFS_CHR_FOP_RELEASE;
	else if (S_ISBLK(inode->i_mode))
		rargs.type.id = REDIRFS_BLK_FOP_RELEASE;
	else if (S_ISFIFO(inode->i_mode))
		rargs.type.id = REDIRFS_FIFO_FOP_RELEASE;

	rargs.args.f_release.inode = inode;
	rargs.args.f_release.file = file;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rfile->op_old && rfile->op_old->release)
			rargs.rv.rv_int = rfile->op_old->release(
					rargs.args.f_release.inode,
					rargs.args.f_release.file);
		else
			rargs.rv.rv_int = 0;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	rfs_file_del(rfile);
	rfs_file_put(rfile);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static int rfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
	LIST_HEAD(sibs);
	struct rfs_dcache_entry *sib;
	struct rfs_file *rfile;
	struct rfs_info *rinfo;
	struct rfs_context rcont;
	struct rfs_dentry *rdentry;
	struct redirfs_args rargs;

	rfile = rfs_file_find(file);
	rinfo = rfs_dentry_get_rinfo(rfile->rdentry);
	rfs_context_init(&rcont, 0);

	if (S_ISDIR(file->f_dentry->d_inode->i_mode))
		rargs.type.id = REDIRFS_DIR_FOP_READDIR;

	rargs.args.f_readdir.file = file;
	rargs.args.f_readdir.dirent = dirent;
	rargs.args.f_readdir.filldir = filldir;

	if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) {
		if (rfile->op_old && rfile->op_old->readdir) 
			rargs.rv.rv_int = rfile->op_old->readdir(
					rargs.args.f_readdir.file,
					rargs.args.f_readdir.dirent,
					rargs.args.f_readdir.filldir);
		else
			rargs.rv.rv_int = -ENOTDIR;
	}

	rfs_postcall_flts(rinfo->rchain, &rcont, &rargs);
	rfs_context_deinit(&rcont);

	if (rargs.rv.rv_int)
		goto exit;

	if (rfs_dcache_get_subs(file->f_dentry, &sibs)) {
		BUG();
		goto exit;
	}

	list_for_each_entry(sib, &sibs, list) {
		rdentry = rfs_dentry_find(sib->dentry);
		if (rdentry) {
			rfs_dentry_put(rdentry);
			continue;
		}

		if (!rinfo->rops) {
			if (!sib->dentry->d_inode)
				continue;

			if (!S_ISDIR(sib->dentry->d_inode->i_mode))
				continue;
		}

		if (rfs_dcache_rdentry_add(sib->dentry, rinfo)) {
			BUG();
			goto exit;
		}
	}

exit:
	rfs_dcache_entry_free_list(&sibs);
	rfs_file_put(rfile);
	rfs_info_put(rinfo);
	return rargs.rv.rv_int;
}

static void rfs_file_set_ops_reg(struct rfs_file *rfile)
{
}

static void rfs_file_set_ops_dir(struct rfs_file *rfile)
{
	rfile->op_new.readdir = rfs_readdir;
}

static void rfs_file_set_ops_lnk(struct rfs_file *rfile)
{
}

static void rfs_file_set_ops_chr(struct rfs_file *rfile)
{
}

static void rfs_file_set_ops_blk(struct rfs_file *rfile)
{
}

static void rfs_file_set_ops_fifo(struct rfs_file *rfile)
{
}

void rfs_file_set_ops(struct rfs_file *rfile)
{
	umode_t mode;

	if (!rfile->rdentry->rinode)
		return;

	mode = rfile->rdentry->rinode->inode->i_mode;

	if (S_ISREG(mode))
		rfs_file_set_ops_reg(rfile);

	else if (S_ISDIR(mode))
		rfs_file_set_ops_dir(rfile);

	else if (S_ISLNK(mode))
		rfs_file_set_ops_lnk(rfile);

	else if (S_ISCHR(mode))
		rfs_file_set_ops_chr(rfile);

	else if (S_ISBLK(mode))
		rfs_file_set_ops_blk(rfile);

	else if (S_ISFIFO(mode))
		rfs_file_set_ops_fifo(rfile);

	rfile->op_new.release = rfs_release;
}

driver/redirfs/.svn/text-base/.svnignore.svn-base0000644000076400007640000000005512112622747021655 0ustar  comodocomodo*.o.cmd
*.ko.cmd
*.mod.c
.tmp_versions
*.ko

driver/redirfs/.svn/text-base/CHANGELOG.svn-base0000644000076400007640000001345512112622747021064 0ustar  comodocomodoversion 0.11 experimental 2011-09-05
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- added pre_rename and post_rename callback to redirfs_filter_operations
		- this can be used by filter to be notified about files moved
		  inside a filter's path within one file system
	- support for 2.6.38+ kernels
	- redirfs_get_filename is now just a simple wrapper around d_path and it
	  returns a filename just for the first mount point.

version 0.10 2010-05-20
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- reflected changes in 2.6.34 kernel
		- include of <linux/slab.h>
		- removeved unnecessary checks in rfs_setattr_default

version 0.9 2010-04-06
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed RHEL 5.4 address_space_operations_ext hang by removing
	  address_space_operations support 
	  thanks to Vasiliy Novikov <vasiliy.novikov@gmail.com>
	- removed rfs_dcache_rdentry_add_check since it causes too many problems
	  when dentry operations were assigned from the root dentry
	  thanks to Vasiliy Novikov <vasiliy.novikov@gmail.com>

version 0.8
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed rfs dentry addition for isofs
	  thanks to Vasiliy Novikov <vasiliy.novikov@gmail.com>
	- support for kernels >= 2.6.12
	  thanks to Vasiliy Novikov <vasiliy.novikov@gmail.com>
	- reflected changes in the follow_up function interface in 2.6.31
	- fixed filter reference counter, kref_get() warning on zero counter 
	
version 0.7
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- used dget_locked instead of direct increase of d_count
          it allows redirfs to run at kernel with openvz patches
	- added callbacks
		REDIRFS_DIR_IOP_UNLINK
		REDIRFS_DIR_IOP_RMDIR
		REDIRFS_REG_IOP_SETATTR
		REDIRFS_DIR_IOP_SETATTR
		REDIRFS_LNK_IOP_SETATTR
		REDIRFS_CHR_IOP_SETATTR
		REDIRFS_BLK_IOP_SETATTR
		REDIRFS_FIFO_IOP_SETATTR
		REDIRFS_SOCK_IOP_SETATTR
		REDIRFS_NONE_DOP_D_REVALIDATE
		REDIRFS_REG_DOP_D_REVALIDATE
		REDIRFS_DIR_DOP_D_REVALIDATE
		REDIRFS_CHR_DOP_D_REVALIDATE
		REDIRFS_BLK_DOP_D_REVALIDATE
		REDIRFS_FIFO_DOP_D_REVALIDATE
		REDIRFS_LNK_DOP_D_REVALIDATE
		REDIRFS_SOCK_DOP_D_REVALIDATE
	- added might_sleep() macro into functions which can sleep
	- fixed locking in redirfs_get_path_id()
	- removed GFP_ATOMIC allocations where possible and added GFP_KERNEL
	  allocation fallbacks otherwise, BUG 14
	- better filter handle check in redirfs API, added IS_ERR check
	- fixed bind mount paths - two paths one root
	- added support for older kernels >= 2.6.16, thanks to Sergey Ivanov
	- fixed open with the O_DIRECTORY flag for non directory file types,
	  thanks to Sergey Ivanov
	- cifs is not supported
	  the -EPERM error is returned when path is to be added within cifs

version 0.6
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed bug 13 - oops BUG at rfs_inode.c:306!

version 0.5
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed NULL pointer dereference in rfs_fsrename_set

version 0.4
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- added support for private data - file, dentry, inode, redirfs root
	- introduced redirfs_root handle representing redirfs root object
	- simplified sysfs interface
	- small changes in the redirfs interface (not compatible with previous
	  versions)
	- redirfs_ctl control callbacks replaced with generic
	  redirfs_filter_operations table
	- fixed rinfo memory leak

version 0.3
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- reflected changes in the permission function interface
	- fixed rdentry NULL dereference in rfs_fsrename
	- rfs_lookup adds only dirs while there are no registered filters

version 0.3-pre4
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- reworked global rename handling
	- makefile cleanup

	* John Ogness <redirfs@ogness.net> 
	- fixed wrong reference usage in rfs_path_get

version 0.3-pre3
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- removed usage of RCU due to CONFIG_PREEMPT_RCU
	- redirfs is now a permanent module which cannot be unloaded
	- fixed dead lock in rfs_dcache_walk and rfs_fsrename
	- redirect readdir instead of d_compare to check newly added vfs objects(NFS)
	- fixed removing of path attached to the file system root
	- cleanup of the redirfs_get_filename function
	- fixed full path name for the file system root
	- added check if filter is active in post calls
	- correct destruction of inode objects in the rfs_d_iput function
	- rinode objects are removed in the rfs_d_iput function
	- rdentry objects are removed in the rfs_d_release function
	- fixed NULL pointer dereferences in the rfs_fsrename functions

version 0.3-pre2
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed removing of rfs_file objects
	- added support for file systems which are adding dentry/inode objects
	  during readdir (e.g. NFS)

version 0.3-pre1
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- rewritten from scratch
	- new path management
	- new sysfs interface
	- new redirfs framework interface
	- supports kernel version 2.6.25 and higher
	- not all features introduced in the 0.2 version implemented yet
		- missing support for filter's private data
		- missing support for address space operations
		- limited set of redirected operations

version 0.2.1
	* never released, experimental support for sub-mounts

	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed bug 09: crash on rdentry_set_ops when changing path
	- fixed bug 10: include subtree after include single path causes crash
	- fixed bug 11: added rename support
	- added support for sub-mounts and sub-unmounts
	- added support for rename
	- changed rfs_get_filename interface, now it requires vfsmount object

	* Paolo Ambrosio <paolo.ambrosio@gmail.com>
	- fixed typo RFS_REG_AOP_COMMINT_WRITE => RFS_REG_AOP_COMMIT_WRITE
	- fixed bug 12: added mmap callback

version 0.2
	* rewritten from scratch

version 0.1
	* first stable version with limited functionality

driver/redirfs/.svn/text-base/rfs_root.c.svn-base0000644000076400007640000002560412112622747021652 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

LIST_HEAD(rfs_root_list);
LIST_HEAD(rfs_root_walk_list);

static struct rfs_root *rfs_root_alloc(struct dentry *dentry)
{
	struct rfs_root *rroot;

	rroot = kzalloc(sizeof(struct rfs_root), GFP_KERNEL);
	if (!rroot)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&rroot->list);
	INIT_LIST_HEAD(&rroot->walk_list);
	INIT_LIST_HEAD(&rroot->rpaths);
	INIT_LIST_HEAD(&rroot->data);
	rroot->dentry = dentry;
	rroot->paths_nr = 0;
	spin_lock_init(&rroot->lock);
	atomic_set(&rroot->count, 1);

	return rroot;
}

struct rfs_root *rfs_root_get(struct rfs_root *rroot)
{
	if (!rroot || IS_ERR(rroot))
		return NULL;

	BUG_ON(!atomic_read(&rroot->count));
	atomic_inc(&rroot->count);

	return rroot;
}

void rfs_root_put(struct rfs_root *rroot)
{
	if (!rroot || IS_ERR(rroot))
		return;

	BUG_ON(!atomic_read(&rroot->count));
	if (!atomic_dec_and_test(&rroot->count))
		return;

	rfs_chain_put(rroot->rinch);
	rfs_chain_put(rroot->rexch);
	rfs_data_remove(&rroot->data);
	kfree(rroot);
}

static struct rfs_root *rfs_root_find(struct dentry *dentry)
{
	struct rfs_root *rroot = NULL;
	struct rfs_root *found = NULL;

	list_for_each_entry(rroot, &rfs_root_list, list) {
		if (rroot->dentry != dentry)
			continue;

		found = rfs_root_get(rroot);
		break;
	}

	return found;
}

static void rfs_root_list_add(struct rfs_root *rroot)
{
	list_add_tail(&rroot->list, &rfs_root_list);
	rfs_root_get(rroot);
}

static void rfs_root_list_rem(struct rfs_root *rroot)
{
	list_del_init(&rroot->list);
	rfs_root_put(rroot);
}

void rfs_root_add_rpath(struct rfs_root *rroot, struct rfs_path *rpath)
{
	rroot->paths_nr++;
	list_add_tail(&rpath->rroot_list, &rroot->rpaths);
	rfs_path_get(rpath);
}

void rfs_root_rem_rpath(struct rfs_root *rroot, struct rfs_path *rpath)
{
	rroot->paths_nr--;
	list_del_init(&rpath->rroot_list);

	if (!list_empty(&rroot->rpaths)) {
		rfs_path_put(rpath);
		return;
	}

	rfs_path_put(rpath);
	rfs_root_list_rem(rroot);
}

struct rfs_root *rfs_root_add(struct dentry *dentry)
{
	struct rfs_root *rroot;

	rroot = rfs_root_find(dentry);
	if (rroot)
		return rroot;

	rroot = rfs_root_alloc(dentry);
	if (IS_ERR(rroot))
		return rroot;

	rfs_root_list_add(rroot);

	return rroot;
}

static int rfs_root_flt_num(struct rfs_root *rroot, struct rfs_flt *rflt,
		int type)
{
	struct rfs_chain *rchain;
	struct rfs_path *rpath;
	int num = 0;

	list_for_each_entry(rpath, &rroot->rpaths, rroot_list) {
		if (type & REDIRFS_PATH_INCLUDE)
			rchain = rpath->rinch;
		else
			rchain = rpath->rexch;

		if (rfs_chain_find(rchain, rflt) != -1)
			num++;
	}

	return num;
}

int rfs_root_add_include(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_chain *rinch;
	int rv;

	if (rfs_chain_find(rroot->rinch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rexch, rflt) != -1)
		return -EEXIST;

	rinch = rfs_chain_add(rroot->rinch, rflt);
	if (IS_ERR(rinch))
		return PTR_ERR(rinch);

	rv = rfs_info_add_include(rroot, rflt);
	if (rv) {
		rfs_chain_put(rinch);
		return rv;
	}

	spin_lock(&rroot->lock);
	rfs_chain_put(rroot->rinch);
	rroot->rinch = rinch;
	spin_unlock(&rroot->lock);
	return 0;
}

int rfs_root_add_exclude(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_chain *rexch ;
	int rv;

	if (rfs_chain_find(rroot->rexch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rinch, rflt) != -1)
		return -EEXIST;

	rexch = rfs_chain_add(rroot->rexch, rflt);
	if (IS_ERR(rexch))
		return PTR_ERR(rexch);

	rv = rfs_info_add_exclude(rroot, rflt);
	if (rv) {
		rfs_chain_put(rexch);
		return rv;
	}

	spin_lock(&rroot->lock);
	rfs_chain_put(rroot->rexch);
	rroot->rexch = rexch;
	spin_unlock(&rroot->lock);
	return 0;
}

int rfs_root_rem_include(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_chain *rinch;
	struct redirfs_data *data;
	int rv;

	if (rfs_root_flt_num(rroot, rflt, REDIRFS_PATH_INCLUDE) > 1)
		return 0;

	rinch = rfs_chain_rem(rroot->rinch, rflt);
	if (IS_ERR(rinch))
		return PTR_ERR(rinch);

	rv = rfs_info_rem_include(rroot, rflt);
	if (rv) {
		rfs_chain_put(rinch);
		return rv;
	}

	spin_lock(&rroot->lock);
	rfs_chain_put(rroot->rinch);
	rroot->rinch = rinch;
	spin_unlock(&rroot->lock);
	data = redirfs_detach_data_root(rflt, rroot);
	if (data && data->detach)
		data->detach(data);
	redirfs_put_data(data);
	return 0;
}

int rfs_root_rem_exclude(struct rfs_root *rroot, struct rfs_flt *rflt)
{
	struct rfs_chain *rexch;
	struct redirfs_data *data;
	int rv;

	if (rfs_root_flt_num(rroot, rflt, REDIRFS_PATH_EXCLUDE) > 1)
		return 0;

	rexch = rfs_chain_rem(rroot->rexch, rflt);
	if (IS_ERR(rexch))
		return PTR_ERR(rexch);

	rv = rfs_info_rem_exclude(rroot, rflt);
	if (rv) {
		rfs_chain_put(rexch);
		return rv;
	}

	spin_lock(&rroot->lock);
	rfs_chain_put(rroot->rexch);
	rroot->rexch = rexch;
	spin_unlock(&rroot->lock);
	data = redirfs_detach_data_root(rflt, rroot);
	if (data && data->detach)
		data->detach(data);
	redirfs_put_data(data);
	return 0;
}

int rfs_root_add_flt(struct rfs_root *rroot, void *data)
{
	struct rfs_chain *rchain = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_dcache_data *rdata = NULL;
	struct rfs_flt *rflt = (struct rfs_flt *)data;
	int rv = 0;

	if (rfs_chain_find(rroot->rinch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rexch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rinfo->rchain, rflt) != -1)
		return 0;

	rchain = rfs_chain_add(rroot->rinfo->rchain, rflt);
	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	rdata = rfs_dcache_data_alloc(rroot->dentry, rinfo, rflt);
	if (IS_ERR(rdata)) {
		rv = PTR_ERR(rdata);
		goto exit;
	}

	rv = rfs_dcache_walk(rroot->dentry, rfs_dcache_add, rdata);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_dcache_data_free(rdata);
	rfs_chain_put(rchain);
	rfs_info_put(rinfo);
	return rv;
}

int rfs_root_rem_flt(struct rfs_root *rroot, void *data)
{
	struct rfs_chain *rchain = NULL;
	struct rfs_info *rinfo = NULL;
	struct rfs_dcache_data *rdata = NULL;
	struct rfs_flt *rflt = (struct rfs_flt *)data;
	int rv = 0;

	if (rfs_chain_find(rroot->rinch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rexch, rflt) != -1)
		return 0;

	if (rfs_chain_find(rroot->rinfo->rchain, rflt) == -1)
		return 0;

	rchain = rfs_chain_rem(rroot->rinfo->rchain, rflt);
	if (IS_ERR(rchain))
		return PTR_ERR(rchain);

	rinfo = rfs_info_alloc(rroot, rchain);
	if (IS_ERR(rinfo)) {
		rv = PTR_ERR(rinfo);
		goto exit;
	}

	rdata = rfs_dcache_data_alloc(rroot->dentry, rinfo, rflt);
	if (IS_ERR(rdata)) {
		rv = PTR_ERR(rdata);
		goto exit;
	}

	rv = rfs_dcache_walk(rroot->dentry, rfs_dcache_rem, rdata);
	if (rv)
		goto exit;

	rfs_root_set_rinfo(rroot, rinfo);
exit:
	rfs_dcache_data_free(rdata);
	rfs_chain_put(rchain);
	rfs_info_put(rinfo);
	return rv;
}

int rfs_root_walk(int (*cb)(struct rfs_root *, void *), void *data)
{
	struct rfs_root *rroot;
	struct rfs_root *tmp;
	int rv = 0;

	while (!list_empty(&rfs_root_walk_list)) {
		rroot = list_entry(rfs_root_walk_list.next, struct rfs_root,
				walk_list);
		rv = cb(rroot, data);
		if (rv)
			break;

		list_del_init(&rroot->walk_list);
	}

	list_for_each_entry_safe(rroot, tmp, &rfs_root_walk_list, walk_list) {
		list_del_init(&rroot->walk_list);
	}

	return rv;
}

void rfs_root_add_walk(struct dentry *dentry)
{
	struct rfs_dentry *rdentry = NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		goto error;

	if (!rdentry->rinfo)
		goto error;

	if (rdentry->rinfo->rroot->dentry != dentry)
		goto error;

	list_add_tail(&rdentry->rinfo->rroot->walk_list, &rfs_root_walk_list);

error:
	rfs_dentry_put(rdentry);
	return;
}

static struct rfs_root *rfs_get_root_flt(struct rfs_flt *rflt,
		struct rfs_info *rinfo_start)
{
	struct rfs_root *rroot = NULL;
	struct rfs_info *rinfo;

	rinfo = rfs_info_get(rinfo_start);

	while (rinfo) {
		if (rfs_chain_find(rinfo->rchain, rflt) == -1)
			goto exit;

		rroot = rfs_root_get(rinfo->rroot);
		if (!rroot)
			goto exit;

		spin_lock(&rroot->lock);

		if (rfs_chain_find(rroot->rinch, rflt) != -1) {
			spin_unlock(&rroot->lock);
			goto exit;

		}

		spin_unlock(&rroot->lock);

		rfs_info_put(rinfo);
		rinfo = rfs_info_parent(rroot->dentry);
		rfs_root_put(rroot);
		rroot = NULL;
	}

exit:
	rfs_info_put(rinfo);
	return rroot;
}

redirfs_root redirfs_get_root_file(redirfs_filter filter, struct file *file)
{
	struct rfs_root *rroot;
	struct rfs_file *rfile;
	struct rfs_info *rinfo;

	if (!filter || IS_ERR(filter) || !file)
		return NULL;

	rfile = rfs_file_find(file);
	if (!rfile)
		return NULL;

	rinfo = rfs_dentry_get_rinfo(rfile->rdentry);

	rroot = rfs_get_root_flt(filter, rinfo);

	rfs_info_put(rinfo);
	rfs_file_put(rfile);
	return rroot;
}

redirfs_root redirfs_get_root_dentry(redirfs_filter filter,
		struct dentry *dentry)
{
	struct rfs_root *rroot;
	struct rfs_dentry *rdentry;
	struct rfs_info *rinfo;

	if (!filter || IS_ERR(filter) || !dentry)
		return NULL;

	rdentry = rfs_dentry_find(dentry);
	if (!rdentry)
		return NULL;

	rinfo = rfs_dentry_get_rinfo(rdentry);

	rroot = rfs_get_root_flt(filter, rinfo);

	rfs_info_put(rinfo);
	rfs_dentry_put(rdentry);
	return rroot;
}

redirfs_root redirfs_get_root_inode(redirfs_filter filter, struct inode *inode)
{
	struct rfs_root *rroot;
	struct rfs_inode *rinode;
	struct rfs_info *rinfo;

	if (!filter || IS_ERR(filter) || !inode)
		return NULL;

	rinode = rfs_inode_find(inode);
	if (!rinode)
		return NULL;

	rinfo = rfs_inode_get_rinfo(rinode);

	rroot = rfs_get_root_flt(filter, rinfo);

	rfs_info_put(rinfo);
	rfs_inode_put(rinode);
	return rroot;
}

redirfs_root redirfs_get_root_path(redirfs_path path)
{
	struct rfs_path *rpath = path;

	if (!path)
		return NULL;

	return rfs_root_get(rpath->rroot);
}

redirfs_root redirfs_get_root(redirfs_root root)
{
	return rfs_root_get(root);
}

void redirfs_put_root(redirfs_root root)
{
	rfs_root_put(root);
}

void rfs_root_set_rinfo(struct rfs_root *rroot, struct rfs_info *rinfo)
{
	rfs_info_put(rroot->rinfo);
	rroot->rinfo = rfs_info_get(rinfo);
}

EXPORT_SYMBOL(redirfs_get_root_file);
EXPORT_SYMBOL(redirfs_get_root_dentry);
EXPORT_SYMBOL(redirfs_get_root_inode);
EXPORT_SYMBOL(redirfs_get_root_path);
EXPORT_SYMBOL(redirfs_get_root);
EXPORT_SYMBOL(redirfs_put_root);

driver/redirfs/.svn/text-base/rfs.c.svn-base0000644000076400007640000000554512112622747020611 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

struct rfs_info *rfs_info_none;

int rfs_precall_flts(struct rfs_chain *rchain, struct rfs_context *rcont,
		struct redirfs_args *rargs)
{
	enum redirfs_rv (*rop)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv rv;

	if (!rchain)
		return 0;

	rargs->type.call = REDIRFS_PRECALL;

	rcont->idx = rcont->idx_start;

	for (; rcont->idx < rchain->rflts_nr; rcont->idx++) {
		if (!atomic_read(&rchain->rflts[rcont->idx]->active))
			continue;

		rop = rchain->rflts[rcont->idx]->cbs[rargs->type.id].pre_cb;
		if (!rop)
			continue;

		rv = rop(rcont, rargs);
		if (rv == REDIRFS_STOP)
			return -1;
	}

	rcont->idx--;

	return 0;
}

void rfs_postcall_flts(struct rfs_chain *rchain, struct rfs_context *rcont,
		struct redirfs_args *rargs)
{
	enum redirfs_rv (*rop)(redirfs_context, struct redirfs_args *);

	if (!rchain)
		return;

	rargs->type.call = REDIRFS_POSTCALL;

	for (; rcont->idx >= rcont->idx_start; rcont->idx--) {
		if (!atomic_read(&rchain->rflts[rcont->idx]->active))
			continue;

		rop = rchain->rflts[rcont->idx]->cbs[rargs->type.id].post_cb;
		if (rop) 
			rop(rcont, rargs);
	}

	rcont->idx++;
}

static int __init rfs_init(void)
{
	int rv;

	rfs_info_none = rfs_info_alloc(NULL, NULL);
	if (IS_ERR(rfs_info_none))
		return PTR_ERR(rfs_info_none);

	rv = rfs_dentry_cache_create();
	if (rv)
		goto err_dentry_cache;

	rv = rfs_inode_cache_create();
	if (rv)
		goto err_inode_cache;

	rv = rfs_file_cache_create();
	if (rv)
		goto err_file_cache;

	rv = rfs_sysfs_create();
	if (rv)
		goto err_sysfs;

	printk(KERN_INFO "Redirecting File System Framework Version "
			REDIRFS_VERSION " <www.redirfs.org>\n");

	return 0;

err_sysfs:
	rfs_file_cache_destory();
err_file_cache:
	rfs_inode_cache_destroy();
err_inode_cache:
	rfs_dentry_cache_destory();
err_dentry_cache:
	rfs_info_put(rfs_info_none);
	return rv;
}

module_init(rfs_init);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Frantisek Hrbata <frantisek.hrbata@redirfs.org>");
MODULE_DESCRIPTION("Redirecting File System Framework Version "
		REDIRFS_VERSION " <www.redirfs.org>");

driver/redirfs/.svn/text-base/rfs_flt.c.svn-base0000644000076400007640000001333312112622747021450 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static LIST_HEAD(rfs_flt_list);
RFS_DEFINE_MUTEX(rfs_flt_list_mutex);

struct rfs_flt *rfs_flt_alloc(struct redirfs_filter_info *flt_info)
{
	struct rfs_flt *rflt;
	char *name;
	int len;
	
	len = strlen(flt_info->name);
	name = kzalloc(len + 1, GFP_KERNEL);
	if (!name)
		return ERR_PTR(-ENOMEM);

	strncpy(name, flt_info->name, len);

	rflt = kzalloc(sizeof(struct rfs_flt), GFP_KERNEL);
	if (!rflt) {
		kfree(name);
		return ERR_PTR(-ENOMEM);
	}

	INIT_LIST_HEAD(&rflt->list);
	rflt->name = name;
	rflt->priority = flt_info->priority;
	rflt->owner = flt_info->owner;
	rflt->ops = flt_info->ops;
	atomic_set(&rflt->count, 1);
	spin_lock_init(&rflt->lock);
	try_module_get(rflt->owner);

	if (flt_info->active)
		atomic_set(&rflt->active, 1);
	else
		atomic_set(&rflt->active, 0);

	return rflt;
}

struct rfs_flt *rfs_flt_get(struct rfs_flt *rflt)
{
	if (!rflt || IS_ERR(rflt))
		return NULL;

	BUG_ON(!atomic_read(&rflt->count));
	atomic_inc(&rflt->count);

	return rflt;
}

void rfs_flt_put(struct rfs_flt *rflt)
{
	if (!rflt || IS_ERR(rflt))
		return;

	BUG_ON(!atomic_read(&rflt->count));
	if (!atomic_dec_and_test(&rflt->count))
		return;

	kfree(rflt->name);
	kfree(rflt);
}

void rfs_flt_release(struct kobject *kobj)
{
	struct rfs_flt *rflt = rfs_kobj_to_rflt(kobj);

	rfs_flt_put(rflt);
}

static int rfs_flt_exist(const char *name, int priority)
{
	struct rfs_flt *rflt;

	list_for_each_entry(rflt, &rfs_flt_list, list) {
		if (rflt->priority == priority)
			return 1;

		if (!strcmp(rflt->name, name))
			return 1;
	}

	return 0;
}

redirfs_filter redirfs_register_filter(struct redirfs_filter_info *info)
{
	struct rfs_flt *rflt;
	int rv;

	might_sleep();

	if (!info)
		return ERR_PTR(-EINVAL);

	rfs_mutex_lock(&rfs_flt_list_mutex);

	if (rfs_flt_exist(info->name, info->priority)) {
		rfs_mutex_unlock(&rfs_flt_list_mutex);
		return ERR_PTR(-EEXIST);
	}

	rflt = rfs_flt_alloc(info);
	if (IS_ERR(rflt)) {
		rfs_mutex_unlock(&rfs_flt_list_mutex);
		return (redirfs_filter)rflt;
	}

	rv = rfs_flt_sysfs_init(rflt);
	if (rv) {
		rfs_flt_put(rflt);
		return ERR_PTR(rv);
	}

	list_add_tail(&rflt->list, &rfs_flt_list);
	rfs_flt_get(rflt);

	rfs_mutex_unlock(&rfs_flt_list_mutex);

	return (redirfs_filter)rflt;
}

int redirfs_unregister_filter(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	might_sleep();

	if (!rflt || IS_ERR(rflt))
		return -EINVAL;

	spin_lock(&rflt->lock);

	/*
	 * Check if the unregistration is already in progress.
	 */
	if (atomic_read(&rflt->count) < 3) {
		spin_unlock(&rflt->lock);
		return 0;
	}

	/*
	 * Filter can be unregistered only if the reference counter is equal to
	 * three. This means no one else is using it except the following.
	 *
	 *    - sysfs interface
	 *    - internal filter list
	 *    - handler returned to filter after registration
	 */
	if (atomic_read(&rflt->count) != 3) {
		spin_unlock(&rflt->lock);
		return -EBUSY;
	}

	rfs_flt_put(rflt);
	spin_unlock(&rflt->lock);

	rfs_mutex_lock(&rfs_flt_list_mutex);
	list_del_init(&rflt->list);
	rfs_mutex_unlock(&rfs_flt_list_mutex);

	module_put(rflt->owner);

	return 0;
}

void redirfs_delete_filter(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || IS_ERR(rflt))
		return;

	BUG_ON(atomic_read(&rflt->count) != 2);

	rfs_flt_sysfs_exit(rflt);
	rfs_flt_put(rflt);
}

static int rfs_flt_set_ops(struct rfs_flt *rflt)
{
	struct rfs_root *rroot;
	struct rfs_info *rinfo;
	int rv;

	list_for_each_entry(rroot, &rfs_root_list, list) {
		if (rfs_chain_find(rroot->rinfo->rchain, rflt) == -1)
			continue;

		rinfo = rfs_info_alloc(rroot, rroot->rinfo->rchain);
		if (IS_ERR(rinfo))
			return PTR_ERR(rinfo);

		rv = rfs_info_reset(rroot->dentry, rinfo);
		if (rv) {
			rfs_info_put(rinfo);
			return rv;
		}

		rfs_info_put(rroot->rinfo);
		rroot->rinfo = rinfo;
	}

	return 0;
}

int redirfs_set_operations(redirfs_filter filter, struct redirfs_op_info ops[])
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;
	int i = 0;
	int rv = 0;

	might_sleep();

	if (!rflt || IS_ERR(rflt))
		return -EINVAL;

	while (ops[i].op_id != REDIRFS_OP_END) {
		rflt->cbs[ops[i].op_id].pre_cb = ops[i].pre_cb;
		rflt->cbs[ops[i].op_id].post_cb = ops[i].post_cb;
		i++;
	}

	rfs_mutex_lock(&rfs_path_mutex);
	rv = rfs_flt_set_ops(rflt);
	rfs_mutex_unlock(&rfs_path_mutex);

	return rv;
}

int redirfs_activate_filter(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || IS_ERR(rflt))
		return -EINVAL;

	atomic_set(&rflt->active, 1);

	return 0;
}

int redirfs_deactivate_filter(redirfs_filter filter)
{
	struct rfs_flt *rflt = (struct rfs_flt *)filter;

	if (!rflt || IS_ERR(rflt))
		return -EINVAL;

	atomic_set(&rflt->active, 0);

	return 0;
}

EXPORT_SYMBOL(redirfs_register_filter);
EXPORT_SYMBOL(redirfs_unregister_filter);
EXPORT_SYMBOL(redirfs_delete_filter);
EXPORT_SYMBOL(redirfs_set_operations);
EXPORT_SYMBOL(redirfs_activate_filter);
EXPORT_SYMBOL(redirfs_deactivate_filter);

driver/redirfs/.svn/text-base/redirfs.h.svn-base0000644000076400007640000003643712112622747021466 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _REDIRFS_H
#define _REDIRFS_H

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/types.h>
#include <linux/aio.h>
#include <linux/version.h>

#define REDIRFS_VERSION "0.11 EXPERIMENTAL"

#define REDIRFS_PATH_INCLUDE		1
#define REDIRFS_PATH_EXCLUDE		2

#define REDIRFS_FILTER_ATTRIBUTE(__name, __mode, __show, __store) \
	__ATTR(__name, __mode, __show, __store)

enum redirfs_op_id {
	REDIRFS_NONE_DOP_D_REVALIDATE,
	/* REDIRFS_NONE_DOP_D_HASH, */
	REDIRFS_NONE_DOP_D_COMPARE,
	/* REDIRFS_NONE_DOP_D_DELETE, */
	REDIRFS_NONE_DOP_D_RELEASE,
	REDIRFS_NONE_DOP_D_IPUT,
	/* REDIRFS_NODE_DOP_D_NAME, */

	REDIRFS_REG_DOP_D_REVALIDATE,
	/* REDIRFS_REG_DOP_D_HASH, */
	REDIRFS_REG_DOP_D_COMPARE,
	/* REDIRFS_REG_DOP_D_DELETE, */
	REDIRFS_REG_DOP_D_RELEASE,
	REDIRFS_REG_DOP_D_IPUT,
	/* REDIRFS_REG_DOP_D_NAME, */

	REDIRFS_DIR_DOP_D_REVALIDATE,
	/* REDIRFS_DIR_DOP_D_HASH, */
	REDIRFS_DIR_DOP_D_COMPARE,
	/* REDIRFS_DIR_DOP_D_DELETE, */
	REDIRFS_DIR_DOP_D_RELEASE,
	REDIRFS_DIR_DOP_D_IPUT,
	/* REDIRFS_DIR_DOP_D_NAME, */

	REDIRFS_CHR_DOP_D_REVALIDATE,
	/* REDIRFS_CHR_DOP_D_HASH, */
	REDIRFS_CHR_DOP_D_COMPARE,
	/* REDIRFS_CHR_DOP_D_DELETE, */
	REDIRFS_CHR_DOP_D_RELEASE,
	REDIRFS_CHR_DOP_D_IPUT,
	/* REDIRFS_CHR_DOP_D_NAME, */

	REDIRFS_BLK_DOP_D_REVALIDATE,
	/* REDIRFS_BLK_DOP_D_HASH, */
	REDIRFS_BLK_DOP_D_COMPARE,
	/* REDIRFS_BLK_DOP_D_DELETE, */
	REDIRFS_BLK_DOP_D_RELEASE,
	REDIRFS_BLK_DOP_D_IPUT,
	/* REDIRFS_BLK_DOP_D_NAME, */

	REDIRFS_FIFO_DOP_D_REVALIDATE,
	/* REDIRFS_FIFO_DOP_D_HASH, */
	REDIRFS_FIFO_DOP_D_COMPARE,
	/* REDIRFS_FIFO_DOP_D_DELETE, */
	REDIRFS_FIFO_DOP_D_RELEASE,
	REDIRFS_FIFO_DOP_D_IPUT,
	/* REDIRFS_FIFO_DOP_D_NAME, */

	REDIRFS_LNK_DOP_D_REVALIDATE,
	/* REDIRFS_LNK_DOP_D_HASH, */
	REDIRFS_LNK_DOP_D_COMPARE,
	/* REDIRFS_LNK_DOP_D_DELETE, */
	REDIRFS_LNK_DOP_D_RELEASE,
	REDIRFS_LNK_DOP_D_IPUT,
	/* REDIRFS_LNK_DOP_D_NAME, */

	REDIRFS_SOCK_DOP_D_REVALIDATE,
	/* REDIRFS_SOCK_DOP_D_HASH, */
	REDIRFS_SOCK_DOP_D_COMPARE,
	/* REDIRFS_SOCK_DOP_D_DELETE, */
	REDIRFS_SOCK_DOP_D_RELEASE,
	REDIRFS_SOCK_DOP_D_IPUT,
	/* REDIRFS_SOCK_DOP_D_NAME, */

	REDIRFS_REG_IOP_PERMISSION,
	REDIRFS_REG_IOP_SETATTR,

	REDIRFS_DIR_IOP_CREATE,
	REDIRFS_DIR_IOP_LOOKUP,
	REDIRFS_DIR_IOP_LINK,
	REDIRFS_DIR_IOP_UNLINK,
	REDIRFS_DIR_IOP_SYMLINK, 
	REDIRFS_DIR_IOP_MKDIR,
	REDIRFS_DIR_IOP_RMDIR,
	REDIRFS_DIR_IOP_MKNOD,
	REDIRFS_DIR_IOP_RENAME,
	REDIRFS_DIR_IOP_PERMISSION,
	REDIRFS_DIR_IOP_SETATTR,

	REDIRFS_CHR_IOP_PERMISSION,
	REDIRFS_CHR_IOP_SETATTR,

	REDIRFS_BLK_IOP_PERMISSION,
	REDIRFS_BLK_IOP_SETATTR,

	REDIRFS_FIFO_IOP_PERMISSION,
	REDIRFS_FIFO_IOP_SETATTR,

	REDIRFS_LNK_IOP_PERMISSION,
	REDIRFS_LNK_IOP_SETATTR,

	REDIRFS_SOCK_IOP_PERMISSION,
	REDIRFS_SOCK_IOP_SETATTR,

	REDIRFS_REG_FOP_OPEN,
	REDIRFS_REG_FOP_RELEASE,
	/* REDIRFS_REG_FOP_LLSEEK, */
	/* REDIRFS_REG_FOP_READ, */
	/* REDIRFS_REG_FOP_WRITE, */
	/* REDIRFS_REG_FOP_AIO_READ, */
	/* REDIRFS_REG_FOP_AIO_WRITE, */
	/* REDIRFS_REG_FOP_MMAP, */
	/* REDIRFS_REG_FOP_FLUSH, */

	REDIRFS_DIR_FOP_OPEN,
	REDIRFS_DIR_FOP_RELEASE,
	REDIRFS_DIR_FOP_READDIR,
	/* REDIRFS_DIR_FOP_FLUSH, */

	REDIRFS_CHR_FOP_OPEN,
	REDIRFS_CHR_FOP_RELEASE,
	/* REDIRFS_CHR_FOP_LLSEEK, */
	/* REDIRFS_CHR_FOP_READ, */
	/* REDIRFS_CHR_FOP_WRITE, */
	/* REDIRFS_CHR_FOP_AIO_READ, */
	/* REDIRFS_CHR_FOP_AIO_WRITE, */
	/* REDIRFS_CHR_FOP_FLUSH, */

	REDIRFS_BLK_FOP_OPEN,
	REDIRFS_BLK_FOP_RELEASE,
	/* REDIRFS_BLK_FOP_LLSEEK, */
	/* REDIRFS_BLK_FOP_READ, */
	/* REDIRFS_BLK_FOP_WRITE, */
	/* REDIRFS_BLK_FOP_AIO_READ, */
	/* REDIRFS_BLK_FOP_AIO_WRITE, */
	/* REDIRFS_BLK_FOP_FLUSH, */

	REDIRFS_FIFO_FOP_OPEN,
	REDIRFS_FIFO_FOP_RELEASE,
	/* REDIRFS_FIFO_FOP_LLSEEK, */
	/* REDIRFS_FIFO_FOP_READ, */
	/* REDIRFS_FIFO_FOP_WRITE, */
	/* REDIRFS_FIFO_FOP_AIO_READ, */
	/* REDIRFS_FIFO_FOP_AIO_WRITE, */
	/* REDIRFS_FIFO_FOP_FLUSH, */

	REDIRFS_LNK_FOP_OPEN,
	REDIRFS_LNK_FOP_RELEASE,
	/* REDIRFS_LNK_FOP_LLSEEK, */
	/* REDIRFS_LNK_FOP_READ, */
	/* REDIRFS_LNK_FOP_WRITE, */
	/* REDIRFS_LNK_FOP_AIO_READ, */
	/* REDIRFS_LNK_FOP_AIO_WRITE, */
	/* REDIRFS_LNK_FOP_FLUSH, */

	/* REDIRFS_REG_AOP_READPAGE, */
	/* REDIRFS_REG_AOP_WRITEPAGE, */
	/* REDIRFS_REG_AOP_READPAGES, */
	/* REDIRFS_REG_AOP_WRITEPAGES, */
	/* REDIRFS_REG_AOP_SYNC_PAGE, */
	/* REDIRFS_REG_AOP_SET_PAGE_DIRTY, */
	/* REDIRFS_REG_AOP_PREPARE_WRITE, */
	/* REDIRFS_REG_AOP_COMMIT_WRITE, */
	/* REDIRFS_REG_AOP_BMAP, */
	/* REDIRFS_REG_AOP_INVALIDATEPAGE, */
	/* REDIRFS_REG_AOP_RELEASEPAGE, */
	/* REDIRFS_REG_AOP_DIRECT_IO, */
	/* REDIRFS_REG_AOP_GET_XIP_PAGE, */
	/* REDIRFS_REG_AOP_MIGRATEPAGE, */
	/* REDIRFS_REG_AOP_LAUNDER_PAGE, */

	REDIRFS_OP_END
};

enum redirfs_op_call {
	REDIRFS_PRECALL,
	REDIRFS_POSTCALL
};

enum redirfs_rv {
	REDIRFS_STOP,
	REDIRFS_CONTINUE
};

typedef void *redirfs_filter;
typedef void *redirfs_context;
typedef void *redirfs_path;
typedef void *redirfs_root;

union redirfs_op_rv {
	int		rv_int;
	ssize_t		rv_ssize;
	unsigned int	rv_uint;
	unsigned long	rv_ulong;
	loff_t		rv_loff;
	struct dentry	*rv_dentry;
	sector_t	rv_sector;
	struct page	*rv_page;
};

union redirfs_op_args {
	struct {
		struct dentry *dentry;
		struct nameidata *nd;
	} d_revalidate;	

	/*
	struct {
		struct dentry *dentry;
		struct qstr *name;
	} d_hash;
	*/

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
	struct {
		struct dentry *dentry;
		struct qstr *name1;
		struct qstr *name2;
	} d_compare;
#else
	struct {
		const struct dentry *parent;
		const struct inode *inode;
		const struct dentry *dentry;
		const struct inode *d_inode;
		unsigned int tlen;
		const char *tname;
		const struct qstr *name;
	} d_compare;
#endif

	/*
	struct {
		struct dentry *dentry;
	} d_delete;
	*/

	struct {
		struct dentry *dentry;
	} d_release;

	struct {
		struct dentry *dentry;
		struct inode *inode;
	} d_iput;	

	struct {
		struct inode *dir;
		struct dentry *dentry;
		int mode;
		struct nameidata *nd;
	} i_create;

	struct {
		struct inode *dir;
		struct dentry *dentry;
		struct nameidata *nd;
	} i_lookup;

	struct {
		struct dentry *old_dentry;
		struct inode *dir;
		struct dentry *dentry;
	} i_link;

	struct {
		struct inode *dir;
		struct dentry *dentry;
	} i_unlink;

	struct {
		struct inode *dir;
		struct dentry *dentry;
		const char *oldname;
	} i_symlink;

	struct {
		struct inode *dir;
		struct dentry *dentry;
		int mode;
	} i_mkdir;

	struct {
		struct inode *dir;
		struct dentry *dentry;
	} i_rmdir;

	struct {
		struct inode *dir;
		struct dentry *dentry;
		int mode;
		dev_t rdev;
	} i_mknod;

	struct {
		struct inode *old_dir;
		struct dentry *old_dentry;
		struct inode *new_dir;
		struct dentry *new_dentry;
	} i_rename;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
	struct {
		struct inode *inode;
		int mask;
		struct nameidata *nd;
	} i_permission;
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
	struct {
		struct inode *inode;
		int mask;
	} i_permission;
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
	struct {
		struct inode *inode;
		int mask;
		unsigned int flags;
	} i_permission;
#else
	struct {
		struct inode *inode;
		int mask;
	} i_permission;
#endif

	struct {
		struct dentry *dentry;
		struct iattr *iattr;
	} i_setattr;

	struct {
		struct inode *inode;
		struct file *file;
	} f_open;

	struct {
		struct inode *inode;
		struct file *file;
	} f_release;

	/*
	struct {
		struct file *file;
		fl_owner_t id;
	} f_flush;
	*/

	/*
	struct {
		struct file *file;
		struct vm_area_struct *vma;
	} f_mmap;
	*/

	struct {
		struct file *file;
		void *dirent;
		filldir_t filldir;
	} f_readdir;

	/*
	struct {
                struct file *file;
                loff_t offset;
                int origin;
	} f_llseek;
	*/

	/*
	struct {
		struct file *file;
		char __user *buf;
		size_t count;
		loff_t *pos;
	} f_read;
	*/

	/*
	struct {
		struct file *file;
		const char __user *buf;
		size_t count;
		loff_t *pos;
	} f_write;
	*/

	/*
	struct {
		struct kiocb *iocb;
		const struct iovec *iov;
		unsigned long nr_segs;
		loff_t pos;
	} f_aio_read;
	*/

	/*
	struct {
		struct kiocb *iocb;
		const struct iovec *iov;
		unsigned long nr_segs;
		loff_t pos;
	} f_aio_write;
	*/

	/*
	struct {
		struct file *file;
		struct page *page;
	} a_readpage;
	*/

	/*
	struct {
		struct page *page;
		struct writeback_control *wbc;
	} a_writepage;
	*/

	/*
	struct {
		struct file *file;
		struct address_space *mapping;
		struct list_head *pages;
		unsigned nr_pages;
	} a_readpages;
	*/

	/*
	struct {
		struct address_space *mapping;
		struct writeback_control *wbc;
	} a_writepages;
	*/

	/*
	struct {
		struct page *page;
	} a_sync_page;
	*/

	/*
	struct {
		struct page *page;
	} a_set_page_dirty;
	*/

	/*
	struct {
		struct file *file;
		struct page *page;
		unsigned from;
		unsigned to;
	} a_prepare_write;
	*/

	/*
	struct {
		struct file *file;
		struct page *page;
		unsigned from;
		unsigned to;
	} a_commit_write;
	*/

	/*
	struct {
		struct address_space *mapping;
		sector_t block;
	} a_bmap;
	*/

	/*
	struct {
		struct page *page;
		unsigned long offset;
	} a_invalidatepage;
	*/

	/*
	struct {
		struct page *page;
		gfp_t flags;
	} a_releasepage;
	*/

	/*
	struct {
		int rw;
		struct kiocb *iocb;
		const struct iovec *iov;
		loff_t offset;
		unsigned long nr_segs;
	} a_direct_IO;
	*/

	/*
	struct {
		struct address_space *mapping;
		sector_t offset;
		int create;
	} a_get_xip_page;
	*/

	/*
	struct {
		struct address_space *mapping;
		struct page *newpage;
		struct page *page;
	} a_migratepage;
	*/

	/*
	struct {
		struct page *page;
	} a_launder_page;
	*/
};

struct redirfs_op_type {
	enum redirfs_op_id id;
	enum redirfs_op_call call;
};

struct redirfs_args {
	union redirfs_op_args args;
	union redirfs_op_rv rv;
	struct redirfs_op_type type;
};

struct redirfs_path_info {
	struct dentry *dentry;
	struct vfsmount *mnt;
	int flags;
};

struct redirfs_op_info {
	enum redirfs_op_id op_id;
	enum redirfs_rv (*pre_cb)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv (*post_cb)(redirfs_context, struct redirfs_args *);
};

struct redirfs_filter_operations {
	int (*activate)(void);
	int (*deactivate)(void);
	int (*add_path)(struct redirfs_path_info *);
	int (*rem_path)(redirfs_path);
	int (*unregister)(void);
	int (*rem_paths)(void);
	void (*move_begin)(void);
	void (*move_end)(void);
	int (*dentry_moved)(redirfs_root, redirfs_root, struct dentry *);
	int (*inode_moved)(redirfs_root, redirfs_root, struct inode *);
	enum redirfs_rv (*pre_rename)(redirfs_context, struct redirfs_args *);
	enum redirfs_rv (*post_rename)(redirfs_context, struct redirfs_args *);
};

struct redirfs_filter_info {
	struct module *owner;
	const char *name;
	int priority;
	int active;
	struct redirfs_filter_operations *ops;
};

struct redirfs_filter_attribute {
	struct attribute attr;
	ssize_t (*show)(redirfs_filter filter,
			struct redirfs_filter_attribute *attr, char *buf);
	ssize_t (*store)(redirfs_filter filter,
			struct redirfs_filter_attribute *attr, const char *buf,
			size_t count);
};

struct redirfs_data {
	struct list_head list;
	atomic_t cnt;
	redirfs_filter filter;
	void (*free)(struct redirfs_data *);
	void (*detach)(struct redirfs_data *);
};

int redirfs_create_attribute(redirfs_filter filter,
		struct redirfs_filter_attribute *attr);
int redirfs_remove_attribute(redirfs_filter filter,
		struct redirfs_filter_attribute *attr);
struct kobject *redirfs_filter_kobject(redirfs_filter filter);
redirfs_path redirfs_add_path(redirfs_filter filter,
		struct redirfs_path_info *info);
int redirfs_rem_path(redirfs_filter filter, redirfs_path path);
int redirfs_get_id_path(redirfs_path path);
redirfs_path redirfs_get_path_id(int id);
redirfs_path redirfs_get_path(redirfs_path path);
void redirfs_put_path(redirfs_path path);
redirfs_path* redirfs_get_paths_root(redirfs_filter filter, redirfs_root root);
redirfs_path* redirfs_get_paths(redirfs_filter filter);
void redirfs_put_paths(redirfs_path *paths);
struct redirfs_path_info *redirfs_get_path_info(redirfs_filter filter,
		redirfs_path path);
void redirfs_put_path_info(struct redirfs_path_info *info);
int redirfs_rem_paths(redirfs_filter filter);
redirfs_root redirfs_get_root_file(redirfs_filter filter, struct file *file);
redirfs_root redirfs_get_root_dentry(redirfs_filter filter,
		struct dentry *dentry);
redirfs_root redirfs_get_root_inode(redirfs_filter filter, struct inode *inode);
redirfs_root redirfs_get_root_path(redirfs_path path);
redirfs_root redirfs_get_root(redirfs_root root);
void redirfs_put_root(redirfs_root root);
redirfs_filter redirfs_register_filter(struct redirfs_filter_info *info);
int redirfs_unregister_filter(redirfs_filter filter);
void redirfs_delete_filter(redirfs_filter filter);
int redirfs_set_operations(redirfs_filter filter, struct redirfs_op_info ops[]);
int redirfs_activate_filter(redirfs_filter filter);
int redirfs_deactivate_filter(redirfs_filter filter);
int redirfs_get_filename(struct vfsmount *mnt, struct dentry *dentry, char *buf,
		int size);
int redirfs_init_data(struct redirfs_data *data, redirfs_filter filter,
		void (*free)(struct redirfs_data *),
		void (*detach)(struct redirfs_data *));
struct redirfs_data *redirfs_get_data(struct redirfs_data *data);
void redirfs_put_data(struct redirfs_data *data);
struct redirfs_data *redirfs_attach_data_file(redirfs_filter filter,
		struct file *file, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_file(redirfs_filter filter,
		struct file *file);
struct redirfs_data *redirfs_get_data_file(redirfs_filter filter,
		struct file *file);
struct redirfs_data *redirfs_attach_data_dentry(redirfs_filter filter,
		struct dentry *dentry, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_dentry(redirfs_filter filter,
		struct dentry *dentry);
struct redirfs_data *redirfs_get_data_dentry(redirfs_filter filter,
		struct dentry *dentry);
struct redirfs_data *redirfs_attach_data_inode(redirfs_filter filter,
		struct inode *inode, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_inode(redirfs_filter filter,
		struct inode *inode);
struct redirfs_data *redirfs_get_data_inode(redirfs_filter filter,
		struct inode *inode);
struct redirfs_data *redirfs_attach_data_context(redirfs_filter filter,
		redirfs_context context, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_context(redirfs_filter filter,
		redirfs_context context);
struct redirfs_data *redirfs_get_data_context(redirfs_filter filter,
		redirfs_context context);
struct redirfs_data *redirfs_attach_data_root(redirfs_filter filter,
		redirfs_root root, struct redirfs_data *data);
struct redirfs_data *redirfs_detach_data_root(redirfs_filter filter,
		redirfs_root root);
struct redirfs_data *redirfs_get_data_root(redirfs_filter filter,
		redirfs_root root);
#endif

driver/redirfs/.svn/text-base/rfs_chain.c.svn-base0000644000076400007640000001310412112622747021741 0ustar  comodocomodo/*
 * RedirFS: Redirecting File System
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "rfs.h"

static struct rfs_chain *rfs_chain_alloc(int size, int type)
{
	struct rfs_chain *rchain;
	struct rfs_flt **rflts;

	rchain = kzalloc(sizeof(struct rfs_chain), type);
	rflts = kzalloc(sizeof(struct rfs_flt*) * size, type);
	if (!rchain || !rflts) {
		kfree(rchain);
		kfree(rflts);
		return ERR_PTR(-ENOMEM);
	}

	rchain->rflts = rflts;
	rchain->rflts_nr = size;
	atomic_set(&rchain->count, 1);

	return rchain;
}

struct rfs_chain *rfs_chain_get(struct rfs_chain *rchain)
{
	if (!rchain || IS_ERR(rchain))
		return NULL;

	BUG_ON(!atomic_read(&rchain->count));
	atomic_inc(&rchain->count);

	return rchain;
}

void rfs_chain_put(struct rfs_chain *rchain)
{
	int i;

	if (!rchain || IS_ERR(rchain))
		return;

	BUG_ON(!atomic_read(&rchain->count));
	if (!atomic_dec_and_test(&rchain->count))
		return;

	for (i = 0; i < rchain->rflts_nr; i++)
		rfs_flt_put(rchain->rflts[i]);

	kfree(rchain->rflts);
	kfree(rchain);
}

int rfs_chain_find(struct rfs_chain *rchain, struct rfs_flt *rflt)
{
	int i;

	if (!rchain)
		return -1;

	for (i = 0; i < rchain->rflts_nr; i++) {
		if (rchain->rflts[i] == rflt)
			return i;
	}

	return -1;
}

struct rfs_chain *rfs_chain_add(struct rfs_chain *rchain, struct rfs_flt *rflt)
{
	struct rfs_chain *rchain_new;
	int size;
	int i = 0;
	int j = 0;

	if (rfs_chain_find(rchain, rflt) != -1)
		return rfs_chain_get(rchain);

	if (!rchain) 
		size = 1;
	else
		size = rchain->rflts_nr + 1;

	rchain_new = rfs_chain_alloc(size, GFP_KERNEL);
	if (IS_ERR(rchain_new))
		return rchain_new;

	if (!rchain) {
		rchain_new->rflts[0] = rfs_flt_get(rflt);
		return rchain_new;
	}

	while (rchain->rflts[i]->priority < rflt->priority) {
		rchain_new->rflts[j++] = rfs_flt_get(rchain->rflts[i++]);
		if (i == rchain->rflts_nr)
			break;
	}

	rchain_new->rflts[j++] = rfs_flt_get(rflt);

	while (j < rchain_new->rflts_nr) {
		rchain_new->rflts[j++] = rfs_flt_get(rchain->rflts[i++]);
	}

	return rchain_new;
}

struct rfs_chain *rfs_chain_rem(struct rfs_chain *rchain, struct rfs_flt *rflt)
{
	struct rfs_chain *rchain_new;
	int i, j;

	if (rfs_chain_find(rchain, rflt) == -1)
		return rfs_chain_get(rchain);

	if (rchain->rflts_nr == 1)
		return NULL;

	rchain_new = rfs_chain_alloc(rchain->rflts_nr - 1, GFP_KERNEL);
	if (IS_ERR(rchain_new))
		return rchain_new;

	for (i = 0, j = 0; i < rchain->rflts_nr; i++) {
		if (rchain->rflts[i] != rflt)
			rchain_new->rflts[j++] = rfs_flt_get(rchain->rflts[i]);
	}

	return rchain_new;
}

void rfs_chain_ops(struct rfs_chain *rchain, struct rfs_ops *rops)
{
	int i, j;

	if (!rchain)
		return;

	for (i = 0; i < rchain->rflts_nr; i++) {
		for (j = 0; j < REDIRFS_OP_END; j++) {
			if (rchain->rflts[i]->cbs[j].pre_cb)
				rops->arr[j]++;
			if (rchain->rflts[i]->cbs[j].post_cb)
				rops->arr[j]++;
		}
	}
}

int rfs_chain_cmp(struct rfs_chain *rch1, struct rfs_chain *rch2)
{
	int i;

	if (!rch1 && !rch2)
		return 0;

	if (!rch1 || !rch2)
		return -1;

	if (rch1->rflts_nr != rch2->rflts_nr)
		return -1;

	for (i = 0; i < rch1->rflts_nr; i++) {
		if (rch1->rflts[i] != rch2->rflts[i])
			return -1;
	}

	return 0;
}

struct rfs_chain *rfs_chain_join(struct rfs_chain *rch1, struct rfs_chain *rch2)
{
	struct rfs_chain *rch;
	int size;
	int i,k,l;

	if (!rch1 && !rch2)
		return NULL;

	if (!rch1)
		return rfs_chain_get(rch2);

	if (!rch2)
		return rfs_chain_get(rch1);

	if (!rfs_chain_cmp(rch1, rch2))
		return rfs_chain_get(rch1);

	size = rch1->rflts_nr;

	for (i = 0; i < rch2->rflts_nr; i++) {
		if (rfs_chain_find(rch1, rch2->rflts[i]) == -1)
			size++;
	}

	rch = rfs_chain_alloc(size, GFP_KERNEL);
	if (IS_ERR(rch))
		return rch;

	i = k = l = 0;
	while (k != rch1->rflts_nr && l != rch2->rflts_nr) {
		if (rch1->rflts[k]->priority == rch2->rflts[l]->priority) {
			rch->rflts[i++] = rfs_flt_get(rch1->rflts[k++]);
			l++;
		} else if (rch1->rflts[k]->priority < rch2->rflts[l]->priority) {
			rch->rflts[i++] = rfs_flt_get(rch1->rflts[k++]);
		} else
			rch->rflts[i++] = rfs_flt_get(rch2->rflts[l++]);
	}

	while (k != rch1->rflts_nr)
		rch->rflts[i++] = rfs_flt_get(rch1->rflts[k++]);

	while (l != rch2->rflts_nr)
		rch->rflts[i++] = rfs_flt_get(rch2->rflts[l++]);

	return rch;
}

struct rfs_chain *rfs_chain_diff(struct rfs_chain *rch1, struct rfs_chain *rch2)
{
	struct rfs_chain *rch;
	int size;
	int i,j;

	if (!rch1)
		return NULL;

	if (!rch2)
		return rfs_chain_get(rch1);

	size = rch1->rflts_nr;

	for (i = 0; i < rch1->rflts_nr; i++) {
		if (rfs_chain_find(rch2, rch1->rflts[i]) != -1)
			size--;
	}

	if (!size)
		return NULL;

	if (size == rch1->rflts_nr)
		return rfs_chain_get(rch1);

	rch = rfs_chain_alloc(size, GFP_KERNEL);
	if (IS_ERR(rch))
		return rch;

	for (i = 0, j = 0; i < rch1->rflts_nr; i++) {
		if (rfs_chain_find(rch2, rch1->rflts[i]) == -1)
			rch->rflts[j++] = rfs_flt_get(rch1->rflts[i]);
	}

	BUG_ON(j != size);

	return rch;
}

driver/redirfs/.svn/props/0000755000076400007640000000000012112622747015374 5ustar  comodocomododriver/redirfs/.svn/entries0000644000076400007640000000676612112622747015644 0ustar  comodocomodo10

dir
268025
https://svn.mcr.colo.comodoca.net/svn/repos/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs
https://svn.mcr.colo.comodoca.net/svn/repos



2011-11-18T07:31:50.813877Z
216573
yangb














03944601-d801-0410-bf24-f2e5d3b8ba88

rfs_flt.c
file




2013-02-18T02:00:38.000000Z
36fae09a965cd7dc0efca898b00053ef
2011-07-01T08:28:03.926547Z
196014
chenpeng





















5851

rfs.h
file




2013-02-18T02:00:38.000000Z
f501917a5ca0e702abb547f2d97643db
2011-11-18T07:31:50.813877Z
216573
yangb





















16830

redirfs.h
file




2013-02-18T02:00:38.000000Z
2f2285ee0cb370250241247466bbd020
2011-11-18T07:31:50.813877Z
216573
yangb





















15647

rfs_info.c
file




2013-02-18T02:00:38.000000Z
b681066d95d9ff28e2eb94e4407b4488
2011-11-18T07:31:50.813877Z
216573
yangb





















8949

CHANGELOG
file




2013-02-18T02:00:38.000000Z
43090c496ee8bebae3a7a44ab0ee449a
2011-11-18T07:31:50.813877Z
216573
yangb





















5933

rfs_path.c
file




2013-02-18T02:00:38.000000Z
64d4a792597fbbbc88841fed8aded908
2011-11-18T07:31:50.813877Z
216573
yangb





















18837

.svnignore
file




2013-02-18T02:00:38.000000Z
e570c45821dbd635dd7367289a2ea537
2011-07-01T08:28:03.926547Z
196014
chenpeng





















45

rfs_inode.c
file




2013-02-18T02:00:38.000000Z
aa7b3f817a3fe6ec12a595120a1ca653
2011-11-18T07:31:50.813877Z
216573
yangb





















27397

rfs_ops.c
file




2013-02-18T02:00:38.000000Z
6ca134a3bf905b43f6873142513de8c4
2011-07-01T08:28:03.926547Z
196014
chenpeng





















1578

README
file




2013-02-18T02:00:38.000000Z
aa5c17847067e415a916478e000e1d8d
2011-07-01T08:28:03.926547Z
196014
chenpeng





















1249

rfs_dentry.c
file




2013-02-18T02:00:38.000000Z
32ce04c05ad4549fb08acfc661c3acc1
2011-11-18T07:31:50.813877Z
216573
yangb





















16222

rfs_dcache.c
file




2013-02-18T02:00:38.000000Z
54f7c397b7927265c5399f5729ba0a6b
2011-11-18T07:31:50.813877Z
216573
yangb





















9115

rfs_sysfs.c
file




2013-02-18T02:00:38.000000Z
28b43a26d2ba44152fd702a5453ca2c1
2011-11-18T07:31:50.813877Z
216573
yangb





















13295

rfs_data.c
file




2013-02-18T02:00:38.000000Z
fb76ef92508ca22709ac789f52d230de
2011-11-18T07:31:50.813877Z
216573
yangb





















10406

TODO
file




2013-02-18T02:00:38.000000Z
6ccb73f6d04d6371327ced1d3dd19a9a
2011-07-01T08:28:03.926547Z
196014
chenpeng





















207

INSTALL
file




2013-02-18T02:00:38.000000Z
9136ad607b36fc44fe762a5eaadb2ba7
2011-07-01T08:28:03.926547Z
196014
chenpeng





















1056

COPYING
file




2013-02-18T02:00:38.000000Z
d32239bcb673463ab874e80d47fae504
2011-07-01T08:28:03.926547Z
196014
chenpeng





















35147

rfs_file.c
file




2013-02-18T02:00:38.000000Z
beacea9e7ea75aa56de537b26042859a
2011-07-01T08:28:03.926547Z
196014
chenpeng





















8179

rfs.c
file




2013-02-18T02:00:38.000000Z
0ef2b79dcbee809ca62b9c93be33a04e
2011-07-01T08:28:03.926547Z
196014
chenpeng





















2917

rfs_chain.c
file




2013-02-18T02:00:38.000000Z
3ebfac585721c2f4533287d40adaf2a2
2011-07-01T08:28:03.926547Z
196014
chenpeng





















5700

Makefile
file




2013-02-18T02:00:38.000000Z
05fdc6a6b995cc63550cb8efcf048e06
2011-07-01T08:28:03.926547Z
196014
chenpeng





















185

rfs_root.c
file




2013-02-18T02:00:38.000000Z
f0cee79098d1d6cfac4a803fbacfb36e
2011-07-01T08:28:03.926547Z
196014
chenpeng





















11140

driver/redirfs/.svn/prop-base/0000755000076400007640000000000012112622747016121 5ustar  comodocomododriver/redirfs/.svn/all-wcprops0000644000076400007640000000635512112622747016430 0ustar  comodocomodoK 25
svn:wc:ra_dav:version-url
V 84
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs
END
rfs_flt.c
K 25
svn:wc:ra_dav:version-url
V 94
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_flt.c
END
rfs.h
K 25
svn:wc:ra_dav:version-url
V 90
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs.h
END
redirfs.h
K 25
svn:wc:ra_dav:version-url
V 94
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/redirfs.h
END
rfs_info.c
K 25
svn:wc:ra_dav:version-url
V 95
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_info.c
END
CHANGELOG
K 25
svn:wc:ra_dav:version-url
V 94
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/CHANGELOG
END
rfs_path.c
K 25
svn:wc:ra_dav:version-url
V 95
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_path.c
END
.svnignore
K 25
svn:wc:ra_dav:version-url
V 95
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/.svnignore
END
rfs_inode.c
K 25
svn:wc:ra_dav:version-url
V 96
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_inode.c
END
rfs_ops.c
K 25
svn:wc:ra_dav:version-url
V 94
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_ops.c
END
README
K 25
svn:wc:ra_dav:version-url
V 91
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/README
END
rfs_dentry.c
K 25
svn:wc:ra_dav:version-url
V 97
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_dentry.c
END
rfs_dcache.c
K 25
svn:wc:ra_dav:version-url
V 97
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_dcache.c
END
rfs_sysfs.c
K 25
svn:wc:ra_dav:version-url
V 96
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_sysfs.c
END
rfs_data.c
K 25
svn:wc:ra_dav:version-url
V 95
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_data.c
END
TODO
K 25
svn:wc:ra_dav:version-url
V 89
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/TODO
END
INSTALL
K 25
svn:wc:ra_dav:version-url
V 92
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/INSTALL
END
COPYING
K 25
svn:wc:ra_dav:version-url
V 92
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/COPYING
END
rfs_file.c
K 25
svn:wc:ra_dav:version-url
V 95
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_file.c
END
rfs.c
K 25
svn:wc:ra_dav:version-url
V 90
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs.c
END
rfs_chain.c
K 25
svn:wc:ra_dav:version-url
V 96
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_chain.c
END
Makefile
K 25
svn:wc:ra_dav:version-url
V 93
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/Makefile
END
rfs_root.c
K 25
svn:wc:ra_dav:version-url
V 95
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/redirfs/rfs_root.c
END
driver/redirfs/.svn/tmp/0000755000076400007640000000000012112622747015031 5ustar  comodocomododriver/redirfs/.svn/tmp/text-base/0000755000076400007640000000000012112622747016725 5ustar  comodocomododriver/redirfs/.svn/tmp/props/0000755000076400007640000000000012112622747016174 5ustar  comodocomododriver/redirfs/.svn/tmp/prop-base/0000755000076400007640000000000012112622747016721 5ustar  comodocomododriver/avflt/0000755000076400007640000000000012112622747013023 5ustar  comodocomododriver/avflt/avflt_rfs.c0000644000076400007640000001163712112622747015165 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static int avflt_should_check(struct file *file)
{
	if (avflt_is_stopped())
		return 0;

	if (avflt_proc_allow(current->tgid))
		return 0;

	if (avflt_trusted_allow(current->tgid))
		return 0;
	
	if (!file->f_dentry->d_inode)
		return 0;

	if (!i_size_read(file->f_dentry->d_inode))
		return 0;

	return 1;
}

static int avflt_check_cache(struct file *file, int type)
{
	struct avflt_root_data *root_data;
	struct avflt_inode_data *inode_data;
	int state = 0;
	int wc;

	if (!atomic_read(&avflt_cache_enabled))
		return 0;

	root_data = avflt_get_root_data_inode(file->f_dentry->d_inode);
	if (!root_data)
		return 0;

	if (!atomic_read(&root_data->cache_enabled)) {
		avflt_put_root_data(root_data);
		return 0;
	}

	inode_data = avflt_get_inode_data_inode(file->f_dentry->d_inode);
	if (!inode_data) {
		avflt_put_root_data(root_data);
		return 0;
	}

	wc = atomic_read(&file->f_dentry->d_inode->i_writecount);

	spin_lock(&inode_data->lock);

	if (wc == 1) {
		if (!(file->f_mode & FMODE_WRITE))
			inode_data->inode_cache_ver++;

		else if (type == AVFLT_EVENT_CLOSE)
			inode_data->inode_cache_ver++;

	} else if (wc > 1)
		inode_data->inode_cache_ver++;

	if (inode_data->root_data != root_data)
		goto exit;

	if (inode_data->root_cache_ver != atomic_read(&root_data->cache_ver))
		goto exit;

	if (inode_data->cache_ver != inode_data->inode_cache_ver)
		goto exit;

	state = inode_data->state;
exit:
	spin_unlock(&inode_data->lock);
	avflt_put_inode_data(inode_data);
	avflt_put_root_data(root_data);
	return state;
}

static enum redirfs_rv avflt_eval_res(int rv, struct redirfs_args *args)
{
	if (rv < 0) {
		args->rv.rv_int = rv;
		return REDIRFS_STOP;
	} 

	if (rv == AVFLT_FILE_INFECTED) {
		args->rv.rv_int = -EPERM;
		return REDIRFS_STOP;
	}

	return REDIRFS_CONTINUE;
}

static enum redirfs_rv avflt_check_file(struct file *file, int type,
		struct redirfs_args *args)
{
	int rv;

	if (!avflt_should_check(file))
		return REDIRFS_CONTINUE;

	rv = avflt_check_cache(file, type);
	if (rv)
		return avflt_eval_res(rv, args);

	rv = avflt_process_request(file, type);
	if (rv)
		return avflt_eval_res(rv, args);

	return REDIRFS_CONTINUE;
}

static enum redirfs_rv avflt_pre_open(redirfs_context context,
		struct redirfs_args *args)
{
	struct file *file = args->args.f_open.file;

	return avflt_check_file(file, AVFLT_EVENT_OPEN, args);
}

static enum redirfs_rv avflt_post_release(redirfs_context context,
		struct redirfs_args *args)
{
	struct file *file = args->args.f_release.file;

	return avflt_check_file(file, AVFLT_EVENT_CLOSE, args);
}

static int avflt_activate(void)
{
	avflt_invalidate_cache();
	return redirfs_activate_filter(avflt);
}

static int avflt_add_path(struct redirfs_path_info *info)
{
	struct avflt_root_data *data;
	redirfs_path path;
	redirfs_root root;

	path = redirfs_add_path(avflt, info);
	if (IS_ERR(path))
		return PTR_ERR(path);

	root = redirfs_get_root_path(path);
	redirfs_put_path(path);
	if (!root)
		return 0;

	data = avflt_attach_root_data(root);

	redirfs_put_root(root);
	avflt_put_root_data(data);
	
	return 0;
}

redirfs_filter avflt;

static struct redirfs_filter_operations avflt_ops = {
	.activate = avflt_activate,
	.add_path = avflt_add_path
};

static struct redirfs_filter_info avflt_info = {
	.owner = THIS_MODULE,
	.name = "avflt",
	.priority = 850000000,
	.active = 1,
	.ops = &avflt_ops
};

static struct redirfs_op_info avflt_op_info[] = {
	{REDIRFS_REG_FOP_OPEN, avflt_pre_open, NULL},
	{REDIRFS_REG_FOP_RELEASE, avflt_post_release, NULL},
	{REDIRFS_OP_END, NULL, NULL}
};

int avflt_rfs_init(void)
{
	int err;
	int rv;

	avflt = redirfs_register_filter(&avflt_info);
	if (IS_ERR(avflt)) {
		rv = PTR_ERR(avflt);
		printk(KERN_ERR "avflt: register filter failed(%d)\n", rv);
		return rv;
	}

	rv = redirfs_set_operations(avflt, avflt_op_info);
	if (rv) {
		printk(KERN_ERR "avflt: set operations failed(%d)\n", rv);
		goto error;
	}

	return 0;
error:
	err = redirfs_unregister_filter(avflt);
	if (err) {
		printk(KERN_ERR "avflt: unregister filter failed(%d)\n", err);
		return 0;
	}

	redirfs_delete_filter(avflt);
	return rv;
}

void avflt_rfs_exit(void)
{
	redirfs_delete_filter(avflt);
}

driver/avflt/README0000644000076400007640000000151712112622747013707 0ustar  comodocomodo		=========================
		AVFlt - Anti-Virus Filter
			  README
		=========================

This software is distributed under the GNU General Public License Version 3.

1. Introduction

	AVFlt or Anti-Virus Filter is a filter for the RedirFS Framework. It is
	intended for so-called on-access scanning, which means that files are 
	checked for malicious content on-the-fly before open and after close.
	AVFlt uses in kernel cache and it makes sure than only changed files are
	checked. It comes hand in hand with the libav library which should be
	used by Anti-Virus scanners.

	For an overview of the RedirFS project, visit 

		http://www.redirfs.org

2. Installation

	See the INSTALL file.

3. Documentation

	http://www.redirfs.org/tiki-index.php?page=redirfs_doc

4. Problems & Bugs
	
	http://www.redirfs.org/cgi-bin/bugzilla/index.cgi
driver/avflt/avflt_dev.c0000644000076400007640000001026012112622747015140 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static struct class *avflt_class;
static struct device *avflt_device;
static dev_t avflt_dev;

static int avflt_dev_open_registered(struct inode *inode, struct file *file)
{
	struct avflt_proc *proc;

	if (avflt_proc_empty())
		avflt_invalidate_cache();

	proc = avflt_proc_add(current->tgid);
	if (IS_ERR(proc))
		return PTR_ERR(proc);

	avflt_proc_put(proc);
	avflt_start_accept();
	return 0;
}

static int avflt_dev_open_trusted(struct inode *inode, struct file *file)
{
	return avflt_trusted_add(current->tgid);
}

static int avflt_dev_open(struct inode *inode, struct file *file)
{
	if (file->f_mode & FMODE_WRITE)
		return avflt_dev_open_registered(inode, file);

	return avflt_dev_open_trusted(inode, file);
}

static int avflt_dev_release_registered(struct inode *inode, struct file *file)
{
	avflt_proc_rem(current->tgid);
	if (!avflt_proc_empty())
		return 0;

	avflt_stop_accept();
	avflt_rem_requests();
	return 0;
}

static int avflt_dev_release_trusted(struct inode *inode, struct file *file)
{
	avflt_trusted_rem(current->tgid);
	return 0;
}

static int avflt_dev_release(struct inode *inode, struct file *file)
{
	if (file->f_mode & FMODE_WRITE)
		return avflt_dev_release_registered(inode, file);

	return avflt_dev_release_trusted(inode, file);
}

static ssize_t avflt_dev_read(struct file *file, char __user *buf,
		size_t size, loff_t *pos)
{
	struct avflt_event *event;
	ssize_t len;
	ssize_t rv;

	if (!(file->f_mode & FMODE_WRITE))
		return -EINVAL;

	event = avflt_get_request();
	if (!event)
		return 0;

	rv = avflt_get_file(event);
	if (rv)
		goto error;

	rv = len = avflt_copy_cmd(buf, size, event);
	if (rv < 0)
		goto error;

	rv = avflt_add_reply(event);
	if (rv)
		goto error;

	avflt_install_fd(event);
	avflt_event_put(event);
	return len;
error:
	avflt_put_file(event);
	avflt_readd_request(event);
	avflt_event_put(event);
	return rv;
}

static ssize_t avflt_dev_write(struct file *file, const char __user *buf,
		size_t size, loff_t *pos)
{
	struct avflt_event *event;

	event = avflt_get_reply(buf, size);
	if (IS_ERR(event))
		return PTR_ERR(event);

	avflt_event_done(event);
	avflt_event_put(event);
	return size;
}

static unsigned int avflt_poll(struct file *file, poll_table *wait)
{
	unsigned int mask;

	poll_wait(file, &avflt_request_available, wait);

	mask = POLLOUT | POLLWRNORM;

	if (!avflt_request_empty())
		mask |= POLLIN | POLLRDNORM;

	return mask;
}

static struct file_operations avflt_fops = {
	.owner = THIS_MODULE,
	.open = avflt_dev_open,
	.release = avflt_dev_release,
	.read = avflt_dev_read,
	.write = avflt_dev_write,
	.poll = avflt_poll
};

int avflt_dev_init(void)
{
	int major;

	major = register_chrdev(0, "avflt", &avflt_fops);
	if (major < 0)
		return major;

	avflt_dev = MKDEV(major, 0);

	avflt_class = class_create(THIS_MODULE, "avflt");
	if (IS_ERR(avflt_class)) {
		unregister_chrdev(major, "avflt");
		return PTR_ERR(avflt_class);
	}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
	avflt_device = device_create(avflt_class, NULL, avflt_dev, "avflt");
#else
	avflt_device = device_create(avflt_class, NULL, avflt_dev, NULL, "avflt");
#endif
	if (IS_ERR(avflt_device)) {
		class_destroy(avflt_class);
		unregister_chrdev(major, "avflt");
		return PTR_ERR(avflt_device);
	}

	return 0;
}

void avflt_dev_exit(void)
{
	device_destroy(avflt_class, avflt_dev);
	class_destroy(avflt_class);
	unregister_chrdev(MAJOR(avflt_dev), "avflt");
}

driver/avflt/COPYING0000644000076400007640000010451312112622747014062 0ustar  comodocomodo                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
driver/avflt/CHANGELOG0000644000076400007640000000271412112622747014241 0ustar  comodocomodoversion 0.6 2010-05-20
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- reflected changes in 2.6.34 kernel
		- include of <linux/slab.h>

version 0.5 2010-04-09
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed memory leak in avflt_proc_add()
	  thanks to Robert Minsk <robertminsk@yahoo.com>
	- proper canceling of pending requests when application is unregistered
	  form avflt
	  thanks to Timo Metsala <timo.metsala@f-secure.com>
	- user-space <==> kernel protocol extended for cache option
	  0 - do not cache cache event result
	  1 - cache event result
	  This is intended to be used by the user-space anti-virus applications
	  when a file cannot be scanned or when an error occurred during scan.
	  In this case application can allow or deny access to the file and it
	  should set the result to not be cached. Next time the file is accessed
	  it is send again for scan instead of returning result from cache.

version 0.4
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- dentry_open adapted to new 2.6.29 security context - struct cred
	- added support for "trusted" processes
	- added sysfs interface for registered and trusted processes

version 0.3
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- better fix of open for files bigger then 2GB
	  O_LARGEFILE flag is set base on original f_flags

version 0.2
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed open for files bigger then 2GB(MAX_NON_LFS)

version 0.1
	* initial release

driver/avflt/avflt.h0000644000076400007640000001170612112622747014315 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _AVFLT_H
#define _AVFLT_H

#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <linux/mount.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
#include <linux/freezer.h>
#endif
#include <linux/fs.h>
#include <linux/slab.h>
#include <rfs.h>

#define AVFLT_VERSION	"0.6"

#define AVFLT_EVENT_OPEN	1
#define AVFLT_EVENT_CLOSE	2

#define AVFLT_FILE_CLEAN	1
#define AVFLT_FILE_INFECTED	2

struct avflt_event {
	struct list_head req_list;
	struct list_head proc_list;
	struct avflt_root_data *root_data;
	struct completion wait;
	atomic_t count;
	int type;
	int id;
	int result;
	struct vfsmount *mnt;
	struct dentry *dentry;
	unsigned int flags;
	struct file *file;
	int fd;
	int root_cache_ver;
	int cache_ver;
	int cache;
	pid_t pid;
	pid_t tgid;
};

struct avflt_event *avflt_event_get(struct avflt_event *event);
void avflt_event_put(struct avflt_event *event);
void avflt_readd_request(struct avflt_event *event);
struct avflt_event *avflt_get_request(void);
int avflt_process_request(struct file *file, int type);
void avflt_event_done(struct avflt_event *event);
int avflt_get_file(struct avflt_event *event);
void avflt_put_file(struct avflt_event *event);
void avflt_install_fd(struct avflt_event *event);
ssize_t avflt_copy_cmd(char __user *buf, size_t size,
		struct avflt_event *event);
int avflt_add_reply(struct avflt_event *event);
int avflt_request_empty(void);
void avflt_start_accept(void);
void avflt_stop_accept(void);
int avflt_is_stopped(void);
void avflt_rem_requests(void);
struct avflt_event *avflt_get_reply(const char __user *buf, size_t size);
int avflt_check_init(void);
void avflt_check_exit(void);

struct avflt_trusted {
	struct list_head list;
	pid_t tgid;
	int open;
};

int avflt_trusted_add(pid_t tgid);
void avflt_trusted_rem(pid_t tgid);
int avflt_trusted_allow(pid_t tgid);
ssize_t avflt_trusted_get_info(char *buf, int size);

struct avflt_proc {
	struct list_head list;
	struct list_head events; 
	spinlock_t lock;
	atomic_t count;
	pid_t tgid;
	int open;
};

struct avflt_proc *avflt_proc_get(struct avflt_proc *proc);
void avflt_proc_put(struct avflt_proc *proc);
struct avflt_proc *avflt_proc_find(pid_t tgid);
struct avflt_proc *avflt_proc_add(pid_t tgid);
void avflt_proc_rem(pid_t tgid);
int avflt_proc_allow(pid_t tgid);
int avflt_proc_empty(void);
void avflt_proc_add_event(struct avflt_proc *proc, struct avflt_event *event);
void avflt_proc_rem_event(struct avflt_proc *proc, struct avflt_event *event);
struct avflt_event *avflt_proc_get_event(struct avflt_proc *proc, int id);
ssize_t avflt_proc_get_info(char *buf, int size);

#define rfs_to_root_data(ptr) \
	container_of(ptr, struct avflt_root_data, rfs_data)

struct avflt_root_data {
	struct redirfs_data rfs_data;
	atomic_t cache_enabled;
	atomic_t cache_ver;
};

struct avflt_root_data *avflt_get_root_data_root(redirfs_root root);
struct avflt_root_data *avflt_get_root_data_inode(struct inode *inode);
struct avflt_root_data *avflt_get_root_data(struct avflt_root_data *data);
void avflt_put_root_data(struct avflt_root_data *data);
struct avflt_root_data *avflt_attach_root_data(redirfs_root root);

#define rfs_to_inode_data(ptr) \
	container_of(ptr, struct avflt_inode_data, rfs_data)

struct avflt_inode_data {
	struct redirfs_data rfs_data;
	struct avflt_root_data *root_data;
	int root_cache_ver;
	int inode_cache_ver;
	int cache_ver;
	int state;
	spinlock_t lock;
};

struct avflt_inode_data *avflt_get_inode_data_inode(struct inode *inode);
struct avflt_inode_data *avflt_get_inode_data(struct avflt_inode_data *data);
void avflt_put_inode_data(struct avflt_inode_data *data);
struct avflt_inode_data *avflt_attach_inode_data(struct inode *inode);
int avflt_data_init(void);
void avflt_data_exit(void);

void avflt_invalidate_cache_root(redirfs_root root);
void avflt_invalidate_cache(void);

int avflt_dev_init(void);
void avflt_dev_exit(void);

int avflt_rfs_init(void);
void avflt_rfs_exit(void);

int avflt_sys_init(void);
void avflt_sys_exit(void);

extern atomic_t avflt_reply_timeout;
extern atomic_t avflt_cache_enabled;
extern redirfs_filter avflt;
extern wait_queue_head_t avflt_request_available;

#endif

driver/avflt/INSTALL0000644000076400007640000000267112112622747014062 0ustar  comodocomodo			======================================
				 Installing AVFlt
			======================================

1. Requirements
	
	* Running Linux kernel version 2.6.25 and higher
	* Source code and configuration for running Linux kernel
	  - at least make scripts and make prepare
	* Linux kernel compiled with modules support
	* Compiled RedirFS Framework, please see the RedirFS's INSTALL file

2. Download
	
	* Get the latest stable version at
	  http://www.redirfs.org/packages/avflt-x.y.tar.gz

3. Compilation
	
	* Unpack package
		$ tar -xvzf avflt-x.y.tar.gz

	* Change to the avflt-x.y directory
		$ cd avflt-x.y

	* Copy the RedirFS's Module.symvers file to the AVFlt source tree.
	  For more info please see Documentation/kbuild/modules.txt
	  section "7.3 Symbols from another external module".
		$ cp <path to the RedirFS's source tree>/Module.symvers .

	* Run make command
		$ make -C /lib/modules/`uname -r`/build M=`pwd` \
			EXTRA_CFLAGS=-I<full path to the redirfs dir> modules

4. Inserting module

	* Change user to root
		$ su

	* Install modules 
		# make -C /lib/modules/`uname -r`/build M=`pwd` \
			EXTRA_CFLAGS=-I<full path to the redirfs dir> \
			modules_install

	* Update module dependencies
		# depmod -a

	* Load avflt.ko module
		# modprobe avflt

5. Problems & Bugs

	* RedirFS's bugzilla
	  http://www.redirfs.org/cgi-bin/bugzilla/index.cgi
	
	* RedirFS's mailing lists
	  http://www.redirfs.org/tiki-index.php?page=redirfs_maillists
driver/avflt/avflt_proc.c0000644000076400007640000001504612112622747015334 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static LIST_HEAD(avflt_proc_list);
static DEFINE_SPINLOCK(avflt_proc_lock);

static LIST_HEAD(avflt_trusted_list);
static DEFINE_SPINLOCK(avflt_trusted_lock);

static struct avflt_trusted *avflt_trusted_alloc(pid_t tgid)
{
	struct avflt_trusted *trusted;

	trusted = kzalloc(sizeof(struct avflt_trusted), GFP_KERNEL);
	if (!trusted)
		return ERR_PTR(-ENOMEM);

	trusted->tgid = tgid;
	trusted->open = 1;

	return trusted;
}

static void avflt_trusted_free(struct avflt_trusted *trusted)
{
	kfree(trusted);
}

static struct avflt_trusted *avflt_trusted_find(pid_t tgid)
{
	struct avflt_trusted *trusted;

	list_for_each_entry(trusted, &avflt_trusted_list, list) {
		if (trusted->tgid == tgid)
			return trusted;
	}

	return NULL;
}

int avflt_trusted_add(pid_t tgid)
{
	struct avflt_trusted *trusted;
	struct avflt_trusted *found;

	trusted = avflt_trusted_alloc(tgid);
	if (IS_ERR(trusted))
		return PTR_ERR(trusted);

	spin_lock(&avflt_trusted_lock);

	found = avflt_trusted_find(tgid);
	if (found) {
		found->open++;
		avflt_trusted_free(trusted);

	} else
		list_add_tail(&trusted->list, &avflt_trusted_list);

	spin_unlock(&avflt_trusted_lock);

	return 0;
}

void avflt_trusted_rem(pid_t tgid)
{
	struct avflt_trusted *found;

	spin_lock(&avflt_trusted_lock);

	found = avflt_trusted_find(tgid);
	if (!found)
		goto exit;

	if (--found->open)
		goto exit;

	list_del_init(&found->list);

	avflt_trusted_free(found);
exit:
	spin_unlock(&avflt_trusted_lock);
}

int avflt_trusted_allow(pid_t tgid)
{
	struct avflt_trusted *found;

	spin_lock(&avflt_trusted_lock);
	found = avflt_trusted_find(tgid);
	spin_unlock(&avflt_trusted_lock);

	if (found)
		return 1;

	return 0;
}

static struct avflt_proc *avflt_proc_alloc(pid_t tgid)
{
	struct avflt_proc *proc;

	proc = kzalloc(sizeof(struct avflt_proc), GFP_KERNEL);
	if (!proc)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&proc->list);
	INIT_LIST_HEAD(&proc->events);
	spin_lock_init(&proc->lock);
	atomic_set(&proc->count, 1);
	proc->tgid = tgid;
	proc->open = 1;
	
	return proc;
}

struct avflt_proc *avflt_proc_get(struct avflt_proc *proc)
{
	if (!proc || IS_ERR(proc))
		return NULL;

	BUG_ON(!atomic_read(&proc->count));
	atomic_inc(&proc->count);

	return proc;
}

void avflt_proc_put(struct avflt_proc *proc)
{
	struct avflt_event *event;
	struct avflt_event *tmp;

	if (!proc || IS_ERR(proc))
		return;

	BUG_ON(!atomic_read(&proc->count));
	if (!atomic_dec_and_test(&proc->count))
		return;

	list_for_each_entry_safe(event, tmp, &proc->events, proc_list) {
		list_del_init(&event->proc_list);
		avflt_readd_request(event);
		avflt_event_put(event);
	}

	kfree(proc);
}

static struct avflt_proc *avflt_proc_find_nolock(pid_t tgid)
{
	struct avflt_proc *found = NULL;
	struct avflt_proc *proc;

	list_for_each_entry(proc, &avflt_proc_list, list) {
		if (proc->tgid == tgid) {
			found = avflt_proc_get(proc);
			break;
		}
	}

	return found;
}

struct avflt_proc *avflt_proc_find(pid_t tgid)
{
	struct avflt_proc *proc;

	spin_lock(&avflt_proc_lock);
	proc = avflt_proc_find_nolock(tgid);
	spin_unlock(&avflt_proc_lock);

	return proc;
}

struct avflt_proc *avflt_proc_add(pid_t tgid)
{
	struct avflt_proc *proc;
	struct avflt_proc *found;

	proc = avflt_proc_alloc(tgid);
	if (IS_ERR(proc))
		return proc;

	spin_lock(&avflt_proc_lock);

	found = avflt_proc_find_nolock(tgid);
	if (found) {
		found->open++;
		spin_unlock(&avflt_proc_lock);
		avflt_proc_put(proc);
		return found;
	}

	list_add_tail(&proc->list, &avflt_proc_list);
	avflt_proc_get(proc);

	spin_unlock(&avflt_proc_lock);

	return proc;
}

void avflt_proc_rem(pid_t tgid)
{
	struct avflt_proc *proc;

	spin_lock(&avflt_proc_lock);

	proc = avflt_proc_find_nolock(tgid);
	if (!proc) {
		spin_unlock(&avflt_proc_lock);
		return;
	}

	if (--proc->open) {
		spin_unlock(&avflt_proc_lock);
		return;
	}

	list_del(&proc->list);
	spin_unlock(&avflt_proc_lock);
	avflt_proc_put(proc);
	avflt_proc_put(proc);
}

int avflt_proc_allow(pid_t tgid)
{
	struct avflt_proc *proc;

	proc = avflt_proc_find(tgid);
	if (proc) {
		avflt_proc_put(proc);
		return 1;
	}

	return 0;
}

int avflt_proc_empty(void)
{
	int empty;

	spin_lock(&avflt_proc_lock);
	empty = list_empty(&avflt_proc_list);
	spin_unlock(&avflt_proc_lock);

	return empty;
}

void avflt_proc_add_event(struct avflt_proc *proc, struct avflt_event *event)
{
	spin_lock(&proc->lock);

	list_add_tail(&event->proc_list, &proc->events);
	avflt_event_get(event);

	spin_unlock(&proc->lock);
}

void avflt_proc_rem_event(struct avflt_proc *proc, struct avflt_event *event)
{
	spin_lock(&proc->lock);

	if (list_empty(&event->proc_list)) {
		spin_unlock(&proc->lock);
		return;
	}

	list_del_init(&event->proc_list);

	spin_unlock(&proc->lock);

	avflt_event_put(event);
}

struct avflt_event *avflt_proc_get_event(struct avflt_proc *proc, int id)
{
	struct avflt_event *found = NULL;
	struct avflt_event *event;

	spin_lock(&proc->lock);

	list_for_each_entry(event, &proc->events, proc_list) {
		if (event->id == id) {
			found = event;
			break;
		}
	}

	if (found)
		list_del_init(&event->proc_list);

	spin_unlock(&proc->lock);

	return found;
}

ssize_t avflt_proc_get_info(char *buf, int size)
{
	struct avflt_proc *proc;
	ssize_t len = 0;

	spin_lock(&avflt_proc_lock);

	list_for_each_entry(proc, &avflt_proc_list, list) {
		len += snprintf(buf + len, size - len, "%d", proc->tgid) + 1;
		if (len >= size) {
			len = size;
			break;
		}
	}

	spin_unlock(&avflt_proc_lock);

	return len;
}

ssize_t avflt_trusted_get_info(char *buf, int size)
{
	struct avflt_trusted *trusted;
	ssize_t len = 0;

	spin_lock(&avflt_trusted_lock);

	list_for_each_entry(trusted, &avflt_trusted_list, list) {
		len += snprintf(buf + len, size - len, "%d", trusted->tgid) + 1;
		if (len >= size) {
			len = size;
			break;
		}
	}

	spin_unlock(&avflt_trusted_lock);

	return len;
}

driver/avflt/avflt_sysfs.c0000644000076400007640000001361112112622747015534 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

atomic_t avflt_reply_timeout = ATOMIC_INIT(0);
atomic_t avflt_cache_enabled = ATOMIC_INIT(1);

static ssize_t avflt_timeout_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	return snprintf(buf, PAGE_SIZE, "%d",
			atomic_read(&avflt_reply_timeout));
}

static ssize_t avflt_timeout_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	int timeout;

	if (sscanf(buf, "%d", &timeout) != 1)
		return -EINVAL;

	if (timeout < 0)
		return -EINVAL;

	atomic_set(&avflt_reply_timeout, timeout);

	return count;
}

static ssize_t avflt_cache_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	char state;

	if (atomic_read(&avflt_cache_enabled))
		state = 'a';
	else
		state = 'd';

	return snprintf(buf, PAGE_SIZE, "%c", state);
}

static ssize_t avflt_cache_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	char cache;

	if (sscanf(buf, "%c", &cache) != 1)
		return -EINVAL;

	switch (cache) {
		case 'a':
			avflt_invalidate_cache();
			atomic_set(&avflt_cache_enabled, 1);
			break;

		case 'd':
			atomic_set(&avflt_cache_enabled, 0);
			break;

		case 'i':
			avflt_invalidate_cache();
			break;

		default:
			return -EINVAL;
	}

	return count;
}

static ssize_t avflt_cache_paths_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	struct avflt_root_data *data;
	redirfs_path *paths;
	redirfs_root root;
	ssize_t size = 0;
	char state;
	int i = 0;

	paths = redirfs_get_paths(avflt);
	if (IS_ERR(paths))
		return PTR_ERR(paths);

	while (paths[i]) {
		root = redirfs_get_root_path(paths[i]);
		if (!root)
			goto next;

		data = avflt_get_root_data_root(root);
		redirfs_put_root(root);
		if (!data)
			goto next;

		if (atomic_read(&data->cache_enabled))
			state = 'a';
		else
			state = 'd';

		avflt_put_root_data(data);

		size += snprintf(buf + size, PAGE_SIZE - size, "%d:%c",
				redirfs_get_id_path(paths[i]), state) + 1;

		if (size >= PAGE_SIZE)
			break;
next:
		i++;
	}

	redirfs_put_paths(paths);
	return size;
}

static ssize_t avflt_cache_paths_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	struct avflt_root_data *data;
	redirfs_path path;
	redirfs_root root;
	char cache;
	int id;

	if (sscanf(buf, "%c:%d", &cache, &id) != 2)
		return -EINVAL;

	path = redirfs_get_path_id(id);
	if (!path)
		return -ENOENT;

	root = redirfs_get_root_path(path);
	redirfs_put_path(path);
	if (!root)
		return -ENOENT;

	data = avflt_get_root_data_root(root);
	redirfs_put_root(root);
	if (!data)
		return -ENOENT;

	switch (cache) {
		case 'a':
			atomic_inc(&data->cache_ver);
			atomic_set(&data->cache_enabled, 1);
			break;
		case 'd':
			atomic_set(&data->cache_enabled, 0);
			break;
		case 'i':
			atomic_inc(&data->cache_ver);
			break;

		default:
			avflt_put_root_data(data);
			return -EINVAL;

	}

	avflt_put_root_data(data);

	return count;
}

static ssize_t avflt_registered_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	return avflt_proc_get_info(buf, PAGE_SIZE);
}

static ssize_t avflt_trusted_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	return avflt_trusted_get_info(buf, PAGE_SIZE);
}

static struct redirfs_filter_attribute avflt_timeout_attr = 
	REDIRFS_FILTER_ATTRIBUTE(timeout, 0644, avflt_timeout_show,
			avflt_timeout_store);

static struct redirfs_filter_attribute avflt_cache_attr = 
	REDIRFS_FILTER_ATTRIBUTE(cache, 0644, avflt_cache_show,
			avflt_cache_store);

static struct redirfs_filter_attribute avflt_pathcache_attr = 
	REDIRFS_FILTER_ATTRIBUTE(cache_paths, 0644, avflt_cache_paths_show,
			avflt_cache_paths_store);

static struct redirfs_filter_attribute avflt_registered_attr = 
	REDIRFS_FILTER_ATTRIBUTE(registered, 0444, avflt_registered_show, NULL);

static struct redirfs_filter_attribute avflt_trusted_attr = 
	REDIRFS_FILTER_ATTRIBUTE(trusted, 0444, avflt_trusted_show, NULL);

int avflt_sys_init(void)
{
	int rv;

	rv = redirfs_create_attribute(avflt, &avflt_timeout_attr);
	if (rv)
		return rv;

	rv = redirfs_create_attribute(avflt, &avflt_cache_attr);
	if (rv)
		goto err_cache;

	rv = redirfs_create_attribute(avflt, &avflt_pathcache_attr);
	if (rv)
		goto err_pathcache;

	rv = redirfs_create_attribute(avflt, &avflt_registered_attr);
	if (rv)
		goto err_registered;

	rv = redirfs_create_attribute(avflt, &avflt_trusted_attr);
	if (rv)
		goto err_trusted;

	return 0;

err_trusted:
	redirfs_remove_attribute(avflt, &avflt_registered_attr);
err_registered:
	redirfs_remove_attribute(avflt, &avflt_pathcache_attr);
err_pathcache:
	redirfs_remove_attribute(avflt, &avflt_cache_attr);
err_cache:
	redirfs_remove_attribute(avflt, &avflt_timeout_attr);
	return rv;
}

void avflt_sys_exit(void)
{
	redirfs_remove_attribute(avflt, &avflt_timeout_attr);
	redirfs_remove_attribute(avflt, &avflt_cache_attr);
	redirfs_remove_attribute(avflt, &avflt_pathcache_attr);
	redirfs_remove_attribute(avflt, &avflt_registered_attr);
	redirfs_remove_attribute(avflt, &avflt_trusted_attr);
}

driver/avflt/avflt_data.c0000644000076400007640000001207112112622747015275 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static rfs_kmem_cache_t *avflt_inode_data_cache = NULL;

static void avflt_root_data_free(struct redirfs_data *rfs_data)
{
	struct avflt_root_data *data = rfs_to_root_data(rfs_data);

	kfree(data);
}

static struct avflt_root_data *avflt_root_data_alloc(void)
{
	struct avflt_root_data *data;
	int err;

	data = kzalloc(sizeof(struct avflt_root_data), GFP_KERNEL);
	if (!data)
		return ERR_PTR(-ENOMEM);

	err = redirfs_init_data(&data->rfs_data, avflt, avflt_root_data_free,
			NULL);
	if (err) {
		kfree(data);
		return ERR_PTR(err);
	}

	atomic_set(&data->cache_enabled, 1);
	atomic_set(&data->cache_ver, 0);

	return data;
}

struct avflt_root_data *avflt_get_root_data_root(redirfs_root root)
{
	struct redirfs_data *rfs_data;

	rfs_data = redirfs_get_data_root(avflt, root);
	if (!rfs_data)
		return NULL;

	return rfs_to_root_data(rfs_data);
}

struct avflt_root_data *avflt_get_root_data_inode(struct inode *inode)
{
	struct avflt_root_data *data;
	redirfs_root root;

	root = redirfs_get_root_inode(avflt, inode);
	if (!root)
		return NULL;

	data = avflt_get_root_data_root(root);
	redirfs_put_root(root);

	return data;
}

struct avflt_root_data *avflt_get_root_data(struct avflt_root_data *data)
{
	struct redirfs_data *rfs_data;

	if (!data || IS_ERR(data))
		return NULL;

	rfs_data = redirfs_get_data(&data->rfs_data);
	if (!rfs_data)
		return NULL;

	return data;
}

void avflt_put_root_data(struct avflt_root_data *data)
{
	if (!data || IS_ERR(data))
		return;

	redirfs_put_data(&data->rfs_data);
}

struct avflt_root_data *avflt_attach_root_data(redirfs_root root)
{
	struct avflt_root_data *data = NULL;
	struct avflt_root_data *rv = NULL;
	struct redirfs_data *rfs_data = NULL;

	data = avflt_get_root_data_root(root);
	if (data)
		return data;

	data = avflt_root_data_alloc();
	if (!data)
		return data;

	rfs_data = redirfs_attach_data_root(avflt, root, &data->rfs_data);
	if (!rfs_data)
		goto exit;

	if (rfs_data != &data->rfs_data)
		rv = rfs_to_root_data(rfs_data);
	else
		rv = data;
exit:
	avflt_put_root_data(data);
	return rv;
}

static void avflt_inode_data_free(struct redirfs_data *rfs_data)
{
	struct avflt_inode_data *data = rfs_to_inode_data(rfs_data);

	avflt_put_root_data(data->root_data);
	kmem_cache_free(avflt_inode_data_cache, data);
}

static struct avflt_inode_data *avflt_inode_data_alloc(void)
{
	struct avflt_inode_data *data;
	int err;

	data = kmem_cache_zalloc(avflt_inode_data_cache, GFP_KERNEL);
	if (!data)
		return ERR_PTR(-ENOMEM);

	err = redirfs_init_data(&data->rfs_data, avflt, avflt_inode_data_free,
			NULL);
	if (err) {
		 kmem_cache_free(avflt_inode_data_cache, data);
		 return ERR_PTR(err);
	}

	spin_lock_init(&data->lock);
	return data;
}

struct avflt_inode_data *avflt_get_inode_data_inode(struct inode *inode)
{
	struct redirfs_data *rfs_data;

	rfs_data = redirfs_get_data_inode(avflt, inode);
	if (!rfs_data)
		return NULL;

	return rfs_to_inode_data(rfs_data);
}

struct avflt_inode_data *avflt_get_inode_data(struct avflt_inode_data *data)
{
	struct redirfs_data *rfs_data;

	if (!data || IS_ERR(data))
		return NULL;

	rfs_data = redirfs_get_data(&data->rfs_data);
	if (!rfs_data)
		return NULL;

	return data;
}

void avflt_put_inode_data(struct avflt_inode_data *data)
{
	if (!data || IS_ERR(data))
		return;

	redirfs_put_data(&data->rfs_data);
}

struct avflt_inode_data *avflt_attach_inode_data(struct inode *inode)
{
	struct redirfs_data *rfs_data = NULL;
	struct avflt_inode_data *data = NULL;
	struct avflt_inode_data *rv = NULL;

	data = avflt_get_inode_data_inode(inode);
	if (data)
		return data;

	data = avflt_inode_data_alloc();
	if (!data) 
		return data;

	rfs_data = redirfs_attach_data_inode(avflt, inode,
			&data->rfs_data);
	if (!rfs_data)
		goto exit;

	if (rfs_data != &data->rfs_data)
		rv = rfs_to_inode_data(rfs_data);
	else
		rv = data;
exit:
	avflt_put_inode_data(data);
	return rv;
}

int avflt_data_init(void)
{
	/*
	avflt_inode_data_cache = kmem_cache_create("avflt_inode_data_cache",
			sizeof(struct avflt_inode_data),
			0, SLAB_RECLAIM_ACCOUNT, NULL);
	*/
	avflt_inode_data_cache = rfs_kmem_cache_create("avflt_inode_data_cache",
			sizeof(struct avflt_inode_data));

	if (!avflt_inode_data_cache)
		return -ENOMEM;

	return 0;
}

void avflt_data_exit(void)
{
	kmem_cache_destroy(avflt_inode_data_cache);
}

driver/avflt/avflt_mod.c0000644000076400007640000000331112112622747015140 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static int __init avflt_init(void)
{
	int rv;

	rv = avflt_check_init();
	if (rv)
		return rv;

	rv = avflt_data_init();
	if (rv)
		goto err_check;

	rv = avflt_rfs_init();
	if (rv)
		goto err_data;

	rv = avflt_sys_init();
	if (rv) 
		goto err_rfs;

	rv = avflt_dev_init();
	if (rv)
		goto err_sys;

	printk(KERN_INFO "Anti-Virus Filter Version "
			AVFLT_VERSION " <www.redirfs.org>\n");
	return 0;

err_sys:
	avflt_sys_exit();
err_rfs:
	avflt_rfs_exit();
err_data:
	avflt_data_exit();
err_check:
	avflt_check_exit();
	return rv;
}

static void __exit avflt_exit(void)
{
	avflt_dev_exit();
	avflt_sys_exit();
	avflt_rfs_exit();
	avflt_data_exit();
	avflt_check_exit();
}

module_init(avflt_init);
module_exit(avflt_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Frantisek Hrbata <frantisek.hrbata@redirfs.org>");
MODULE_DESCRIPTION("Anti-Virus Filter for the RedirFS Framework");

driver/avflt/avflt_check.c0000644000076400007640000002414112112622747015442 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

DECLARE_WAIT_QUEUE_HEAD(avflt_request_available);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
static spinlock_t avflt_request_lock = SPIN_LOCK_UNLOCKED;
#else
static DEFINE_SPINLOCK(avflt_request_lock);
#endif
static LIST_HEAD(avflt_request_list);
static int avflt_request_accept = 0;
static rfs_kmem_cache_t *avflt_event_cache = NULL;
atomic_t avflt_cache_ver = ATOMIC_INIT(0);
atomic_t avflt_event_ids = ATOMIC_INIT(0);

static struct avflt_event *avflt_event_alloc(struct file *file, int type)
{
	struct avflt_inode_data *inode_data;
	struct avflt_root_data *root_data;
	struct avflt_event *event;

	event = kmem_cache_zalloc(avflt_event_cache, GFP_KERNEL);
	if (!event) 
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&event->req_list);
	INIT_LIST_HEAD(&event->proc_list);
	init_completion(&event->wait);
	atomic_set(&event->count, 1);
	event->type = type;
	event->id = -1;
	event->mnt = mntget(file->f_vfsmnt);
	event->dentry = dget(file->f_dentry);
	event->flags = file->f_flags;
	event->fd = -1;
	event->pid = current->pid;
	event->tgid = current->tgid;
	event->cache = 1;

	root_data = avflt_get_root_data_inode(file->f_dentry->d_inode);
	inode_data = avflt_get_inode_data_inode(file->f_dentry->d_inode);

	if (root_data) 
		event->root_cache_ver = atomic_read(&root_data->cache_ver);

	event->root_data = avflt_get_root_data(root_data);

	if (inode_data) {
		spin_lock(&inode_data->lock);
		event->cache_ver = inode_data->inode_cache_ver;
		spin_unlock(&inode_data->lock);
	}

	avflt_put_inode_data(inode_data);
	avflt_put_root_data(root_data);

	return event;
}

struct avflt_event *avflt_event_get(struct avflt_event *event)
{
	if (!event || IS_ERR(event))
		return NULL;

	BUG_ON(!atomic_read(&event->count));
	atomic_inc(&event->count);

	return event;
}

void avflt_event_put(struct avflt_event *event)
{
	if (!event || IS_ERR(event))
		return;

	BUG_ON(!atomic_read(&event->count));

	if (!atomic_dec_and_test(&event->count))
		return;

	avflt_put_root_data(event->root_data);
	mntput(event->mnt);
	dput(event->dentry);
	kmem_cache_free(avflt_event_cache, event);
}

static int avflt_add_request(struct avflt_event *event, int tail)
{
	spin_lock(&avflt_request_lock);

	if (avflt_request_accept == 0) {
		spin_unlock(&avflt_request_lock);
		return 1;
	}

	if (tail)
		list_add_tail(&event->req_list, &avflt_request_list);
	else
		list_add(&event->req_list, &avflt_request_list);

	avflt_event_get(event);
	
	wake_up_interruptible(&avflt_request_available);

	spin_unlock(&avflt_request_lock);

	return 0;
}

void avflt_readd_request(struct avflt_event *event)
{
	if (avflt_add_request(event, 0))
		avflt_event_done(event);
}

static void avflt_rem_request(struct avflt_event *event)
{
	spin_lock(&avflt_request_lock);
	if (list_empty(&event->req_list)) {
		spin_unlock(&avflt_request_lock);
		return;
	}
	list_del_init(&event->req_list);
	spin_unlock(&avflt_request_lock);
	avflt_event_put(event);
}

struct avflt_event *avflt_get_request(void)
{
	struct avflt_event *event;

	spin_lock(&avflt_request_lock);

	if (list_empty(&avflt_request_list)) {
		spin_unlock(&avflt_request_lock);
		return NULL;
	}

	event = list_entry(avflt_request_list.next, struct avflt_event,
			req_list);
	list_del_init(&event->req_list);

	spin_unlock(&avflt_request_lock);

	event->id = atomic_inc_return(&avflt_event_ids);
	return event;
}

static int avflt_wait_for_reply(struct avflt_event *event)
{
	long jiffies;
	int timeout;

	timeout = atomic_read(&avflt_reply_timeout);
	if (timeout)
		jiffies = msecs_to_jiffies(timeout);
	else
		jiffies = MAX_SCHEDULE_TIMEOUT;

	jiffies = wait_for_completion_interruptible_timeout(&event->wait,
			jiffies);

	if (jiffies < 0)
		return (int)jiffies;

	if (!jiffies) {
		printk(KERN_WARNING "avflt: wait for reply timeout\n");
		return -ETIMEDOUT;
	}

	return 0;
}

static void avflt_update_cache(struct avflt_event *event)
{
	struct avflt_inode_data *inode_data;
	struct avflt_root_data *root_data;

	if (!event->cache)
		return;

	if (!atomic_read(&avflt_cache_enabled))
		return;

	root_data = avflt_get_root_data_inode(event->dentry->d_inode);
	if (!root_data)
		return;

	if (!atomic_read(&root_data->cache_enabled)) {
		avflt_put_root_data(root_data);
		return;
	}

	avflt_put_root_data(root_data);

	inode_data = avflt_attach_inode_data(event->dentry->d_inode);
	if (!inode_data)
		return;

	spin_lock(&inode_data->lock);
	avflt_put_root_data(inode_data->root_data);
	inode_data->root_data = avflt_get_root_data(event->root_data);
	inode_data->root_cache_ver = event->root_cache_ver;
	inode_data->cache_ver = event->cache_ver;
	inode_data->state = event->result;
	spin_unlock(&inode_data->lock);
	avflt_put_inode_data(inode_data);
}

int avflt_process_request(struct file *file, int type)
{
	struct avflt_event *event;
	int rv = 0;

	event = avflt_event_alloc(file, type);
	if (IS_ERR(event))
		return PTR_ERR(event);

	if (avflt_add_request(event, 1))
		goto exit;

	rv = avflt_wait_for_reply(event);
	if (rv)
		goto exit;

	avflt_update_cache(event);
	rv = event->result;
exit:
	avflt_rem_request(event);
	avflt_event_put(event);
	return rv;
}

void avflt_event_done(struct avflt_event *event)
{
	complete(&event->wait);
}

int avflt_get_file(struct avflt_event *event)
{
	struct file *file;
	int flags;
	int fd;

	fd = get_unused_fd();
	if (fd < 0)
		return fd;

	flags = O_RDONLY;
	flags |= event->flags & O_LARGEFILE;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
	file = dentry_open(dget(event->dentry), mntget(event->mnt), flags);
#else
	file = dentry_open(dget(event->dentry), mntget(event->mnt), flags,
			current_cred());
#endif
	if (IS_ERR(file)) {
		put_unused_fd(fd);
		return PTR_ERR(file);
	}

	event->file = file;
	event->fd = fd;

	return 0;
}

void avflt_put_file(struct avflt_event *event)
{
	if (event->fd > 0) 
		put_unused_fd(event->fd);

	if (event->file) 
		fput(event->file);

	event->fd = -1;
	event->file = NULL;
}

void avflt_install_fd(struct avflt_event *event)
{
	fd_install(event->fd, event->file);
}

ssize_t avflt_copy_cmd(char __user *buf, size_t size, struct avflt_event *event)
{
	char cmd[256];
	int len;

	len = snprintf(cmd, 256, "id:%d,type:%d,fd:%d,pid:%d,tgid:%d",
			event->id, event->type, event->fd, event->pid,
			event->tgid);
	if (len < 0)
		return len;

	len++;

	if (len > size)
		return -EINVAL;

	if (copy_to_user(buf, cmd, len)) 
		return -EFAULT;

	return len;
}

int avflt_add_reply(struct avflt_event *event)
{
	struct avflt_proc *proc;

	proc = avflt_proc_find(current->tgid);
	if (!proc)
		return -ENOENT;

	avflt_proc_add_event(proc, event);
	avflt_proc_put(proc);

	return 0;
}

int avflt_request_empty(void)
{
	int rv;

	spin_lock(&avflt_request_lock);

	if (list_empty(&avflt_request_list))
		rv = 1;
	else
		rv = 0;

	spin_unlock(&avflt_request_lock);

	return rv;
}

void avflt_start_accept(void)
{
	spin_lock(&avflt_request_lock);
	avflt_request_accept = 1;
	spin_unlock(&avflt_request_lock);
}

void avflt_stop_accept(void)
{
	spin_lock(&avflt_request_lock);
	if (avflt_proc_empty())
		avflt_request_accept = 0;
	spin_unlock(&avflt_request_lock);
}

int avflt_is_stopped(void)
{
	int stopped;

	spin_lock(&avflt_request_lock);
	stopped = avflt_request_accept == 0;
	spin_unlock(&avflt_request_lock);

	return stopped;
}

void avflt_rem_requests(void)
{
	LIST_HEAD(list);
	struct avflt_event *event;
	struct avflt_event *tmp;

	spin_lock(&avflt_request_lock);

	if (avflt_request_accept == 1) {
		spin_unlock(&avflt_request_lock);
		return;

	}

	list_for_each_entry_safe(event, tmp, &avflt_request_list, req_list) {
		list_move_tail(&event->req_list, &list);
		avflt_event_done(event);
	}

	spin_unlock(&avflt_request_lock);

	list_for_each_entry_safe(event, tmp, &list, req_list) {
		list_del_init(&event->req_list);
		avflt_event_put(event);
	}
}

struct avflt_event *avflt_get_reply(const char __user *buf, size_t size)
{
	struct avflt_proc *proc;
	struct avflt_event *event;
	char cmd[256];
	int id;
	int result;
	int cache;
	int rv;

	if (size > 256)
		return ERR_PTR(-EINVAL);

	if (copy_from_user(cmd, buf, size))
		return ERR_PTR(-EFAULT);

	cache = -1;
	/*
	 * v0: id:%d,res:%d
	 * v1: id:%d,res:%d,cache:%d
	 */
	rv = sscanf(buf, "id:%d,res:%d,cache:%d", &id, &result, &cache);
	if (rv != 2 && rv != 3)
		return ERR_PTR(-EINVAL);

	proc = avflt_proc_find(current->tgid);
	if (!proc)
		return ERR_PTR(-ENOENT);

	event = avflt_proc_get_event(proc, id);
	avflt_proc_put(proc);
	if (!event)
		return ERR_PTR(-ENOENT);

	event->result = result;
	
	if (cache != -1)
		event->cache = cache;

	return event;
}

void avflt_invalidate_cache_root(redirfs_root root)
{
	struct avflt_root_data *data;

	if (!root)
		return;

	data = avflt_get_root_data_root(root);
	if (!data)
		return;

	atomic_inc(&data->cache_ver);
	avflt_put_root_data(data);
}

void avflt_invalidate_cache(void)
{
	redirfs_path *paths;
	redirfs_root root;
	int i = 0;

	paths = redirfs_get_paths(avflt);
	if (IS_ERR(paths))
		return;

	while (paths[i]) {
		root = redirfs_get_root_path(paths[i]);
		avflt_invalidate_cache_root(root);
		redirfs_put_root(root);
		i++;
	}

	redirfs_put_paths(paths);
}

int avflt_check_init(void)
{
	/*
	avflt_event_cache = kmem_cache_create("avflt_event_cache",
			sizeof(struct avflt_event),
			0, SLAB_RECLAIM_ACCOUNT, NULL);
	*/
	avflt_event_cache = rfs_kmem_cache_create("avflt_event_cache",
			sizeof(struct avflt_event));

	if (!avflt_event_cache)
		return -ENOMEM;

	return 0;
}

void avflt_check_exit(void)
{
	kmem_cache_destroy(avflt_event_cache);
}

driver/avflt/Makefile0000644000076400007640000000017612112622747014467 0ustar  comodocomodoobj-m += avflt.o
avflt-objs :=  avflt_check.o avflt_data.o avflt_dev.o avflt_mod.o \
	avflt_proc.o avflt_rfs.o avflt_sysfs.o

driver/avflt/.svn/0000755000076400007640000000000012112622747013707 5ustar  comodocomododriver/avflt/.svn/text-base/0000755000076400007640000000000012112622747015603 5ustar  comodocomododriver/avflt/.svn/text-base/avflt_check.c.svn-base0000644000076400007640000002414112112622747021737 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

DECLARE_WAIT_QUEUE_HEAD(avflt_request_available);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
static spinlock_t avflt_request_lock = SPIN_LOCK_UNLOCKED;
#else
static DEFINE_SPINLOCK(avflt_request_lock);
#endif
static LIST_HEAD(avflt_request_list);
static int avflt_request_accept = 0;
static rfs_kmem_cache_t *avflt_event_cache = NULL;
atomic_t avflt_cache_ver = ATOMIC_INIT(0);
atomic_t avflt_event_ids = ATOMIC_INIT(0);

static struct avflt_event *avflt_event_alloc(struct file *file, int type)
{
	struct avflt_inode_data *inode_data;
	struct avflt_root_data *root_data;
	struct avflt_event *event;

	event = kmem_cache_zalloc(avflt_event_cache, GFP_KERNEL);
	if (!event) 
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&event->req_list);
	INIT_LIST_HEAD(&event->proc_list);
	init_completion(&event->wait);
	atomic_set(&event->count, 1);
	event->type = type;
	event->id = -1;
	event->mnt = mntget(file->f_vfsmnt);
	event->dentry = dget(file->f_dentry);
	event->flags = file->f_flags;
	event->fd = -1;
	event->pid = current->pid;
	event->tgid = current->tgid;
	event->cache = 1;

	root_data = avflt_get_root_data_inode(file->f_dentry->d_inode);
	inode_data = avflt_get_inode_data_inode(file->f_dentry->d_inode);

	if (root_data) 
		event->root_cache_ver = atomic_read(&root_data->cache_ver);

	event->root_data = avflt_get_root_data(root_data);

	if (inode_data) {
		spin_lock(&inode_data->lock);
		event->cache_ver = inode_data->inode_cache_ver;
		spin_unlock(&inode_data->lock);
	}

	avflt_put_inode_data(inode_data);
	avflt_put_root_data(root_data);

	return event;
}

struct avflt_event *avflt_event_get(struct avflt_event *event)
{
	if (!event || IS_ERR(event))
		return NULL;

	BUG_ON(!atomic_read(&event->count));
	atomic_inc(&event->count);

	return event;
}

void avflt_event_put(struct avflt_event *event)
{
	if (!event || IS_ERR(event))
		return;

	BUG_ON(!atomic_read(&event->count));

	if (!atomic_dec_and_test(&event->count))
		return;

	avflt_put_root_data(event->root_data);
	mntput(event->mnt);
	dput(event->dentry);
	kmem_cache_free(avflt_event_cache, event);
}

static int avflt_add_request(struct avflt_event *event, int tail)
{
	spin_lock(&avflt_request_lock);

	if (avflt_request_accept == 0) {
		spin_unlock(&avflt_request_lock);
		return 1;
	}

	if (tail)
		list_add_tail(&event->req_list, &avflt_request_list);
	else
		list_add(&event->req_list, &avflt_request_list);

	avflt_event_get(event);
	
	wake_up_interruptible(&avflt_request_available);

	spin_unlock(&avflt_request_lock);

	return 0;
}

void avflt_readd_request(struct avflt_event *event)
{
	if (avflt_add_request(event, 0))
		avflt_event_done(event);
}

static void avflt_rem_request(struct avflt_event *event)
{
	spin_lock(&avflt_request_lock);
	if (list_empty(&event->req_list)) {
		spin_unlock(&avflt_request_lock);
		return;
	}
	list_del_init(&event->req_list);
	spin_unlock(&avflt_request_lock);
	avflt_event_put(event);
}

struct avflt_event *avflt_get_request(void)
{
	struct avflt_event *event;

	spin_lock(&avflt_request_lock);

	if (list_empty(&avflt_request_list)) {
		spin_unlock(&avflt_request_lock);
		return NULL;
	}

	event = list_entry(avflt_request_list.next, struct avflt_event,
			req_list);
	list_del_init(&event->req_list);

	spin_unlock(&avflt_request_lock);

	event->id = atomic_inc_return(&avflt_event_ids);
	return event;
}

static int avflt_wait_for_reply(struct avflt_event *event)
{
	long jiffies;
	int timeout;

	timeout = atomic_read(&avflt_reply_timeout);
	if (timeout)
		jiffies = msecs_to_jiffies(timeout);
	else
		jiffies = MAX_SCHEDULE_TIMEOUT;

	jiffies = wait_for_completion_interruptible_timeout(&event->wait,
			jiffies);

	if (jiffies < 0)
		return (int)jiffies;

	if (!jiffies) {
		printk(KERN_WARNING "avflt: wait for reply timeout\n");
		return -ETIMEDOUT;
	}

	return 0;
}

static void avflt_update_cache(struct avflt_event *event)
{
	struct avflt_inode_data *inode_data;
	struct avflt_root_data *root_data;

	if (!event->cache)
		return;

	if (!atomic_read(&avflt_cache_enabled))
		return;

	root_data = avflt_get_root_data_inode(event->dentry->d_inode);
	if (!root_data)
		return;

	if (!atomic_read(&root_data->cache_enabled)) {
		avflt_put_root_data(root_data);
		return;
	}

	avflt_put_root_data(root_data);

	inode_data = avflt_attach_inode_data(event->dentry->d_inode);
	if (!inode_data)
		return;

	spin_lock(&inode_data->lock);
	avflt_put_root_data(inode_data->root_data);
	inode_data->root_data = avflt_get_root_data(event->root_data);
	inode_data->root_cache_ver = event->root_cache_ver;
	inode_data->cache_ver = event->cache_ver;
	inode_data->state = event->result;
	spin_unlock(&inode_data->lock);
	avflt_put_inode_data(inode_data);
}

int avflt_process_request(struct file *file, int type)
{
	struct avflt_event *event;
	int rv = 0;

	event = avflt_event_alloc(file, type);
	if (IS_ERR(event))
		return PTR_ERR(event);

	if (avflt_add_request(event, 1))
		goto exit;

	rv = avflt_wait_for_reply(event);
	if (rv)
		goto exit;

	avflt_update_cache(event);
	rv = event->result;
exit:
	avflt_rem_request(event);
	avflt_event_put(event);
	return rv;
}

void avflt_event_done(struct avflt_event *event)
{
	complete(&event->wait);
}

int avflt_get_file(struct avflt_event *event)
{
	struct file *file;
	int flags;
	int fd;

	fd = get_unused_fd();
	if (fd < 0)
		return fd;

	flags = O_RDONLY;
	flags |= event->flags & O_LARGEFILE;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
	file = dentry_open(dget(event->dentry), mntget(event->mnt), flags);
#else
	file = dentry_open(dget(event->dentry), mntget(event->mnt), flags,
			current_cred());
#endif
	if (IS_ERR(file)) {
		put_unused_fd(fd);
		return PTR_ERR(file);
	}

	event->file = file;
	event->fd = fd;

	return 0;
}

void avflt_put_file(struct avflt_event *event)
{
	if (event->fd > 0) 
		put_unused_fd(event->fd);

	if (event->file) 
		fput(event->file);

	event->fd = -1;
	event->file = NULL;
}

void avflt_install_fd(struct avflt_event *event)
{
	fd_install(event->fd, event->file);
}

ssize_t avflt_copy_cmd(char __user *buf, size_t size, struct avflt_event *event)
{
	char cmd[256];
	int len;

	len = snprintf(cmd, 256, "id:%d,type:%d,fd:%d,pid:%d,tgid:%d",
			event->id, event->type, event->fd, event->pid,
			event->tgid);
	if (len < 0)
		return len;

	len++;

	if (len > size)
		return -EINVAL;

	if (copy_to_user(buf, cmd, len)) 
		return -EFAULT;

	return len;
}

int avflt_add_reply(struct avflt_event *event)
{
	struct avflt_proc *proc;

	proc = avflt_proc_find(current->tgid);
	if (!proc)
		return -ENOENT;

	avflt_proc_add_event(proc, event);
	avflt_proc_put(proc);

	return 0;
}

int avflt_request_empty(void)
{
	int rv;

	spin_lock(&avflt_request_lock);

	if (list_empty(&avflt_request_list))
		rv = 1;
	else
		rv = 0;

	spin_unlock(&avflt_request_lock);

	return rv;
}

void avflt_start_accept(void)
{
	spin_lock(&avflt_request_lock);
	avflt_request_accept = 1;
	spin_unlock(&avflt_request_lock);
}

void avflt_stop_accept(void)
{
	spin_lock(&avflt_request_lock);
	if (avflt_proc_empty())
		avflt_request_accept = 0;
	spin_unlock(&avflt_request_lock);
}

int avflt_is_stopped(void)
{
	int stopped;

	spin_lock(&avflt_request_lock);
	stopped = avflt_request_accept == 0;
	spin_unlock(&avflt_request_lock);

	return stopped;
}

void avflt_rem_requests(void)
{
	LIST_HEAD(list);
	struct avflt_event *event;
	struct avflt_event *tmp;

	spin_lock(&avflt_request_lock);

	if (avflt_request_accept == 1) {
		spin_unlock(&avflt_request_lock);
		return;

	}

	list_for_each_entry_safe(event, tmp, &avflt_request_list, req_list) {
		list_move_tail(&event->req_list, &list);
		avflt_event_done(event);
	}

	spin_unlock(&avflt_request_lock);

	list_for_each_entry_safe(event, tmp, &list, req_list) {
		list_del_init(&event->req_list);
		avflt_event_put(event);
	}
}

struct avflt_event *avflt_get_reply(const char __user *buf, size_t size)
{
	struct avflt_proc *proc;
	struct avflt_event *event;
	char cmd[256];
	int id;
	int result;
	int cache;
	int rv;

	if (size > 256)
		return ERR_PTR(-EINVAL);

	if (copy_from_user(cmd, buf, size))
		return ERR_PTR(-EFAULT);

	cache = -1;
	/*
	 * v0: id:%d,res:%d
	 * v1: id:%d,res:%d,cache:%d
	 */
	rv = sscanf(buf, "id:%d,res:%d,cache:%d", &id, &result, &cache);
	if (rv != 2 && rv != 3)
		return ERR_PTR(-EINVAL);

	proc = avflt_proc_find(current->tgid);
	if (!proc)
		return ERR_PTR(-ENOENT);

	event = avflt_proc_get_event(proc, id);
	avflt_proc_put(proc);
	if (!event)
		return ERR_PTR(-ENOENT);

	event->result = result;
	
	if (cache != -1)
		event->cache = cache;

	return event;
}

void avflt_invalidate_cache_root(redirfs_root root)
{
	struct avflt_root_data *data;

	if (!root)
		return;

	data = avflt_get_root_data_root(root);
	if (!data)
		return;

	atomic_inc(&data->cache_ver);
	avflt_put_root_data(data);
}

void avflt_invalidate_cache(void)
{
	redirfs_path *paths;
	redirfs_root root;
	int i = 0;

	paths = redirfs_get_paths(avflt);
	if (IS_ERR(paths))
		return;

	while (paths[i]) {
		root = redirfs_get_root_path(paths[i]);
		avflt_invalidate_cache_root(root);
		redirfs_put_root(root);
		i++;
	}

	redirfs_put_paths(paths);
}

int avflt_check_init(void)
{
	/*
	avflt_event_cache = kmem_cache_create("avflt_event_cache",
			sizeof(struct avflt_event),
			0, SLAB_RECLAIM_ACCOUNT, NULL);
	*/
	avflt_event_cache = rfs_kmem_cache_create("avflt_event_cache",
			sizeof(struct avflt_event));

	if (!avflt_event_cache)
		return -ENOMEM;

	return 0;
}

void avflt_check_exit(void)
{
	kmem_cache_destroy(avflt_event_cache);
}

driver/avflt/.svn/text-base/COPYING.svn-base0000644000076400007640000010451312112622747020357 0ustar  comodocomodo                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
driver/avflt/.svn/text-base/avflt_proc.c.svn-base0000644000076400007640000001504612112622747021631 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static LIST_HEAD(avflt_proc_list);
static DEFINE_SPINLOCK(avflt_proc_lock);

static LIST_HEAD(avflt_trusted_list);
static DEFINE_SPINLOCK(avflt_trusted_lock);

static struct avflt_trusted *avflt_trusted_alloc(pid_t tgid)
{
	struct avflt_trusted *trusted;

	trusted = kzalloc(sizeof(struct avflt_trusted), GFP_KERNEL);
	if (!trusted)
		return ERR_PTR(-ENOMEM);

	trusted->tgid = tgid;
	trusted->open = 1;

	return trusted;
}

static void avflt_trusted_free(struct avflt_trusted *trusted)
{
	kfree(trusted);
}

static struct avflt_trusted *avflt_trusted_find(pid_t tgid)
{
	struct avflt_trusted *trusted;

	list_for_each_entry(trusted, &avflt_trusted_list, list) {
		if (trusted->tgid == tgid)
			return trusted;
	}

	return NULL;
}

int avflt_trusted_add(pid_t tgid)
{
	struct avflt_trusted *trusted;
	struct avflt_trusted *found;

	trusted = avflt_trusted_alloc(tgid);
	if (IS_ERR(trusted))
		return PTR_ERR(trusted);

	spin_lock(&avflt_trusted_lock);

	found = avflt_trusted_find(tgid);
	if (found) {
		found->open++;
		avflt_trusted_free(trusted);

	} else
		list_add_tail(&trusted->list, &avflt_trusted_list);

	spin_unlock(&avflt_trusted_lock);

	return 0;
}

void avflt_trusted_rem(pid_t tgid)
{
	struct avflt_trusted *found;

	spin_lock(&avflt_trusted_lock);

	found = avflt_trusted_find(tgid);
	if (!found)
		goto exit;

	if (--found->open)
		goto exit;

	list_del_init(&found->list);

	avflt_trusted_free(found);
exit:
	spin_unlock(&avflt_trusted_lock);
}

int avflt_trusted_allow(pid_t tgid)
{
	struct avflt_trusted *found;

	spin_lock(&avflt_trusted_lock);
	found = avflt_trusted_find(tgid);
	spin_unlock(&avflt_trusted_lock);

	if (found)
		return 1;

	return 0;
}

static struct avflt_proc *avflt_proc_alloc(pid_t tgid)
{
	struct avflt_proc *proc;

	proc = kzalloc(sizeof(struct avflt_proc), GFP_KERNEL);
	if (!proc)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&proc->list);
	INIT_LIST_HEAD(&proc->events);
	spin_lock_init(&proc->lock);
	atomic_set(&proc->count, 1);
	proc->tgid = tgid;
	proc->open = 1;
	
	return proc;
}

struct avflt_proc *avflt_proc_get(struct avflt_proc *proc)
{
	if (!proc || IS_ERR(proc))
		return NULL;

	BUG_ON(!atomic_read(&proc->count));
	atomic_inc(&proc->count);

	return proc;
}

void avflt_proc_put(struct avflt_proc *proc)
{
	struct avflt_event *event;
	struct avflt_event *tmp;

	if (!proc || IS_ERR(proc))
		return;

	BUG_ON(!atomic_read(&proc->count));
	if (!atomic_dec_and_test(&proc->count))
		return;

	list_for_each_entry_safe(event, tmp, &proc->events, proc_list) {
		list_del_init(&event->proc_list);
		avflt_readd_request(event);
		avflt_event_put(event);
	}

	kfree(proc);
}

static struct avflt_proc *avflt_proc_find_nolock(pid_t tgid)
{
	struct avflt_proc *found = NULL;
	struct avflt_proc *proc;

	list_for_each_entry(proc, &avflt_proc_list, list) {
		if (proc->tgid == tgid) {
			found = avflt_proc_get(proc);
			break;
		}
	}

	return found;
}

struct avflt_proc *avflt_proc_find(pid_t tgid)
{
	struct avflt_proc *proc;

	spin_lock(&avflt_proc_lock);
	proc = avflt_proc_find_nolock(tgid);
	spin_unlock(&avflt_proc_lock);

	return proc;
}

struct avflt_proc *avflt_proc_add(pid_t tgid)
{
	struct avflt_proc *proc;
	struct avflt_proc *found;

	proc = avflt_proc_alloc(tgid);
	if (IS_ERR(proc))
		return proc;

	spin_lock(&avflt_proc_lock);

	found = avflt_proc_find_nolock(tgid);
	if (found) {
		found->open++;
		spin_unlock(&avflt_proc_lock);
		avflt_proc_put(proc);
		return found;
	}

	list_add_tail(&proc->list, &avflt_proc_list);
	avflt_proc_get(proc);

	spin_unlock(&avflt_proc_lock);

	return proc;
}

void avflt_proc_rem(pid_t tgid)
{
	struct avflt_proc *proc;

	spin_lock(&avflt_proc_lock);

	proc = avflt_proc_find_nolock(tgid);
	if (!proc) {
		spin_unlock(&avflt_proc_lock);
		return;
	}

	if (--proc->open) {
		spin_unlock(&avflt_proc_lock);
		return;
	}

	list_del(&proc->list);
	spin_unlock(&avflt_proc_lock);
	avflt_proc_put(proc);
	avflt_proc_put(proc);
}

int avflt_proc_allow(pid_t tgid)
{
	struct avflt_proc *proc;

	proc = avflt_proc_find(tgid);
	if (proc) {
		avflt_proc_put(proc);
		return 1;
	}

	return 0;
}

int avflt_proc_empty(void)
{
	int empty;

	spin_lock(&avflt_proc_lock);
	empty = list_empty(&avflt_proc_list);
	spin_unlock(&avflt_proc_lock);

	return empty;
}

void avflt_proc_add_event(struct avflt_proc *proc, struct avflt_event *event)
{
	spin_lock(&proc->lock);

	list_add_tail(&event->proc_list, &proc->events);
	avflt_event_get(event);

	spin_unlock(&proc->lock);
}

void avflt_proc_rem_event(struct avflt_proc *proc, struct avflt_event *event)
{
	spin_lock(&proc->lock);

	if (list_empty(&event->proc_list)) {
		spin_unlock(&proc->lock);
		return;
	}

	list_del_init(&event->proc_list);

	spin_unlock(&proc->lock);

	avflt_event_put(event);
}

struct avflt_event *avflt_proc_get_event(struct avflt_proc *proc, int id)
{
	struct avflt_event *found = NULL;
	struct avflt_event *event;

	spin_lock(&proc->lock);

	list_for_each_entry(event, &proc->events, proc_list) {
		if (event->id == id) {
			found = event;
			break;
		}
	}

	if (found)
		list_del_init(&event->proc_list);

	spin_unlock(&proc->lock);

	return found;
}

ssize_t avflt_proc_get_info(char *buf, int size)
{
	struct avflt_proc *proc;
	ssize_t len = 0;

	spin_lock(&avflt_proc_lock);

	list_for_each_entry(proc, &avflt_proc_list, list) {
		len += snprintf(buf + len, size - len, "%d", proc->tgid) + 1;
		if (len >= size) {
			len = size;
			break;
		}
	}

	spin_unlock(&avflt_proc_lock);

	return len;
}

ssize_t avflt_trusted_get_info(char *buf, int size)
{
	struct avflt_trusted *trusted;
	ssize_t len = 0;

	spin_lock(&avflt_trusted_lock);

	list_for_each_entry(trusted, &avflt_trusted_list, list) {
		len += snprintf(buf + len, size - len, "%d", trusted->tgid) + 1;
		if (len >= size) {
			len = size;
			break;
		}
	}

	spin_unlock(&avflt_trusted_lock);

	return len;
}

driver/avflt/.svn/text-base/avflt_data.c.svn-base0000644000076400007640000001207112112622747021572 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static rfs_kmem_cache_t *avflt_inode_data_cache = NULL;

static void avflt_root_data_free(struct redirfs_data *rfs_data)
{
	struct avflt_root_data *data = rfs_to_root_data(rfs_data);

	kfree(data);
}

static struct avflt_root_data *avflt_root_data_alloc(void)
{
	struct avflt_root_data *data;
	int err;

	data = kzalloc(sizeof(struct avflt_root_data), GFP_KERNEL);
	if (!data)
		return ERR_PTR(-ENOMEM);

	err = redirfs_init_data(&data->rfs_data, avflt, avflt_root_data_free,
			NULL);
	if (err) {
		kfree(data);
		return ERR_PTR(err);
	}

	atomic_set(&data->cache_enabled, 1);
	atomic_set(&data->cache_ver, 0);

	return data;
}

struct avflt_root_data *avflt_get_root_data_root(redirfs_root root)
{
	struct redirfs_data *rfs_data;

	rfs_data = redirfs_get_data_root(avflt, root);
	if (!rfs_data)
		return NULL;

	return rfs_to_root_data(rfs_data);
}

struct avflt_root_data *avflt_get_root_data_inode(struct inode *inode)
{
	struct avflt_root_data *data;
	redirfs_root root;

	root = redirfs_get_root_inode(avflt, inode);
	if (!root)
		return NULL;

	data = avflt_get_root_data_root(root);
	redirfs_put_root(root);

	return data;
}

struct avflt_root_data *avflt_get_root_data(struct avflt_root_data *data)
{
	struct redirfs_data *rfs_data;

	if (!data || IS_ERR(data))
		return NULL;

	rfs_data = redirfs_get_data(&data->rfs_data);
	if (!rfs_data)
		return NULL;

	return data;
}

void avflt_put_root_data(struct avflt_root_data *data)
{
	if (!data || IS_ERR(data))
		return;

	redirfs_put_data(&data->rfs_data);
}

struct avflt_root_data *avflt_attach_root_data(redirfs_root root)
{
	struct avflt_root_data *data = NULL;
	struct avflt_root_data *rv = NULL;
	struct redirfs_data *rfs_data = NULL;

	data = avflt_get_root_data_root(root);
	if (data)
		return data;

	data = avflt_root_data_alloc();
	if (!data)
		return data;

	rfs_data = redirfs_attach_data_root(avflt, root, &data->rfs_data);
	if (!rfs_data)
		goto exit;

	if (rfs_data != &data->rfs_data)
		rv = rfs_to_root_data(rfs_data);
	else
		rv = data;
exit:
	avflt_put_root_data(data);
	return rv;
}

static void avflt_inode_data_free(struct redirfs_data *rfs_data)
{
	struct avflt_inode_data *data = rfs_to_inode_data(rfs_data);

	avflt_put_root_data(data->root_data);
	kmem_cache_free(avflt_inode_data_cache, data);
}

static struct avflt_inode_data *avflt_inode_data_alloc(void)
{
	struct avflt_inode_data *data;
	int err;

	data = kmem_cache_zalloc(avflt_inode_data_cache, GFP_KERNEL);
	if (!data)
		return ERR_PTR(-ENOMEM);

	err = redirfs_init_data(&data->rfs_data, avflt, avflt_inode_data_free,
			NULL);
	if (err) {
		 kmem_cache_free(avflt_inode_data_cache, data);
		 return ERR_PTR(err);
	}

	spin_lock_init(&data->lock);
	return data;
}

struct avflt_inode_data *avflt_get_inode_data_inode(struct inode *inode)
{
	struct redirfs_data *rfs_data;

	rfs_data = redirfs_get_data_inode(avflt, inode);
	if (!rfs_data)
		return NULL;

	return rfs_to_inode_data(rfs_data);
}

struct avflt_inode_data *avflt_get_inode_data(struct avflt_inode_data *data)
{
	struct redirfs_data *rfs_data;

	if (!data || IS_ERR(data))
		return NULL;

	rfs_data = redirfs_get_data(&data->rfs_data);
	if (!rfs_data)
		return NULL;

	return data;
}

void avflt_put_inode_data(struct avflt_inode_data *data)
{
	if (!data || IS_ERR(data))
		return;

	redirfs_put_data(&data->rfs_data);
}

struct avflt_inode_data *avflt_attach_inode_data(struct inode *inode)
{
	struct redirfs_data *rfs_data = NULL;
	struct avflt_inode_data *data = NULL;
	struct avflt_inode_data *rv = NULL;

	data = avflt_get_inode_data_inode(inode);
	if (data)
		return data;

	data = avflt_inode_data_alloc();
	if (!data) 
		return data;

	rfs_data = redirfs_attach_data_inode(avflt, inode,
			&data->rfs_data);
	if (!rfs_data)
		goto exit;

	if (rfs_data != &data->rfs_data)
		rv = rfs_to_inode_data(rfs_data);
	else
		rv = data;
exit:
	avflt_put_inode_data(data);
	return rv;
}

int avflt_data_init(void)
{
	/*
	avflt_inode_data_cache = kmem_cache_create("avflt_inode_data_cache",
			sizeof(struct avflt_inode_data),
			0, SLAB_RECLAIM_ACCOUNT, NULL);
	*/
	avflt_inode_data_cache = rfs_kmem_cache_create("avflt_inode_data_cache",
			sizeof(struct avflt_inode_data));

	if (!avflt_inode_data_cache)
		return -ENOMEM;

	return 0;
}

void avflt_data_exit(void)
{
	kmem_cache_destroy(avflt_inode_data_cache);
}

driver/avflt/.svn/text-base/avflt_mod.c.svn-base0000644000076400007640000000331112112622747021435 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static int __init avflt_init(void)
{
	int rv;

	rv = avflt_check_init();
	if (rv)
		return rv;

	rv = avflt_data_init();
	if (rv)
		goto err_check;

	rv = avflt_rfs_init();
	if (rv)
		goto err_data;

	rv = avflt_sys_init();
	if (rv) 
		goto err_rfs;

	rv = avflt_dev_init();
	if (rv)
		goto err_sys;

	printk(KERN_INFO "Anti-Virus Filter Version "
			AVFLT_VERSION " <www.redirfs.org>\n");
	return 0;

err_sys:
	avflt_sys_exit();
err_rfs:
	avflt_rfs_exit();
err_data:
	avflt_data_exit();
err_check:
	avflt_check_exit();
	return rv;
}

static void __exit avflt_exit(void)
{
	avflt_dev_exit();
	avflt_sys_exit();
	avflt_rfs_exit();
	avflt_data_exit();
	avflt_check_exit();
}

module_init(avflt_init);
module_exit(avflt_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Frantisek Hrbata <frantisek.hrbata@redirfs.org>");
MODULE_DESCRIPTION("Anti-Virus Filter for the RedirFS Framework");

driver/avflt/.svn/text-base/INSTALL.svn-base0000644000076400007640000000267112112622747020357 0ustar  comodocomodo			======================================
				 Installing AVFlt
			======================================

1. Requirements
	
	* Running Linux kernel version 2.6.25 and higher
	* Source code and configuration for running Linux kernel
	  - at least make scripts and make prepare
	* Linux kernel compiled with modules support
	* Compiled RedirFS Framework, please see the RedirFS's INSTALL file

2. Download
	
	* Get the latest stable version at
	  http://www.redirfs.org/packages/avflt-x.y.tar.gz

3. Compilation
	
	* Unpack package
		$ tar -xvzf avflt-x.y.tar.gz

	* Change to the avflt-x.y directory
		$ cd avflt-x.y

	* Copy the RedirFS's Module.symvers file to the AVFlt source tree.
	  For more info please see Documentation/kbuild/modules.txt
	  section "7.3 Symbols from another external module".
		$ cp <path to the RedirFS's source tree>/Module.symvers .

	* Run make command
		$ make -C /lib/modules/`uname -r`/build M=`pwd` \
			EXTRA_CFLAGS=-I<full path to the redirfs dir> modules

4. Inserting module

	* Change user to root
		$ su

	* Install modules 
		# make -C /lib/modules/`uname -r`/build M=`pwd` \
			EXTRA_CFLAGS=-I<full path to the redirfs dir> \
			modules_install

	* Update module dependencies
		# depmod -a

	* Load avflt.ko module
		# modprobe avflt

5. Problems & Bugs

	* RedirFS's bugzilla
	  http://www.redirfs.org/cgi-bin/bugzilla/index.cgi
	
	* RedirFS's mailing lists
	  http://www.redirfs.org/tiki-index.php?page=redirfs_maillists
driver/avflt/.svn/text-base/README.svn-base0000644000076400007640000000151712112622747020204 0ustar  comodocomodo		=========================
		AVFlt - Anti-Virus Filter
			  README
		=========================

This software is distributed under the GNU General Public License Version 3.

1. Introduction

	AVFlt or Anti-Virus Filter is a filter for the RedirFS Framework. It is
	intended for so-called on-access scanning, which means that files are 
	checked for malicious content on-the-fly before open and after close.
	AVFlt uses in kernel cache and it makes sure than only changed files are
	checked. It comes hand in hand with the libav library which should be
	used by Anti-Virus scanners.

	For an overview of the RedirFS project, visit 

		http://www.redirfs.org

2. Installation

	See the INSTALL file.

3. Documentation

	http://www.redirfs.org/tiki-index.php?page=redirfs_doc

4. Problems & Bugs
	
	http://www.redirfs.org/cgi-bin/bugzilla/index.cgi
driver/avflt/.svn/text-base/avflt_rfs.c.svn-base0000644000076400007640000001163712112622747021462 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static int avflt_should_check(struct file *file)
{
	if (avflt_is_stopped())
		return 0;

	if (avflt_proc_allow(current->tgid))
		return 0;

	if (avflt_trusted_allow(current->tgid))
		return 0;
	
	if (!file->f_dentry->d_inode)
		return 0;

	if (!i_size_read(file->f_dentry->d_inode))
		return 0;

	return 1;
}

static int avflt_check_cache(struct file *file, int type)
{
	struct avflt_root_data *root_data;
	struct avflt_inode_data *inode_data;
	int state = 0;
	int wc;

	if (!atomic_read(&avflt_cache_enabled))
		return 0;

	root_data = avflt_get_root_data_inode(file->f_dentry->d_inode);
	if (!root_data)
		return 0;

	if (!atomic_read(&root_data->cache_enabled)) {
		avflt_put_root_data(root_data);
		return 0;
	}

	inode_data = avflt_get_inode_data_inode(file->f_dentry->d_inode);
	if (!inode_data) {
		avflt_put_root_data(root_data);
		return 0;
	}

	wc = atomic_read(&file->f_dentry->d_inode->i_writecount);

	spin_lock(&inode_data->lock);

	if (wc == 1) {
		if (!(file->f_mode & FMODE_WRITE))
			inode_data->inode_cache_ver++;

		else if (type == AVFLT_EVENT_CLOSE)
			inode_data->inode_cache_ver++;

	} else if (wc > 1)
		inode_data->inode_cache_ver++;

	if (inode_data->root_data != root_data)
		goto exit;

	if (inode_data->root_cache_ver != atomic_read(&root_data->cache_ver))
		goto exit;

	if (inode_data->cache_ver != inode_data->inode_cache_ver)
		goto exit;

	state = inode_data->state;
exit:
	spin_unlock(&inode_data->lock);
	avflt_put_inode_data(inode_data);
	avflt_put_root_data(root_data);
	return state;
}

static enum redirfs_rv avflt_eval_res(int rv, struct redirfs_args *args)
{
	if (rv < 0) {
		args->rv.rv_int = rv;
		return REDIRFS_STOP;
	} 

	if (rv == AVFLT_FILE_INFECTED) {
		args->rv.rv_int = -EPERM;
		return REDIRFS_STOP;
	}

	return REDIRFS_CONTINUE;
}

static enum redirfs_rv avflt_check_file(struct file *file, int type,
		struct redirfs_args *args)
{
	int rv;

	if (!avflt_should_check(file))
		return REDIRFS_CONTINUE;

	rv = avflt_check_cache(file, type);
	if (rv)
		return avflt_eval_res(rv, args);

	rv = avflt_process_request(file, type);
	if (rv)
		return avflt_eval_res(rv, args);

	return REDIRFS_CONTINUE;
}

static enum redirfs_rv avflt_pre_open(redirfs_context context,
		struct redirfs_args *args)
{
	struct file *file = args->args.f_open.file;

	return avflt_check_file(file, AVFLT_EVENT_OPEN, args);
}

static enum redirfs_rv avflt_post_release(redirfs_context context,
		struct redirfs_args *args)
{
	struct file *file = args->args.f_release.file;

	return avflt_check_file(file, AVFLT_EVENT_CLOSE, args);
}

static int avflt_activate(void)
{
	avflt_invalidate_cache();
	return redirfs_activate_filter(avflt);
}

static int avflt_add_path(struct redirfs_path_info *info)
{
	struct avflt_root_data *data;
	redirfs_path path;
	redirfs_root root;

	path = redirfs_add_path(avflt, info);
	if (IS_ERR(path))
		return PTR_ERR(path);

	root = redirfs_get_root_path(path);
	redirfs_put_path(path);
	if (!root)
		return 0;

	data = avflt_attach_root_data(root);

	redirfs_put_root(root);
	avflt_put_root_data(data);
	
	return 0;
}

redirfs_filter avflt;

static struct redirfs_filter_operations avflt_ops = {
	.activate = avflt_activate,
	.add_path = avflt_add_path
};

static struct redirfs_filter_info avflt_info = {
	.owner = THIS_MODULE,
	.name = "avflt",
	.priority = 850000000,
	.active = 1,
	.ops = &avflt_ops
};

static struct redirfs_op_info avflt_op_info[] = {
	{REDIRFS_REG_FOP_OPEN, avflt_pre_open, NULL},
	{REDIRFS_REG_FOP_RELEASE, avflt_post_release, NULL},
	{REDIRFS_OP_END, NULL, NULL}
};

int avflt_rfs_init(void)
{
	int err;
	int rv;

	avflt = redirfs_register_filter(&avflt_info);
	if (IS_ERR(avflt)) {
		rv = PTR_ERR(avflt);
		printk(KERN_ERR "avflt: register filter failed(%d)\n", rv);
		return rv;
	}

	rv = redirfs_set_operations(avflt, avflt_op_info);
	if (rv) {
		printk(KERN_ERR "avflt: set operations failed(%d)\n", rv);
		goto error;
	}

	return 0;
error:
	err = redirfs_unregister_filter(avflt);
	if (err) {
		printk(KERN_ERR "avflt: unregister filter failed(%d)\n", err);
		return 0;
	}

	redirfs_delete_filter(avflt);
	return rv;
}

void avflt_rfs_exit(void)
{
	redirfs_delete_filter(avflt);
}

driver/avflt/.svn/text-base/Makefile.svn-base0000644000076400007640000000017612112622747020764 0ustar  comodocomodoobj-m += avflt.o
avflt-objs :=  avflt_check.o avflt_data.o avflt_dev.o avflt_mod.o \
	avflt_proc.o avflt_rfs.o avflt_sysfs.o

driver/avflt/.svn/text-base/avflt.h.svn-base0000644000076400007640000001170612112622747020612 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _AVFLT_H
#define _AVFLT_H

#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <linux/mount.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
#include <linux/freezer.h>
#endif
#include <linux/fs.h>
#include <linux/slab.h>
#include <rfs.h>

#define AVFLT_VERSION	"0.6"

#define AVFLT_EVENT_OPEN	1
#define AVFLT_EVENT_CLOSE	2

#define AVFLT_FILE_CLEAN	1
#define AVFLT_FILE_INFECTED	2

struct avflt_event {
	struct list_head req_list;
	struct list_head proc_list;
	struct avflt_root_data *root_data;
	struct completion wait;
	atomic_t count;
	int type;
	int id;
	int result;
	struct vfsmount *mnt;
	struct dentry *dentry;
	unsigned int flags;
	struct file *file;
	int fd;
	int root_cache_ver;
	int cache_ver;
	int cache;
	pid_t pid;
	pid_t tgid;
};

struct avflt_event *avflt_event_get(struct avflt_event *event);
void avflt_event_put(struct avflt_event *event);
void avflt_readd_request(struct avflt_event *event);
struct avflt_event *avflt_get_request(void);
int avflt_process_request(struct file *file, int type);
void avflt_event_done(struct avflt_event *event);
int avflt_get_file(struct avflt_event *event);
void avflt_put_file(struct avflt_event *event);
void avflt_install_fd(struct avflt_event *event);
ssize_t avflt_copy_cmd(char __user *buf, size_t size,
		struct avflt_event *event);
int avflt_add_reply(struct avflt_event *event);
int avflt_request_empty(void);
void avflt_start_accept(void);
void avflt_stop_accept(void);
int avflt_is_stopped(void);
void avflt_rem_requests(void);
struct avflt_event *avflt_get_reply(const char __user *buf, size_t size);
int avflt_check_init(void);
void avflt_check_exit(void);

struct avflt_trusted {
	struct list_head list;
	pid_t tgid;
	int open;
};

int avflt_trusted_add(pid_t tgid);
void avflt_trusted_rem(pid_t tgid);
int avflt_trusted_allow(pid_t tgid);
ssize_t avflt_trusted_get_info(char *buf, int size);

struct avflt_proc {
	struct list_head list;
	struct list_head events; 
	spinlock_t lock;
	atomic_t count;
	pid_t tgid;
	int open;
};

struct avflt_proc *avflt_proc_get(struct avflt_proc *proc);
void avflt_proc_put(struct avflt_proc *proc);
struct avflt_proc *avflt_proc_find(pid_t tgid);
struct avflt_proc *avflt_proc_add(pid_t tgid);
void avflt_proc_rem(pid_t tgid);
int avflt_proc_allow(pid_t tgid);
int avflt_proc_empty(void);
void avflt_proc_add_event(struct avflt_proc *proc, struct avflt_event *event);
void avflt_proc_rem_event(struct avflt_proc *proc, struct avflt_event *event);
struct avflt_event *avflt_proc_get_event(struct avflt_proc *proc, int id);
ssize_t avflt_proc_get_info(char *buf, int size);

#define rfs_to_root_data(ptr) \
	container_of(ptr, struct avflt_root_data, rfs_data)

struct avflt_root_data {
	struct redirfs_data rfs_data;
	atomic_t cache_enabled;
	atomic_t cache_ver;
};

struct avflt_root_data *avflt_get_root_data_root(redirfs_root root);
struct avflt_root_data *avflt_get_root_data_inode(struct inode *inode);
struct avflt_root_data *avflt_get_root_data(struct avflt_root_data *data);
void avflt_put_root_data(struct avflt_root_data *data);
struct avflt_root_data *avflt_attach_root_data(redirfs_root root);

#define rfs_to_inode_data(ptr) \
	container_of(ptr, struct avflt_inode_data, rfs_data)

struct avflt_inode_data {
	struct redirfs_data rfs_data;
	struct avflt_root_data *root_data;
	int root_cache_ver;
	int inode_cache_ver;
	int cache_ver;
	int state;
	spinlock_t lock;
};

struct avflt_inode_data *avflt_get_inode_data_inode(struct inode *inode);
struct avflt_inode_data *avflt_get_inode_data(struct avflt_inode_data *data);
void avflt_put_inode_data(struct avflt_inode_data *data);
struct avflt_inode_data *avflt_attach_inode_data(struct inode *inode);
int avflt_data_init(void);
void avflt_data_exit(void);

void avflt_invalidate_cache_root(redirfs_root root);
void avflt_invalidate_cache(void);

int avflt_dev_init(void);
void avflt_dev_exit(void);

int avflt_rfs_init(void);
void avflt_rfs_exit(void);

int avflt_sys_init(void);
void avflt_sys_exit(void);

extern atomic_t avflt_reply_timeout;
extern atomic_t avflt_cache_enabled;
extern redirfs_filter avflt;
extern wait_queue_head_t avflt_request_available;

#endif

driver/avflt/.svn/text-base/avflt_dev.c.svn-base0000644000076400007640000001026012112622747021435 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

static struct class *avflt_class;
static struct device *avflt_device;
static dev_t avflt_dev;

static int avflt_dev_open_registered(struct inode *inode, struct file *file)
{
	struct avflt_proc *proc;

	if (avflt_proc_empty())
		avflt_invalidate_cache();

	proc = avflt_proc_add(current->tgid);
	if (IS_ERR(proc))
		return PTR_ERR(proc);

	avflt_proc_put(proc);
	avflt_start_accept();
	return 0;
}

static int avflt_dev_open_trusted(struct inode *inode, struct file *file)
{
	return avflt_trusted_add(current->tgid);
}

static int avflt_dev_open(struct inode *inode, struct file *file)
{
	if (file->f_mode & FMODE_WRITE)
		return avflt_dev_open_registered(inode, file);

	return avflt_dev_open_trusted(inode, file);
}

static int avflt_dev_release_registered(struct inode *inode, struct file *file)
{
	avflt_proc_rem(current->tgid);
	if (!avflt_proc_empty())
		return 0;

	avflt_stop_accept();
	avflt_rem_requests();
	return 0;
}

static int avflt_dev_release_trusted(struct inode *inode, struct file *file)
{
	avflt_trusted_rem(current->tgid);
	return 0;
}

static int avflt_dev_release(struct inode *inode, struct file *file)
{
	if (file->f_mode & FMODE_WRITE)
		return avflt_dev_release_registered(inode, file);

	return avflt_dev_release_trusted(inode, file);
}

static ssize_t avflt_dev_read(struct file *file, char __user *buf,
		size_t size, loff_t *pos)
{
	struct avflt_event *event;
	ssize_t len;
	ssize_t rv;

	if (!(file->f_mode & FMODE_WRITE))
		return -EINVAL;

	event = avflt_get_request();
	if (!event)
		return 0;

	rv = avflt_get_file(event);
	if (rv)
		goto error;

	rv = len = avflt_copy_cmd(buf, size, event);
	if (rv < 0)
		goto error;

	rv = avflt_add_reply(event);
	if (rv)
		goto error;

	avflt_install_fd(event);
	avflt_event_put(event);
	return len;
error:
	avflt_put_file(event);
	avflt_readd_request(event);
	avflt_event_put(event);
	return rv;
}

static ssize_t avflt_dev_write(struct file *file, const char __user *buf,
		size_t size, loff_t *pos)
{
	struct avflt_event *event;

	event = avflt_get_reply(buf, size);
	if (IS_ERR(event))
		return PTR_ERR(event);

	avflt_event_done(event);
	avflt_event_put(event);
	return size;
}

static unsigned int avflt_poll(struct file *file, poll_table *wait)
{
	unsigned int mask;

	poll_wait(file, &avflt_request_available, wait);

	mask = POLLOUT | POLLWRNORM;

	if (!avflt_request_empty())
		mask |= POLLIN | POLLRDNORM;

	return mask;
}

static struct file_operations avflt_fops = {
	.owner = THIS_MODULE,
	.open = avflt_dev_open,
	.release = avflt_dev_release,
	.read = avflt_dev_read,
	.write = avflt_dev_write,
	.poll = avflt_poll
};

int avflt_dev_init(void)
{
	int major;

	major = register_chrdev(0, "avflt", &avflt_fops);
	if (major < 0)
		return major;

	avflt_dev = MKDEV(major, 0);

	avflt_class = class_create(THIS_MODULE, "avflt");
	if (IS_ERR(avflt_class)) {
		unregister_chrdev(major, "avflt");
		return PTR_ERR(avflt_class);
	}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
	avflt_device = device_create(avflt_class, NULL, avflt_dev, "avflt");
#else
	avflt_device = device_create(avflt_class, NULL, avflt_dev, NULL, "avflt");
#endif
	if (IS_ERR(avflt_device)) {
		class_destroy(avflt_class);
		unregister_chrdev(major, "avflt");
		return PTR_ERR(avflt_device);
	}

	return 0;
}

void avflt_dev_exit(void)
{
	device_destroy(avflt_class, avflt_dev);
	class_destroy(avflt_class);
	unregister_chrdev(MAJOR(avflt_dev), "avflt");
}

driver/avflt/.svn/text-base/avflt_sysfs.c.svn-base0000644000076400007640000001361112112622747022031 0ustar  comodocomodo/*
 * AVFlt: Anti-Virus Filter
 * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org>
 *
 * Copyright 2008 - 2010 Frantisek Hrbata
 * All rights reserved.
 *
 * This file is part of RedirFS.
 *
 * RedirFS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedirFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedirFS. If not, see <http://www.gnu.org/licenses/>.
 */

#include "avflt.h"

atomic_t avflt_reply_timeout = ATOMIC_INIT(0);
atomic_t avflt_cache_enabled = ATOMIC_INIT(1);

static ssize_t avflt_timeout_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	return snprintf(buf, PAGE_SIZE, "%d",
			atomic_read(&avflt_reply_timeout));
}

static ssize_t avflt_timeout_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	int timeout;

	if (sscanf(buf, "%d", &timeout) != 1)
		return -EINVAL;

	if (timeout < 0)
		return -EINVAL;

	atomic_set(&avflt_reply_timeout, timeout);

	return count;
}

static ssize_t avflt_cache_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	char state;

	if (atomic_read(&avflt_cache_enabled))
		state = 'a';
	else
		state = 'd';

	return snprintf(buf, PAGE_SIZE, "%c", state);
}

static ssize_t avflt_cache_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	char cache;

	if (sscanf(buf, "%c", &cache) != 1)
		return -EINVAL;

	switch (cache) {
		case 'a':
			avflt_invalidate_cache();
			atomic_set(&avflt_cache_enabled, 1);
			break;

		case 'd':
			atomic_set(&avflt_cache_enabled, 0);
			break;

		case 'i':
			avflt_invalidate_cache();
			break;

		default:
			return -EINVAL;
	}

	return count;
}

static ssize_t avflt_cache_paths_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	struct avflt_root_data *data;
	redirfs_path *paths;
	redirfs_root root;
	ssize_t size = 0;
	char state;
	int i = 0;

	paths = redirfs_get_paths(avflt);
	if (IS_ERR(paths))
		return PTR_ERR(paths);

	while (paths[i]) {
		root = redirfs_get_root_path(paths[i]);
		if (!root)
			goto next;

		data = avflt_get_root_data_root(root);
		redirfs_put_root(root);
		if (!data)
			goto next;

		if (atomic_read(&data->cache_enabled))
			state = 'a';
		else
			state = 'd';

		avflt_put_root_data(data);

		size += snprintf(buf + size, PAGE_SIZE - size, "%d:%c",
				redirfs_get_id_path(paths[i]), state) + 1;

		if (size >= PAGE_SIZE)
			break;
next:
		i++;
	}

	redirfs_put_paths(paths);
	return size;
}

static ssize_t avflt_cache_paths_store(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, const char *buf,
		size_t count)
{
	struct avflt_root_data *data;
	redirfs_path path;
	redirfs_root root;
	char cache;
	int id;

	if (sscanf(buf, "%c:%d", &cache, &id) != 2)
		return -EINVAL;

	path = redirfs_get_path_id(id);
	if (!path)
		return -ENOENT;

	root = redirfs_get_root_path(path);
	redirfs_put_path(path);
	if (!root)
		return -ENOENT;

	data = avflt_get_root_data_root(root);
	redirfs_put_root(root);
	if (!data)
		return -ENOENT;

	switch (cache) {
		case 'a':
			atomic_inc(&data->cache_ver);
			atomic_set(&data->cache_enabled, 1);
			break;
		case 'd':
			atomic_set(&data->cache_enabled, 0);
			break;
		case 'i':
			atomic_inc(&data->cache_ver);
			break;

		default:
			avflt_put_root_data(data);
			return -EINVAL;

	}

	avflt_put_root_data(data);

	return count;
}

static ssize_t avflt_registered_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	return avflt_proc_get_info(buf, PAGE_SIZE);
}

static ssize_t avflt_trusted_show(redirfs_filter filter,
		struct redirfs_filter_attribute *attr, char *buf)
{
	return avflt_trusted_get_info(buf, PAGE_SIZE);
}

static struct redirfs_filter_attribute avflt_timeout_attr = 
	REDIRFS_FILTER_ATTRIBUTE(timeout, 0644, avflt_timeout_show,
			avflt_timeout_store);

static struct redirfs_filter_attribute avflt_cache_attr = 
	REDIRFS_FILTER_ATTRIBUTE(cache, 0644, avflt_cache_show,
			avflt_cache_store);

static struct redirfs_filter_attribute avflt_pathcache_attr = 
	REDIRFS_FILTER_ATTRIBUTE(cache_paths, 0644, avflt_cache_paths_show,
			avflt_cache_paths_store);

static struct redirfs_filter_attribute avflt_registered_attr = 
	REDIRFS_FILTER_ATTRIBUTE(registered, 0444, avflt_registered_show, NULL);

static struct redirfs_filter_attribute avflt_trusted_attr = 
	REDIRFS_FILTER_ATTRIBUTE(trusted, 0444, avflt_trusted_show, NULL);

int avflt_sys_init(void)
{
	int rv;

	rv = redirfs_create_attribute(avflt, &avflt_timeout_attr);
	if (rv)
		return rv;

	rv = redirfs_create_attribute(avflt, &avflt_cache_attr);
	if (rv)
		goto err_cache;

	rv = redirfs_create_attribute(avflt, &avflt_pathcache_attr);
	if (rv)
		goto err_pathcache;

	rv = redirfs_create_attribute(avflt, &avflt_registered_attr);
	if (rv)
		goto err_registered;

	rv = redirfs_create_attribute(avflt, &avflt_trusted_attr);
	if (rv)
		goto err_trusted;

	return 0;

err_trusted:
	redirfs_remove_attribute(avflt, &avflt_registered_attr);
err_registered:
	redirfs_remove_attribute(avflt, &avflt_pathcache_attr);
err_pathcache:
	redirfs_remove_attribute(avflt, &avflt_cache_attr);
err_cache:
	redirfs_remove_attribute(avflt, &avflt_timeout_attr);
	return rv;
}

void avflt_sys_exit(void)
{
	redirfs_remove_attribute(avflt, &avflt_timeout_attr);
	redirfs_remove_attribute(avflt, &avflt_cache_attr);
	redirfs_remove_attribute(avflt, &avflt_pathcache_attr);
	redirfs_remove_attribute(avflt, &avflt_registered_attr);
	redirfs_remove_attribute(avflt, &avflt_trusted_attr);
}

driver/avflt/.svn/text-base/CHANGELOG.svn-base0000644000076400007640000000271412112622747020536 0ustar  comodocomodoversion 0.6 2010-05-20
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- reflected changes in 2.6.34 kernel
		- include of <linux/slab.h>

version 0.5 2010-04-09
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed memory leak in avflt_proc_add()
	  thanks to Robert Minsk <robertminsk@yahoo.com>
	- proper canceling of pending requests when application is unregistered
	  form avflt
	  thanks to Timo Metsala <timo.metsala@f-secure.com>
	- user-space <==> kernel protocol extended for cache option
	  0 - do not cache cache event result
	  1 - cache event result
	  This is intended to be used by the user-space anti-virus applications
	  when a file cannot be scanned or when an error occurred during scan.
	  In this case application can allow or deny access to the file and it
	  should set the result to not be cached. Next time the file is accessed
	  it is send again for scan instead of returning result from cache.

version 0.4
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- dentry_open adapted to new 2.6.29 security context - struct cred
	- added support for "trusted" processes
	- added sysfs interface for registered and trusted processes

version 0.3
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- better fix of open for files bigger then 2GB
	  O_LARGEFILE flag is set base on original f_flags

version 0.2
	* Frantisek Hrbata <frantisek.hrbata@redirfs.org>
	- fixed open for files bigger then 2GB(MAX_NON_LFS)

version 0.1
	* initial release

driver/avflt/.svn/props/0000755000076400007640000000000012112622747015052 5ustar  comodocomododriver/avflt/.svn/entries0000644000076400007640000000430212112622747015302 0ustar  comodocomodo10

dir
268025
https://svn.mcr.colo.comodoca.net/svn/repos/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt
https://svn.mcr.colo.comodoca.net/svn/repos



2011-11-30T02:02:53.196901Z
217894
chenpeng














03944601-d801-0410-bf24-f2e5d3b8ba88

avflt_proc.c
file




2013-02-18T02:00:35.000000Z
87b5459d984b597415fa0618b9ee2173
2011-11-18T07:31:50.813877Z
216573
yangb





















6694

avflt.h
file




2013-02-18T02:00:35.000000Z
751f2a1197833807e7de1299fe3c50ff
2011-11-25T01:59:10.548756Z
217359
chenpeng





















5062

avflt_sysfs.c
file




2013-02-18T02:00:35.000000Z
154692f2281ef8ba6d1d2bfba6ec73d5
2011-07-01T08:28:03.926547Z
196014
chenpeng





















6025

INSTALL
file




2013-02-18T02:00:35.000000Z
c1212b0cc0da2dcf5761c02808a57ae1
2011-07-01T08:28:03.926547Z
196014
chenpeng





















1465

avflt_data.c
file




2013-02-18T02:00:35.000000Z
22d4079a3c65993945db756ca35d3f4e
2011-11-25T01:59:10.548756Z
217359
chenpeng





















5177

CHANGELOG
file




2013-02-18T02:00:35.000000Z
2d02cbc766ee841e2b7bf73edd182d7d
2011-07-01T08:28:03.926547Z
196014
chenpeng





















1484

avflt_rfs.c
file




2013-02-18T02:00:35.000000Z
b80dbb5aa7cbe455dbd1a3a92e321277
2011-07-01T08:28:03.926547Z
196014
chenpeng





















5023

COPYING
file




2013-02-18T02:00:35.000000Z
d32239bcb673463ab874e80d47fae504
2011-07-01T08:28:03.926547Z
196014
chenpeng





















35147

avflt_check.c
file




2013-02-18T02:00:35.000000Z
f92d9c6425e03e03caab20bae18ad76a
2011-11-30T02:02:53.196901Z
217894
chenpeng





















10337

avflt_dev.c
file




2013-02-18T02:00:35.000000Z
df2c869322c2207aaead9b249d84c078
2011-07-01T08:28:03.926547Z
196014
chenpeng





















4272

avflt_mod.c
file




2013-02-18T02:00:35.000000Z
26949161f5dea0972ab34acde6aaaa1d
2011-07-01T08:28:03.926547Z
196014
chenpeng





















1737

Makefile
file




2013-02-18T02:00:35.000000Z
f88350d59eafc8bbeec02d235b4c99c7
2011-07-01T08:28:03.926547Z
196014
chenpeng





















126

README
file




2013-02-18T02:00:35.000000Z
2a87e07e7b2f063f0b8da7eec29c37bd
2011-07-01T08:28:03.926547Z
196014
chenpeng





















847

driver/avflt/.svn/prop-base/0000755000076400007640000000000012112622747015577 5ustar  comodocomododriver/avflt/.svn/all-wcprops0000644000076400007640000000372212112622747016101 0ustar  comodocomodoK 25
svn:wc:ra_dav:version-url
V 82
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt
END
avflt_proc.c
K 25
svn:wc:ra_dav:version-url
V 95
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/avflt_proc.c
END
avflt.h
K 25
svn:wc:ra_dav:version-url
V 90
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/avflt.h
END
avflt_sysfs.c
K 25
svn:wc:ra_dav:version-url
V 96
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/avflt_sysfs.c
END
INSTALL
K 25
svn:wc:ra_dav:version-url
V 90
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/INSTALL
END
avflt_data.c
K 25
svn:wc:ra_dav:version-url
V 95
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/avflt_data.c
END
CHANGELOG
K 25
svn:wc:ra_dav:version-url
V 92
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/CHANGELOG
END
avflt_rfs.c
K 25
svn:wc:ra_dav:version-url
V 94
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/avflt_rfs.c
END
COPYING
K 25
svn:wc:ra_dav:version-url
V 90
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/COPYING
END
avflt_check.c
K 25
svn:wc:ra_dav:version-url
V 96
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/avflt_check.c
END
avflt_dev.c
K 25
svn:wc:ra_dav:version-url
V 94
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/avflt_dev.c
END
avflt_mod.c
K 25
svn:wc:ra_dav:version-url
V 94
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/avflt_mod.c
END
Makefile
K 25
svn:wc:ra_dav:version-url
V 91
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/Makefile
END
README
K 25
svn:wc:ra_dav:version-url
V 89
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/avflt/README
END
driver/avflt/.svn/tmp/0000755000076400007640000000000012112622747014507 5ustar  comodocomododriver/avflt/.svn/tmp/text-base/0000755000076400007640000000000012112622747016403 5ustar  comodocomododriver/avflt/.svn/tmp/props/0000755000076400007640000000000012112622747015652 5ustar  comodocomododriver/avflt/.svn/tmp/prop-base/0000755000076400007640000000000012112622747016377 5ustar  comodocomododriver/Makefile0000644000076400007640000000116712112622747013354 0ustar  comodocomodo
all:
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/redirfs modules
	cp $(ROOT_PATH)/redirfs/Module.symvers $(ROOT_PATH)/avflt
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/avflt EXTRA_CFLAGS=-I$(ROOT_PATH)/redirfs modules

install:
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/redirfs modules_install
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/avflt EXTRA_CFLAGS=-I$(ROOT_PATH)/redirfs modules_install

clean:
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/avflt EXTRA_CFLAGS=-I$(ROOT_PATH)/redirfs clean
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/redirfs clean
	driver/.svn/0000755000076400007640000000000012112622747012573 5ustar  comodocomododriver/.svn/text-base/0000755000076400007640000000000012112622747014467 5ustar  comodocomododriver/.svn/text-base/Makefile.svn-base0000644000076400007640000000116712112622747017651 0ustar  comodocomodo
all:
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/redirfs modules
	cp $(ROOT_PATH)/redirfs/Module.symvers $(ROOT_PATH)/avflt
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/avflt EXTRA_CFLAGS=-I$(ROOT_PATH)/redirfs modules

install:
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/redirfs modules_install
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/avflt EXTRA_CFLAGS=-I$(ROOT_PATH)/redirfs modules_install

clean:
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/avflt EXTRA_CFLAGS=-I$(ROOT_PATH)/redirfs clean
	make -C /lib/modules/`uname -r`/build M=$(ROOT_PATH)/redirfs clean
	driver/.svn/props/0000755000076400007640000000000012112622747013736 5ustar  comodocomododriver/.svn/entries0000644000076400007640000000065512112622747014175 0ustar  comodocomodo10

dir
268025
https://svn.mcr.colo.comodoca.net/svn/repos/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver
https://svn.mcr.colo.comodoca.net/svn/repos



2011-11-30T02:02:53.196901Z
217894
chenpeng














03944601-d801-0410-bf24-f2e5d3b8ba88

avflt
dir

Makefile
file




2013-02-18T02:00:38.000000Z
414f032236c4546745c134b9ad5adaac
2011-11-21T08:37:48.032860Z
216732
chenpeng





















631

redirfs
dir

driver/.svn/prop-base/0000755000076400007640000000000012112622747014463 5ustar  comodocomododriver/.svn/all-wcprops0000644000076400007640000000037412112622747014765 0ustar  comodocomodoK 25
svn:wc:ra_dav:version-url
V 76
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver
END
Makefile
K 25
svn:wc:ra_dav:version-url
V 85
/svn/repos/!svn/ver/218202/COMODOAVforNonWin/AV4LINUX/trunk/CAV_LINUX/driver/Makefile
END
driver/.svn/tmp/0000755000076400007640000000000012112622747013373 5ustar  comodocomododriver/.svn/tmp/text-base/0000755000076400007640000000000012112622747015267 5ustar  comodocomododriver/.svn/tmp/props/0000755000076400007640000000000012112622747014536 5ustar  comodocomododriver/.svn/tmp/prop-base/0000755000076400007640000000000012112622747015263 5ustar  comodocomodo