429 lines
17 KiB
C
429 lines
17 KiB
C
|
/* cache.h: directory and file cache.
|
||
|
Copyright (C) 2006, 2007, 2008, 2009 Werner Baumann
|
||
|
|
||
|
This file is part of davfs2.
|
||
|
|
||
|
davfs2 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.
|
||
|
|
||
|
davfs2 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 davfs2; if not, write to the Free Software Foundation,
|
||
|
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||
|
|
||
|
|
||
|
#ifndef DAV_CACHE_H
|
||
|
#define DAV_CACHE_H
|
||
|
|
||
|
|
||
|
/* Constants */
|
||
|
/*===========*/
|
||
|
|
||
|
/* A mask to separate access bits from mode. */
|
||
|
#define DAV_A_MASK (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX)
|
||
|
|
||
|
|
||
|
/* Data Types */
|
||
|
/*============*/
|
||
|
|
||
|
/* File descriptors for open files are stored within a dav_node in a linked
|
||
|
list. As coda does not return the file descriptor when closing a file,
|
||
|
this data structure contains additional information to identify the
|
||
|
appropriate file descriptor. */
|
||
|
typedef struct dav_handle dav_handle;
|
||
|
struct dav_handle {
|
||
|
dav_handle *next; /* Next in the list. */
|
||
|
int fd; /* File descriptor of the open file. */
|
||
|
int flags; /* Access mode flags only. */
|
||
|
pid_t pid; /* id of requesting process. */
|
||
|
pid_t pgid; /* Group id of requesting process. */
|
||
|
uid_t uid; /* User id of requesting process. */
|
||
|
};
|
||
|
|
||
|
|
||
|
/* A node in the cache. It represents a directory or a regular file.
|
||
|
Nodes that are direct childs of the same directory-node are linked together
|
||
|
by the next-pointer to a linked list.
|
||
|
The hierarchical directory structure is formed by pointers to the parent
|
||
|
direcotry and to the first member in the linked list of direct childs.
|
||
|
Nodes are also stored in a hash table. The hash is derived from the nodes
|
||
|
address. Nodes with the same hash value are linked together by table_next. */
|
||
|
typedef struct dav_node dav_node;
|
||
|
struct dav_node {
|
||
|
/* The parent directory. */
|
||
|
dav_node *parent;
|
||
|
/* The first node in the linked list of childs. Will be NULL for files.*/
|
||
|
dav_node *childs;
|
||
|
/* The next node in the linked list of childs. */
|
||
|
dav_node *next;
|
||
|
/* The next node in the linked list of nodes with the same hash value. */
|
||
|
dav_node *table_next;
|
||
|
/* The unescaped absolute path of the resource on the server. This must
|
||
|
conform to RFC 2518. For collections it must have a trailing slash, for
|
||
|
non-collections it must not have one. */
|
||
|
char *path;
|
||
|
/* The name of the node (not path) without leading or trailing slash. The
|
||
|
name of the root node is the empty string. Name may be different from
|
||
|
the last component of path if the servers uses display-names. */
|
||
|
char *name;
|
||
|
/* Path of the file where the contents of the node is cached. These files
|
||
|
are only created when needed, and they are deleted when there is
|
||
|
information that the contents is no langer valid.
|
||
|
So cache_path may be NULL.
|
||
|
For directories: A file containing the directory entries.
|
||
|
For regular files: A local copy of the file.
|
||
|
File times are set according the values from the server when the file
|
||
|
is downloaded. As long as the file is cached only dav_set_attr() may
|
||
|
changed file attributes directly, but they may be changed by open,
|
||
|
read, write and close. */
|
||
|
char *cache_path;
|
||
|
/* Etag from the server. Set when the resource is downloaded. Used for
|
||
|
conditional GET requests and to detect whether a resource has been
|
||
|
changed remotely. If present it overrides information from the
|
||
|
Last-Modified time (smtime). */
|
||
|
char *etag;
|
||
|
/* The media-type as in HTTP-header Content-Type. */
|
||
|
char *mime_type;
|
||
|
/* A linked list of handles for open files. */
|
||
|
dav_handle *handles;
|
||
|
/* Size of the contents of the node.
|
||
|
Files: Initially set to the value of the content-lenght header. When
|
||
|
the file is open it is updated to the size of the cached file.
|
||
|
Directories: Size of the file containing the directory entries. */
|
||
|
off_t size;
|
||
|
/* Initially set to the value of mtime. Updated by some upcalls
|
||
|
Files: When a local copy exists its atime is also used for update. */
|
||
|
time_t atime;
|
||
|
/* Initially set to the last-modified time from the server, or the system
|
||
|
time if created locally.
|
||
|
Files: When a local cache file exists updated to mtime of this cache file.
|
||
|
Used to evaluate whether a file is dirty. */
|
||
|
time_t mtime;
|
||
|
/* Initially set to the value of mtime. Updated by dav_setattr(). */
|
||
|
time_t ctime;
|
||
|
/* Files: Last-modified time from the server. Like etag frozen when the
|
||
|
file is opened for writing. Used to check whether the file has
|
||
|
been changed remotely. */
|
||
|
time_t smtime;
|
||
|
/* Time when the node has last been updated from the server. */
|
||
|
time_t utime;
|
||
|
/* Files: Time when the lock expires.
|
||
|
0 if not locked. -1 locked infinitely. */
|
||
|
time_t lock_expire;
|
||
|
/* Directories: Number of subdirectories, including "." and "..".
|
||
|
Files: Allways 1. */
|
||
|
int nref;
|
||
|
/* Files: File exists on the server. For locally created files that have
|
||
|
not been put to the server it will be 0.
|
||
|
Note: Some server create an empty file when locking. Maybe the RFC will
|
||
|
be changed this way. */
|
||
|
int remote_exists;
|
||
|
/* Files: Dirty flag. Must be set, when a file is opened for writing, and
|
||
|
reset, when the file is saved back. */
|
||
|
int dirty;
|
||
|
/* mode, uid and gid are initially set to the default values, but may be
|
||
|
changed by dav_setattr(). */
|
||
|
mode_t mode;
|
||
|
uid_t uid;
|
||
|
gid_t gid;
|
||
|
};
|
||
|
|
||
|
|
||
|
/* An item in a linked list. Each item holds a pointer to a dav_node.*/
|
||
|
typedef struct dav_node_item dav_node_list_item;
|
||
|
struct dav_node_item {
|
||
|
dav_node_list_item *next;
|
||
|
dav_node *node;
|
||
|
time_t save_at;
|
||
|
};
|
||
|
|
||
|
|
||
|
/* Returned by dav_statfs(). */
|
||
|
typedef struct dav_stat dav_stat;
|
||
|
struct dav_stat {
|
||
|
off_t blocks;
|
||
|
off_t bfree;
|
||
|
off_t bavail;
|
||
|
off_t files;
|
||
|
off_t ffree;
|
||
|
off_t bsize;
|
||
|
off_t namelen;
|
||
|
};
|
||
|
|
||
|
|
||
|
/* Call back function that writes a directory entry to file descriptor fd.
|
||
|
fd : An open file descriptor to write to.
|
||
|
off : The current file size.
|
||
|
node : The pointer to node is taken as inode/file number (shrinked to
|
||
|
fit if necessary).
|
||
|
name : File name; if NULL, the last, empty entry is written (if the
|
||
|
kernel file system wants one).
|
||
|
return value : New size of the file. -1 in case of an error. */
|
||
|
typedef off_t (*dav_write_dir_entry_fn)(int fd, off_t off, const dav_node *node,
|
||
|
const char *name);
|
||
|
|
||
|
|
||
|
/* Function prototypes */
|
||
|
/*=====================*/
|
||
|
|
||
|
/* Initializing and closing the cache. */
|
||
|
|
||
|
/* Sets a lot of private global variables that govern the behaviour of the
|
||
|
cache, taking the values from parameters.
|
||
|
It registers dummy functions for the callbacks from kernel interface.
|
||
|
Creates the root node and restores the nodes from the permanent cache.
|
||
|
Finally it retrieves the root directory entries from the server.
|
||
|
If the connection to the server fails because of authentication failure
|
||
|
it prints an error message and terminates the programm. If the connection
|
||
|
fails due to other reasons, it will nevertheless return with success, as the
|
||
|
filesystem can be mounted, but will only get useable when the connection
|
||
|
comes up.
|
||
|
paramters: if not self explaining, please see mount_davfs.c, struct args. */
|
||
|
void
|
||
|
dav_init_cache(const dav_args *args, const char *mpoint);
|
||
|
|
||
|
|
||
|
/* Tries to write back to the server all open files that have been changed or
|
||
|
newly created. If a file from cache can not be stored back to the server,
|
||
|
a local backup file is created. All local copies of files and the necessary
|
||
|
directories are stored in the permanent cache. A new index file of the
|
||
|
permanent cache is created.
|
||
|
If got_sigterm is 1, dirty files will not be stored back to the server.
|
||
|
Finally it frees all nodes. */
|
||
|
void
|
||
|
dav_close_cache(int got_sigterm);
|
||
|
|
||
|
|
||
|
/* Registers the kernel_interface.
|
||
|
Sets pointers to the write_dir_entry_fn flush_flag.
|
||
|
If blksize is not NULL, the preferred bloksize for IO is asigned.
|
||
|
It returns the value of alignment. */
|
||
|
size_t
|
||
|
dav_register_kernel_interface(dav_write_dir_entry_fn write_fn, int *flush_flag,
|
||
|
unsigned int *blksize);
|
||
|
|
||
|
|
||
|
/* Scans the hash table for file nodes to be saved them back on the server,
|
||
|
locks to be refreshed and locks to be released.
|
||
|
If maximum cache size is reached, it removes the file with the lowest
|
||
|
access time from the cache.
|
||
|
It must be called regularly.
|
||
|
The return value indicates whether another run would be useful.
|
||
|
return value: 0 there is nothing left to do.
|
||
|
1 another call of dav_tidy_cache would be useful. */
|
||
|
int
|
||
|
dav_tidy_cache(void);
|
||
|
|
||
|
|
||
|
/* Upcalls from the kernel, via the interface module. */
|
||
|
|
||
|
/* All these functions will first check if the node addressed in the
|
||
|
parameters exists.
|
||
|
|
||
|
Common parameters (not all of this must be present in one function):
|
||
|
dav_node **nodep : Used to return a pointer to a node.
|
||
|
dav_node *node : A pointer to the node that shall be acted on.
|
||
|
dav_node *parent : A pointer to the parent directory of the node in question.
|
||
|
const char *name : Name of the node in question. It's is just one name, not
|
||
|
a path, and without any trailing or leading slashes.
|
||
|
uid_t uid : ID of the user that requested the operation.
|
||
|
|
||
|
Common return values:
|
||
|
0 Success.
|
||
|
EACCES Access is denied to user uid according to the acces bits.
|
||
|
EAGAIN A temporary failure in the connection to the WebDAV server.
|
||
|
EBUSY The action on the node can not be performed, as somebody else uses
|
||
|
it allready in a way that would collide with the requested action.
|
||
|
EEXIST Cration of a new node is requested with flag O_EXCL, but it exists.
|
||
|
EINVAL One of the parameters has an invalid value.
|
||
|
EIO Error performing I/O-operation. Usually there are problems in the
|
||
|
communication with the WebDAV server.
|
||
|
EISDIR The node is a directory but should not be.
|
||
|
ENOENT The file or directory does not exist.
|
||
|
ENOSPC There is not enough space on the server.
|
||
|
ENOTDIR The node is not a directory but the requested action needs it to be.
|
||
|
EPERM The reuested action is not allowed to user uid. */
|
||
|
|
||
|
|
||
|
/* Tests whether user uid has access described by how to node.
|
||
|
int how : A bit mask describing the kind of acces. It may be any combination
|
||
|
of R_OK, W_OK, X_OK and F_OK. */
|
||
|
int
|
||
|
dav_access(dav_node *node, uid_t uid, int how);
|
||
|
|
||
|
|
||
|
/* Closed file descriptor fd of node.
|
||
|
Permissions are not checked, but flags are compared to the ones used for
|
||
|
opening. If fd is 0 (coda), flags, pid and pgid are used to find the best
|
||
|
matching file descriptor.
|
||
|
Only access mode bits must be set in flags.*/
|
||
|
int
|
||
|
dav_close(dav_node *node, int fd, int flags, pid_t pid, pid_t pgid);
|
||
|
|
||
|
|
||
|
/* Creates a new file node with name name in directory parent. The file is
|
||
|
locked on the server. The new node is returned in nodep.
|
||
|
There must no node with name name allready exist in parent.
|
||
|
The new node is owned by uid; group is the primary group of uid. Mode is
|
||
|
set to mode, but with the bits from file_umask removed.
|
||
|
Permissions:
|
||
|
uid must have execute permission for parent and all of its ancestors, as
|
||
|
well as write permission for parent. */
|
||
|
int
|
||
|
dav_create(dav_node **nodep, dav_node *parent, const char *name, uid_t uid,
|
||
|
mode_t mode);
|
||
|
|
||
|
|
||
|
/* Checks whether node exists and uid has permissions. The kernel interface
|
||
|
may then translate attributes from node.
|
||
|
Permissions:
|
||
|
uid must have execute permission for parent and all of its ancestors, as
|
||
|
well as read permission for parent. */
|
||
|
int
|
||
|
dav_getattr(dav_node *node, uid_t uid);
|
||
|
|
||
|
|
||
|
/* Checks whether node exists and uid has permissions. The value of
|
||
|
extended attribute name is copied into buf. If its size is greater
|
||
|
than size, EOVERFLOW is returned.
|
||
|
Permissions:
|
||
|
uid must have execute permission for parent and all of its ancestors, as
|
||
|
well as read permission for parent. */
|
||
|
int
|
||
|
dav_getxattr(dav_node *node, const char *name, char *buf, size_t *size,
|
||
|
uid_t uid);
|
||
|
|
||
|
|
||
|
/* Returns the list of supported extended attributes. This is just
|
||
|
user.mime_type. */
|
||
|
int
|
||
|
dav_listxattr(dav_node *node, char *buf, size_t *size, uid_t uid);
|
||
|
|
||
|
|
||
|
/* Searches for a node with name name in the directory parent and returns the
|
||
|
node in nodep.
|
||
|
Permissions:
|
||
|
uid must have execute permission for parent and all of its ancestors, as
|
||
|
well as read permission for parent. */
|
||
|
int
|
||
|
dav_lookup(dav_node **nodep, dav_node *parent, const char *name, uid_t uid);
|
||
|
|
||
|
|
||
|
/* Creates a new directory named name in direcotry parent. The directory must
|
||
|
not yet exist. The new node is returned in nodep.
|
||
|
Owner will be uid, group the primary group of uid. Mode will be mode with
|
||
|
the bits from dir_umask removed.
|
||
|
Permissions:
|
||
|
uid must have execute permission for parent and all of its ancestors, as
|
||
|
well as write permission for parent. */
|
||
|
int
|
||
|
dav_mkdir(dav_node **nodep, dav_node *parent, const char *name, uid_t uid,
|
||
|
mode_t mode);
|
||
|
|
||
|
|
||
|
/* Opens file or directory node according to flags and returns file descriptor
|
||
|
fd. fd, together with pid, pgid and uid, is stored in node for read, write
|
||
|
and close operations.
|
||
|
Only the O_ACCESSMOE, O_APPEND and O_TRUNC bits in flags will be honoured.
|
||
|
O_CREATE and O_EXCL are not allowed.
|
||
|
Permissions:
|
||
|
uid must have execute permission for parent and all of its ancestors, as
|
||
|
as well as read and/or write permission for node, according to the
|
||
|
accessmode. */
|
||
|
int
|
||
|
dav_open(int *fd, dav_node *node, int flags, pid_t pid, pid_t pgid, uid_t uid);
|
||
|
|
||
|
/* Reads size bytes from file descriptor fd, starting at position offset
|
||
|
and copies them into buf.
|
||
|
The number of bytes read is returned in len.
|
||
|
The file must be opened readonly or readwrite. */
|
||
|
int
|
||
|
dav_read(ssize_t *len, dav_node * node, int fd, char *buf, size_t size,
|
||
|
off_t offset);
|
||
|
|
||
|
|
||
|
/* Removes file node name in directory parent from the cache and on the server.
|
||
|
The file must not be locked by another WebDAV client.
|
||
|
Permissions:
|
||
|
uid must have execute permission for parent and all of its ancestors, as
|
||
|
well as write permission for parent. */
|
||
|
int
|
||
|
dav_remove(dav_node *parent, const char *name, uid_t uid);
|
||
|
|
||
|
|
||
|
/* Moves file or directory src_name from directory src_parent to directory
|
||
|
dst_parent and renames it to dst_name.
|
||
|
If dst_name allready exists in dst_parent and is a directory, there must
|
||
|
be no files opened for writing in it.
|
||
|
Moves into the backup directory are not allowed.
|
||
|
Permissions:
|
||
|
uid must have execute permission for src_parent and dst_parent and all of
|
||
|
their ancestors, as well as write permission for src_parent and
|
||
|
dst_parent. */
|
||
|
int
|
||
|
dav_rename(dav_node *src_parent, const char *src_name, dav_node *dst_parent,
|
||
|
const char *dst_name, uid_t uid);
|
||
|
|
||
|
|
||
|
/* Removes direcotry name in directory parent.
|
||
|
The directory must be empty and not the local backup directory.
|
||
|
uid must have execute permission for parent and all of its ancestors, as
|
||
|
well as write permission for parent. */
|
||
|
int
|
||
|
dav_rmdir(dav_node *parent, const char *name, uid_t uid);
|
||
|
|
||
|
|
||
|
/* Returns a pointer to the root node in nodep.
|
||
|
Permissions:
|
||
|
uid must be root, as this function is only called when the file system is
|
||
|
mounted. */
|
||
|
int
|
||
|
dav_root(dav_node **nodep, uid_t uid);
|
||
|
|
||
|
|
||
|
/* Changes attributes of the node.
|
||
|
sm, so, ... are flags. A value of 1 indicates that the respective
|
||
|
attribute is to be changed.
|
||
|
Permissions:
|
||
|
uid must have execute permission for parent directory of node and all of
|
||
|
its ancestors.
|
||
|
To change mode, owner, or gid, uid must be owner of the node or root.
|
||
|
To change atime, mtime or size, uid must have write permission for
|
||
|
node.
|
||
|
To change gid, uid must be member of the new group or root.
|
||
|
Note: This attributes, except size and the execute bit of mode, are only
|
||
|
changed locally and not on the server. */
|
||
|
int
|
||
|
dav_setattr(dav_node *node, uid_t uid, int sm, mode_t mode, int so,
|
||
|
uid_t owner, int sg, gid_t gid, int sat, time_t atime, int smt,
|
||
|
time_t mtime, int ssz, off_t size);
|
||
|
|
||
|
/* Returns struct dav_stat which currently is mainly fake.
|
||
|
No permissions necessary. */
|
||
|
dav_stat dav_statfs(void);
|
||
|
|
||
|
|
||
|
/* Calls fsync() for all filedescriptors of node, that are not read only.
|
||
|
No permissions are checked. */
|
||
|
int
|
||
|
dav_sync(dav_node *node);
|
||
|
|
||
|
|
||
|
/* Writes size bytes from buf to file descriptor fd, starting at position
|
||
|
offset.
|
||
|
The number of bytes written is returned in len.
|
||
|
The file must be opened writeonly or readwrite. */
|
||
|
/* TODO: Remove pid; check flags. */
|
||
|
int
|
||
|
dav_write(size_t *written, dav_node * node, int fd, char *buf, size_t size,
|
||
|
off_t offset);
|
||
|
|
||
|
|
||
|
#endif /* DAV_CACHE_H */
|