first import

This commit is contained in:
wbaumann
2009-04-14 19:54:53 +00:00
commit d12d77382e
60 changed files with 28149 additions and 0 deletions

62
src/Makefile.am Normal file
View File

@ -0,0 +1,62 @@
## Makefile for program src directory in davfs.
## 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. */
## Process this file with automake to produce Makefile.in
localedir = $(datadir)/locale
pkgsysconfdir = $(sysconfdir)/@PACKAGE@
pkglocalstatedir = $(dav_localstatedir)/mount.davfs
pkgsyscachedir = $(dav_syscachedir)/@PACKAGE@
ssbindir = @ssbindir@
sbin_PROGRAMS = mount.davfs umount.davfs
mount_davfs_SOURCES = cache.c dav_coda.c \
dav_fuse.c kernel_interface.c mount_davfs.c webdav.c \
cache.h coda.h defaults.h fuse_kernel.h \
kernel_interface.h mount_davfs.h webdav.h
umount_davfs_SOURCES = umount_davfs.c defaults.h
AM_CFLAGS = -Wall
DEFS = -DPROGRAM_NAME=\"mount.davfs\" \
-DDAV_SYS_CONF_DIR=\"$(pkgsysconfdir)\" \
-DDAV_SYS_RUN=\"$(pkglocalstatedir)\" \
-DDAV_SYS_CACHE=\"$(pkgsyscachedir)\" \
-DDAV_SECRETS=\"secrets\" \
-DDAV_CONFIG=\"$(PACKAGE).conf\" \
-DDAV_CERTS_DIR=\"certs\" \
-DDAV_CLICERTS_DIR=\"private\" \
-DDAV_DATA_DIR=\"$(pkgdatadir)\" \
-DLOCALEDIR=\"$(localedir)\" \
-DDAV_USER=\"$(dav_user)\" \
-DDAV_GROUP=\"$(dav_group)\" @DEFS@
LIBS = $(NEON_LIBS) @LIBS@
install-exec-hook:
chmod u+s $(DESTDIR)$(sbindir)/mount.davfs; \
if test "$(sbindir)" != "$(ssbindir)"; then \
$(mkinstalldirs) $(DESTDIR)$(ssbindir); \
$(LN_S) -f $(DESTDIR)$(sbindir)/mount.davfs $(DESTDIR)$(ssbindir)/mount.davfs; \
$(LN_S) -f $(DESTDIR)$(sbindir)/umount.davfs $(DESTDIR)$(ssbindir)/umount.davfs; \
fi
uninstall-hook:
if test "$(sbindir)" != "$(ssbindir)"; then \
rm -f $(DESTDIR)$(ssbindir)/mount.davfs; \
rm -f $(DESTDIR)$(ssbindir)/umount.davfs; \
fi

3692
src/cache.c Normal file

File diff suppressed because it is too large Load Diff

428
src/cache.h Normal file
View File

@ -0,0 +1,428 @@
/* 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 */

643
src/coda.h Normal file
View File

@ -0,0 +1,643 @@
/* This header file was taken from Linux kernel 2.6.18.
From the two alternative licences the Carnegie Mellon University
specific licence has been chosen.
Definitions intended for use by the kernel and not for userspace,
old API definitions and other parts unused by davfs2 have been removed.
Modifications by Werner Baumann, 2009-04-14. */
/*
Coda: an Experimental Distributed File System
Release 4.0
Copyright (c) 1987-1999 Carnegie Mellon University
All Rights Reserved
Permission to use, copy, modify and distribute this software and its
documentation is hereby granted, provided that both the copyright
notice and this permission notice appear in all copies of the
software, derivative works or modified versions, and any portions
thereof, and that both notices appear in supporting documentation, and
that credit is given to Carnegie Mellon University in all documents
and publicity pertaining to direct or indirect use of this code or its
derivatives.
CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
ANY DERIVATIVE WORK.
Carnegie Mellon encourages users of this software to return any
improvements or extensions that they make, and to grant Carnegie
Mellon the rights to redistribute these changes without encumbrance.
*/
/*
*
* Based on cfs.h from Mach, but revamped for increased simplicity.
* Linux modifications by
* Peter Braam, Aug 1996
*/
#ifndef _CODA_HEADER_
#define _CODA_HEADER_
#define cdev_t dev_t
#ifndef __BIT_TYPES_DEFINED__
#define __BIT_TYPES_DEFINED__
typedef signed char int8_t;
typedef unsigned char u_int8_t;
typedef short int16_t;
typedef unsigned short u_int16_t;
typedef int int32_t;
typedef unsigned int u_int32_t;
#endif
/*
* Cfs constants
*/
#define CODA_MAXNAMLEN 255
#define CODA_MAXPATHLEN 1024
#define CODA_MAXSYMLINK 10
/* these are Coda's version of O_RDONLY etc combinations
* to deal with VFS open modes
*/
#define C_O_READ 0x001
#define C_O_WRITE 0x002
#define C_O_TRUNC 0x010
#define C_O_EXCL 0x100
#define C_O_CREAT 0x200
/* these are to find mode bits in Venus */
#define C_M_READ 00400
#define C_M_WRITE 00200
/* for access Venus will use */
#define C_A_C_OK 8 /* Test for writing upon create. */
#define C_A_R_OK 4 /* Test for read permission. */
#define C_A_W_OK 2 /* Test for write permission. */
#define C_A_X_OK 1 /* Test for execute permission. */
#define C_A_F_OK 0 /* Test for existence. */
#ifndef _VENUS_DIRENT_T_
#define _VENUS_DIRENT_T_ 1
struct venus_dirent {
u_int32_t d_fileno; /* file number of entry */
u_int16_t d_reclen; /* length of this record */
u_int8_t d_type; /* file type, see below */
u_int8_t d_namlen; /* length of string in d_name */
char d_name[CODA_MAXNAMLEN + 1];/* name must be no longer than this */
};
#undef DIRSIZ
#define DIRSIZ(dp) ((sizeof (struct venus_dirent) - (CODA_MAXNAMLEN+1)) + \
(((dp)->d_namlen+1 + 3) &~ 3))
/*
* File types
*/
#define CDT_UNKNOWN 0
#define CDT_FIFO 1
#define CDT_CHR 2
#define CDT_DIR 4
#define CDT_BLK 6
#define CDT_REG 8
#define CDT_LNK 10
#define CDT_SOCK 12
#define CDT_WHT 14
/*
* Convert between stat structure types and directory types.
*/
#define IFTOCDT(mode) (((mode) & 0170000) >> 12)
#define CDTTOIF(dirtype) ((dirtype) << 12)
#endif
#ifndef _VUID_T_
#define _VUID_T_
typedef u_int32_t vuid_t;
typedef u_int32_t vgid_t;
#endif /*_VUID_T_ */
struct CodaFid {
u_int32_t opaque[4];
};
#define coda_f2i(fid)\
(fid ? (fid->opaque[3] ^ (fid->opaque[2]<<10) ^ (fid->opaque[1]<<20) ^ fid->opaque[0]) : 0)
#ifndef _VENUS_VATTR_T_
#define _VENUS_VATTR_T_
/*
* Vnode types. VNON means no type.
*/
enum coda_vtype { C_VNON, C_VREG, C_VDIR, C_VBLK, C_VCHR, C_VLNK, C_VSOCK, C_VFIFO, C_VBAD };
struct coda_vattr {
long va_type; /* vnode type (for create) */
u_short va_mode; /* files access mode and type */
short va_nlink; /* number of references to file */
vuid_t va_uid; /* owner user id */
vgid_t va_gid; /* owner group id */
long va_fileid; /* file id */
u_quad_t va_size; /* file size in bytes */
long va_blocksize; /* blocksize preferred for i/o */
struct timespec va_atime; /* time of last access */
struct timespec va_mtime; /* time of last modification */
struct timespec va_ctime; /* time file changed */
u_long va_gen; /* generation number of file */
u_long va_flags; /* flags defined for file */
cdev_t va_rdev; /* device special file represents */
u_quad_t va_bytes; /* bytes of disk space held by file */
u_quad_t va_filerev; /* file modification number */
};
#endif
/* structure used by CODA_STATFS for getting cache information from venus */
struct coda_statfs {
int32_t f_blocks;
int32_t f_bfree;
int32_t f_bavail;
int32_t f_files;
int32_t f_ffree;
};
/*
* Kernel <--> Venus communications.
*/
#define CODA_ROOT 2
#define CODA_OPEN_BY_FD 3
#define CODA_OPEN 4
#define CODA_CLOSE 5
#define CODA_IOCTL 6
#define CODA_GETATTR 7
#define CODA_SETATTR 8
#define CODA_ACCESS 9
#define CODA_LOOKUP 10
#define CODA_CREATE 11
#define CODA_REMOVE 12
#define CODA_LINK 13
#define CODA_RENAME 14
#define CODA_MKDIR 15
#define CODA_RMDIR 16
#define CODA_SYMLINK 18
#define CODA_READLINK 19
#define CODA_FSYNC 20
#define CODA_VGET 22
#define CODA_SIGNAL 23
#define CODA_REPLACE 24 /* DOWNCALL */
#define CODA_FLUSH 25 /* DOWNCALL */
#define CODA_PURGEUSER 26 /* DOWNCALL */
#define CODA_ZAPFILE 27 /* DOWNCALL */
#define CODA_ZAPDIR 28 /* DOWNCALL */
#define CODA_PURGEFID 30 /* DOWNCALL */
#define CODA_OPEN_BY_PATH 31
#define CODA_RESOLVE 32
#define CODA_REINTEGRATE 33
#define CODA_STATFS 34
#define CODA_STORE 35
#define CODA_RELEASE 36
#define CODA_NCALLS 37
#define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID)
#define VC_MAXDATASIZE 8192
#define VC_MAXMSGSIZE sizeof(union inputArgs)+sizeof(union outputArgs) +\
VC_MAXDATASIZE
#define CIOC_KERNEL_VERSION _IOWR('c', 10, size_t)
#define CODA_KERNEL_VERSION 3 /* 128-bit file identifiers */
/*
* Venus <-> Coda RPC arguments
*/
struct coda_in_hdr {
u_int32_t opcode;
u_int32_t unique; /* Keep multiple outstanding msgs distinct */
pid_t pid;
pid_t pgid;
vuid_t uid;
};
/* Really important that opcode and unique are 1st two fields! */
struct coda_out_hdr {
u_int32_t opcode;
u_int32_t unique;
u_int32_t result;
};
/* coda_root: NO_IN */
struct coda_root_out {
struct coda_out_hdr oh;
struct CodaFid VFid;
};
struct coda_root_in {
struct coda_in_hdr in;
};
/* coda_open: */
struct coda_open_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int flags;
};
struct coda_open_out {
struct coda_out_hdr oh;
cdev_t dev;
ino_t inode;
};
/* coda_store: */
struct coda_store_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int flags;
};
struct coda_store_out {
struct coda_out_hdr out;
};
/* coda_release: */
struct coda_release_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int flags;
};
struct coda_release_out {
struct coda_out_hdr out;
};
/* coda_close: */
struct coda_close_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int flags;
};
struct coda_close_out {
struct coda_out_hdr out;
};
/* coda_ioctl: */
struct coda_ioctl_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int cmd;
int len;
int rwflag;
char *data; /* Place holder for data. */
};
struct coda_ioctl_out {
struct coda_out_hdr oh;
int len;
caddr_t data; /* Place holder for data. */
};
/* coda_getattr: */
struct coda_getattr_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
};
struct coda_getattr_out {
struct coda_out_hdr oh;
struct coda_vattr attr;
};
/* coda_setattr: NO_OUT */
struct coda_setattr_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
struct coda_vattr attr;
};
struct coda_setattr_out {
struct coda_out_hdr out;
};
/* coda_access: NO_OUT */
struct coda_access_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int flags;
};
struct coda_access_out {
struct coda_out_hdr out;
};
/* lookup flags */
#define CLU_CASE_SENSITIVE 0x01
#define CLU_CASE_INSENSITIVE 0x02
/* coda_lookup: */
struct coda_lookup_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int name; /* Place holder for data. */
int flags;
};
struct coda_lookup_out {
struct coda_out_hdr oh;
struct CodaFid VFid;
int vtype;
};
/* coda_create: */
struct coda_create_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
struct coda_vattr attr;
int excl;
int mode;
int name; /* Place holder for data. */
};
struct coda_create_out {
struct coda_out_hdr oh;
struct CodaFid VFid;
struct coda_vattr attr;
};
/* coda_remove: NO_OUT */
struct coda_remove_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int name; /* Place holder for data. */
};
struct coda_remove_out {
struct coda_out_hdr out;
};
/* coda_link: NO_OUT */
struct coda_link_in {
struct coda_in_hdr ih;
struct CodaFid sourceFid; /* cnode to link *to* */
struct CodaFid destFid; /* Directory in which to place link */
int tname; /* Place holder for data. */
};
struct coda_link_out {
struct coda_out_hdr out;
};
/* coda_rename: NO_OUT */
struct coda_rename_in {
struct coda_in_hdr ih;
struct CodaFid sourceFid;
int srcname;
struct CodaFid destFid;
int destname;
};
struct coda_rename_out {
struct coda_out_hdr out;
};
/* coda_mkdir: */
struct coda_mkdir_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
struct coda_vattr attr;
int name; /* Place holder for data. */
};
struct coda_mkdir_out {
struct coda_out_hdr oh;
struct CodaFid VFid;
struct coda_vattr attr;
};
/* coda_rmdir: NO_OUT */
struct coda_rmdir_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int name; /* Place holder for data. */
};
struct coda_rmdir_out {
struct coda_out_hdr out;
};
/* coda_symlink: NO_OUT */
struct coda_symlink_in {
struct coda_in_hdr ih;
struct CodaFid VFid; /* Directory to put symlink in */
int srcname;
struct coda_vattr attr;
int tname;
};
struct coda_symlink_out {
struct coda_out_hdr out;
};
/* coda_readlink: */
struct coda_readlink_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
};
struct coda_readlink_out {
struct coda_out_hdr oh;
int count;
caddr_t data; /* Place holder for data. */
};
/* coda_fsync: NO_OUT */
struct coda_fsync_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
};
struct coda_fsync_out {
struct coda_out_hdr out;
};
/* coda_vget: */
struct coda_vget_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
};
struct coda_vget_out {
struct coda_out_hdr oh;
struct CodaFid VFid;
int vtype;
};
/* CODA_SIGNAL is out-of-band, doesn't need data. */
/* CODA_INVALIDATE is a venus->kernel call */
/* CODA_FLUSH is a venus->kernel call */
/* coda_purgeuser: */
/* CODA_PURGEUSER is a venus->kernel call */
struct coda_purgeuser_out {
struct coda_out_hdr oh;
vuid_t uid;
};
/* coda_zapfile: */
/* CODA_ZAPFILE is a venus->kernel call */
struct coda_zapfile_out {
struct coda_out_hdr oh;
struct CodaFid CodaFid;
};
/* coda_zapdir: */
/* CODA_ZAPDIR is a venus->kernel call */
struct coda_zapdir_out {
struct coda_out_hdr oh;
struct CodaFid CodaFid;
};
/* coda_purgefid: */
/* CODA_PURGEFID is a venus->kernel call */
struct coda_purgefid_out {
struct coda_out_hdr oh;
struct CodaFid CodaFid;
};
/* coda_replace: */
/* CODA_REPLACE is a venus->kernel call */
struct coda_replace_out { /* coda_replace is a venus->kernel call */
struct coda_out_hdr oh;
struct CodaFid NewFid;
struct CodaFid OldFid;
};
/* coda_open_by_fd: */
struct coda_open_by_fd_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int flags;
};
struct coda_open_by_fd_out {
struct coda_out_hdr oh;
int fd;
};
/* coda_open_by_path: */
struct coda_open_by_path_in {
struct coda_in_hdr ih;
struct CodaFid VFid;
int flags;
};
struct coda_open_by_path_out {
struct coda_out_hdr oh;
int path;
};
/* coda_statfs: NO_IN */
struct coda_statfs_in {
struct coda_in_hdr in;
};
struct coda_statfs_out {
struct coda_out_hdr oh;
struct coda_statfs stat;
};
union inputArgs {
struct coda_in_hdr ih; /* NB: every struct below begins with an ih */
struct coda_open_in coda_open;
struct coda_store_in coda_store;
struct coda_release_in coda_release;
struct coda_close_in coda_close;
struct coda_ioctl_in coda_ioctl;
struct coda_getattr_in coda_getattr;
struct coda_setattr_in coda_setattr;
struct coda_access_in coda_access;
struct coda_lookup_in coda_lookup;
struct coda_create_in coda_create;
struct coda_remove_in coda_remove;
struct coda_link_in coda_link;
struct coda_rename_in coda_rename;
struct coda_mkdir_in coda_mkdir;
struct coda_rmdir_in coda_rmdir;
struct coda_symlink_in coda_symlink;
struct coda_readlink_in coda_readlink;
struct coda_fsync_in coda_fsync;
struct coda_vget_in coda_vget;
struct coda_open_by_fd_in coda_open_by_fd;
struct coda_open_by_path_in coda_open_by_path;
struct coda_statfs_in coda_statfs;
};
union outputArgs {
struct coda_out_hdr oh; /* NB: every struct below begins with an oh */
struct coda_root_out coda_root;
struct coda_open_out coda_open;
struct coda_ioctl_out coda_ioctl;
struct coda_getattr_out coda_getattr;
struct coda_lookup_out coda_lookup;
struct coda_create_out coda_create;
struct coda_mkdir_out coda_mkdir;
struct coda_readlink_out coda_readlink;
struct coda_vget_out coda_vget;
struct coda_purgeuser_out coda_purgeuser;
struct coda_zapfile_out coda_zapfile;
struct coda_zapdir_out coda_zapdir;
struct coda_purgefid_out coda_purgefid;
struct coda_replace_out coda_replace;
struct coda_open_by_fd_out coda_open_by_fd;
struct coda_open_by_path_out coda_open_by_path;
struct coda_statfs_out coda_statfs;
};
union coda_downcalls {
/* CODA_INVALIDATE is a venus->kernel call */
/* CODA_FLUSH is a venus->kernel call */
struct coda_purgeuser_out purgeuser;
struct coda_zapfile_out zapfile;
struct coda_zapdir_out zapdir;
struct coda_purgefid_out purgefid;
struct coda_replace_out replace;
};
/* Data passed to mount */
#define CODA_MOUNT_VERSION 1
struct coda_mount_data {
int version;
int fd; /* Opened device */
};
#endif

810
src/dav_coda.c Normal file
View File

@ -0,0 +1,810 @@
/* dav_coda.c: interface to the Coda kernel module CODA_KERNEL_VERSION 3.
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. */
#include "config.h"
#include <errno.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_LIBINTL_H
#include <libintl.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <string.h>
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif
#include <time.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "defaults.h"
#include "mount_davfs.h"
#include "cache.h"
#include "kernel_interface.h"
#include "coda.h"
#ifdef ENABLE_NLS
#define _(String) gettext(String)
#else
#define _(String) String
#endif
/* Constants */
/*===========*/
/* Size of buffer for communication with the kernel module. */
#define BUF_SIZE 2048
/* This constants are used by davfs2 to fill fields of struct CodaFid that
are not used by davfs2, but are expected by coda. */
#define DAV_VOL 0x01234567
#define DAV_VNODE 0xffffffff
/* Private global variables */
/*==========================*/
/* Buffer used for communication with the kernel module (in and out). */
static char *buf;
/* The preferred blocksize used by the local filesystem for cache files.
Used by set_attr(). */
static unsigned int blocksize;
/* Alignment boundary of dav_node in byte.
Used to compute file numbers from node pointers. */
static size_t alignment;
/* Send debug messages to syslog if != 0. */
int debug;
/* Private function prototypes */
/*=============================*/
/* Functions to handle upcalls fromthe kernel module. */
static uint32_t
coda_access(void);
static uint32_t
coda_close(void);
static uint32_t
coda_create(void);
static uint32_t
coda_getattr(void);
static uint32_t
coda_lookup(void);
static uint32_t
coda_mkdir(void);
static uint32_t
coda_open_by_fd(void);
static uint32_t
coda_root(void);
static uint32_t
coda_setattr(void);
static uint32_t
coda_statfs(void);
/* Functions that will do a downcall to the kernel module. */
static void
coda_flush(int device);
/* Auxiliary functions. */
static off_t
write_dir_entry(int fd, off_t off, const dav_node *node, const char *name);
static void
set_attr(struct coda_vattr *attr, const dav_node *node);
/* Public functions */
/*==================*/
void
dav_coda_loop(int device, size_t bufsize, time_t idle_time,
dav_is_mounted_fn is_mounted, volatile int *keep_on_running,
int dbg)
{
debug = dbg;
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "coda kernel version 3");
buf = malloc(BUF_SIZE);
if (!buf) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
_("can't allocate message buffer"));
return;
}
static int flush = 0;
alignment = dav_register_kernel_interface(&write_dir_entry, &flush,
&blocksize);
struct timeval tv;
tv.tv_sec = idle_time;
tv.tv_usec = 0;
time_t last_tidy_cache = time(NULL);
while (*keep_on_running) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(device, &fds);
int ret = select(device + 1, &fds, NULL, NULL, &tv);
if (ret > 0) {
ssize_t bytes_read = read(device, buf, BUF_SIZE);
if (bytes_read <= 0) {
if (bytes_read == 0 || errno == EINTR || errno == EAGAIN) {
if (time(NULL) < (last_tidy_cache + idle_time)) {
tv.tv_sec = last_tidy_cache + idle_time - time(NULL);
} else {
tv.tv_sec = 0;
}
continue;
}
break;
}
} else if (ret == 0) {
if (!is_mounted())
break;
if (dav_tidy_cache() == 0) {
tv.tv_sec = idle_time;
last_tidy_cache = time(NULL);
} else {
tv.tv_sec = 0;
}
continue;
} else {
break;
}
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
uint32_t len;
switch (ih->opcode) {
case CODA_ROOT:
len = coda_root();
break;
case CODA_OPEN_BY_FD:
len = coda_open_by_fd();
break;
case CODA_OPEN:
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_OPEN:");
oh->result = ENOTSUP;
len = sizeof(struct coda_out_hdr);
break;
case CODA_CLOSE:
len = coda_close();
last_tidy_cache = 0;
break;
case CODA_IOCTL:
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_IOCTL:");
oh->result = ENOTSUP;
len = sizeof(struct coda_out_hdr);
break;
case CODA_GETATTR:
len = coda_getattr();
break;
case CODA_SETATTR:
len = coda_setattr();
break;
case CODA_ACCESS:
len = coda_access();
break;
case CODA_LOOKUP:
len = coda_lookup();
break;
case CODA_CREATE:
len = coda_create();
break;
case CODA_REMOVE: {
struct coda_remove_in *in = (struct coda_remove_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_REMOVE:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " p %p, %s", node,
buf + in->name);
}
oh->result = dav_remove(node, buf + in->name, ih->uid);
len = sizeof(struct coda_out_hdr);
break; }
case CODA_LINK:
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_LINK:");
oh->result = ENOTSUP;
len = sizeof(struct coda_out_hdr);
break;
case CODA_RENAME: {
struct coda_rename_in *in = (struct coda_rename_in *) buf;
dav_node *src = *((dav_node **) &(in->sourceFid.opaque[2]));
dav_node *dst = *((dav_node **) &(in->destFid.opaque[2]));
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_RENAME:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " sp %p, %s", src,
buf + in->srcname);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " dp %p, %s", dst,
buf + in->destname);
}
oh->result = dav_rename(src, buf + in->srcname, dst,
buf + in->destname, ih->uid);
len = sizeof(struct coda_out_hdr);
break; }
case CODA_MKDIR:
len = coda_mkdir();
break;
case CODA_RMDIR: {
struct coda_rmdir_in *in = (struct coda_rmdir_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_RMDIR:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " p %p, %s", node,
buf + in->name);
}
oh->result = dav_rmdir(node, buf + in->name, ih->uid);
len = sizeof(struct coda_out_hdr);
break; }
case CODA_SYMLINK:
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_SYMLINK:");
oh->result = ENOTSUP;
len = sizeof(struct coda_out_hdr);
break;
case CODA_READLINK:
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_READLINK:");
oh->result = ENOTSUP;
len = sizeof(struct coda_out_hdr);
break;
case CODA_FSYNC: {
struct coda_fsync_in *in = (struct coda_fsync_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_FSYNC:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " n %p", node);
}
oh->result = dav_sync(node);
len = sizeof(struct coda_out_hdr);
break; }
case CODA_VGET:
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_VGET:");
oh->result = ENOTSUP;
len = sizeof(struct coda_out_hdr);
break;
case CODA_OPEN_BY_PATH:
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
"CODA_OPEN_BY_PATH:");
oh->result = ENOTSUP;
len = sizeof(struct coda_out_hdr);
break;
case CODA_STATFS:
len = coda_statfs();
break;
case CODA_STORE: {
struct coda_store_in *in = (struct coda_store_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_STORE:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " n %p, f 0x%x",
node, in->flags);
}
oh->result = dav_sync(node);
len = sizeof(struct coda_out_hdr);
break; }
case CODA_RELEASE:
len = coda_close();
last_tidy_cache = 0;
break;
default:
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
"UNKNOWN CODA CALL %u", ih->opcode);
oh->result = ENOTSUP;
len = sizeof(struct coda_out_hdr);
break;
}
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "RET: %s",
strerror(oh->result));
ssize_t n = 0;
ssize_t w = 0;
while (n < len && w >= 0) {
w = write(device, buf + n, len - n);
n += w;
}
if (time(NULL) < (last_tidy_cache + idle_time)) {
tv.tv_sec = last_tidy_cache + idle_time - time(NULL);
} else {
dav_tidy_cache();
tv.tv_sec = idle_time;
last_tidy_cache = time(NULL);
}
if (flush) {
coda_flush(device);
flush = 0;
}
}
}
/* Private functions */
/*===================*/
/* Functions to handle upcalls fromthe kernel module.
The cache module only uses data types from the C-library. For file access,
mode and the like it only uses symbolic constants defined in the C-library.
So the main porpose of this functions is to translate from kernel specific
types and constants to types and constants from the C-library, and back.
All of this functions return the amount of data in buf that is to be
send to the kernel module. */
static uint32_t
coda_access(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_access_in *in = (struct coda_access_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_ACCESS:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " n %p, f %x",
node, in->flags);
}
int how = (in->flags & C_A_R_OK) ? R_OK : 0;
how |= (in->flags & C_A_W_OK) ? W_OK : 0;
how |= (in->flags & C_A_X_OK) ? X_OK : 0;
how |= (in->flags & C_A_F_OK) ? F_OK : 0;
oh->result = dav_access(node, ih->uid, how);
return sizeof(struct coda_out_hdr);
}
static uint32_t
coda_close(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_close_in *in = (struct coda_close_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
if (debug) {
if (ih->opcode == CODA_CLOSE) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_CLOSE:");
} else {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_RELEASE:");
}
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " n %p, f %x",
node, in->flags);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " pid %i, pgid %i",
ih->pid, ih->pgid);
}
int flags = 0;
if ((in->flags & C_O_READ) && (in->flags & C_O_WRITE)) {
flags = O_RDWR;
} else if (in->flags & C_O_READ) {
flags = O_RDONLY;
} else if (in->flags & C_O_WRITE) {
flags = O_WRONLY;
}
oh->result = dav_close(node, 0, flags, ih->pid, ih->pgid);
return sizeof(struct coda_out_hdr);
}
static uint32_t
coda_create(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_create_in *in = (struct coda_create_in *) buf;
dav_node *parent = *((dav_node **) &(in->VFid.opaque[2]));
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
struct coda_create_out *out = (struct coda_create_out *) buf;
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_CREATE:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " p %p, m %o",
parent, in->mode);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " %s", buf + in->name);
}
dav_node *node = NULL;
oh->result = dav_create(&node, parent, buf + in->name, ih->uid,
in->mode & DAV_A_MASK);
if (oh->result || !node) {
if (!oh->result)
oh->result = EIO;
return sizeof(struct coda_out_hdr);
}
out->VFid.opaque[0] = DAV_VOL;
out->VFid.opaque[1] = DAV_VNODE;
out->VFid.opaque[3] = 0;
*((dav_node **) &(out->VFid.opaque[2])) = node;
set_attr(&out->attr, node);
return sizeof(struct coda_create_out);
}
static uint32_t
coda_getattr(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_getattr_in *in = (struct coda_getattr_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
struct coda_getattr_out *out = (struct coda_getattr_out *) buf;
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_GETATTR:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " n %p", node);
}
oh->result = dav_getattr(node, ih->uid);
if (oh->result)
return sizeof(struct coda_out_hdr);
set_attr(&out->attr, node);
return sizeof(struct coda_getattr_out);
}
static uint32_t
coda_lookup(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_lookup_in *in = (struct coda_lookup_in *) buf;
dav_node *parent = *((dav_node **) &(in->VFid.opaque[2]));
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
struct coda_lookup_out *out = (struct coda_lookup_out *) buf;
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_LOOKUP:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " p %p, %s", parent,
buf + in->name);
}
dav_node *node = NULL;
oh->result = dav_lookup(&node, parent, buf + in->name, ih->uid);
if (oh->result || !node) {
if (!oh->result)
oh->result = EIO;
return sizeof(struct coda_out_hdr);
}
out->VFid.opaque[0] = DAV_VOL;
out->VFid.opaque[1] = DAV_VNODE;
out->VFid.opaque[3] = 0;
*((dav_node **) &(out->VFid.opaque[2])) = node;
out->vtype = (node->mode & S_IFDIR) ? CDT_DIR : CDT_REG;
return sizeof(struct coda_lookup_out);
}
static uint32_t
coda_mkdir(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_mkdir_in *in = (struct coda_mkdir_in *) buf;
dav_node *parent = *((dav_node **) &(in->VFid.opaque[2]));
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
struct coda_mkdir_out *out = (struct coda_mkdir_out *) buf;
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_MKDIR:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " p %p, %s", parent,
buf + in->name);
}
dav_node *node = NULL;
oh->result = dav_mkdir(&node, parent, buf + in->name, ih->uid,
in->attr.va_mode & DAV_A_MASK);
if (oh->result || !node) {
if (!oh->result)
oh->result = EIO;
return sizeof(struct coda_out_hdr);
}
out->VFid.opaque[0] = DAV_VOL;
out->VFid.opaque[1] = DAV_VNODE;
out->VFid.opaque[3] = 0;
*((dav_node **) &(out->VFid.opaque[2])) = node;
set_attr(&out->attr, node);
return sizeof(struct coda_mkdir_out);
}
static uint32_t
coda_open_by_fd(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_open_by_fd_in *in = (struct coda_open_by_fd_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
struct coda_open_by_fd_out *out = (struct coda_open_by_fd_out *) buf;
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_OPEN_BY_FD:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " n %p, f %x", node,
in->flags);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " pid %i, pgid %i",
ih->pid, ih->pgid);
}
int flags = 0;
if ((in->flags & C_O_READ) && (in->flags & C_O_WRITE)) {
flags = O_RDWR;
} else if (in->flags & C_O_READ) {
flags = O_RDONLY;
} else if (in->flags & C_O_WRITE) {
flags = O_WRONLY;
}
flags |= (in->flags & C_O_TRUNC) ? O_TRUNC : 0;
oh->result = dav_open(&out->fd, node, flags, ih->pid, ih->pgid, ih->uid);
if (oh->result || !out->fd) {
if (!oh->result)
oh->result = EIO;
return sizeof(struct coda_out_hdr);
}
return sizeof(struct coda_open_by_fd_out);
}
static uint32_t
coda_root(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
struct coda_root_out *out = (struct coda_root_out *) buf;
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_ROOT:");
dav_node *node = NULL;
oh->result = dav_root(&node, ih->uid);
if (oh->result || !node) {
if (!oh->result)
oh->result = EIO;
return sizeof(struct coda_out_hdr);
}
out->VFid.opaque[0] = DAV_VOL;
out->VFid.opaque[1] = DAV_VNODE;
out->VFid.opaque[3] = 0;
*((dav_node **) &(out->VFid.opaque[2])) = node;
return sizeof(struct coda_root_out);
}
static uint32_t
coda_setattr(void)
{
struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
struct coda_setattr_in *in = (struct coda_setattr_in *) buf;
dav_node *node = *((dav_node **) &(in->VFid.opaque[2]));
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_SETATTR:");
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " n %p, m %o", node,
in->attr.va_mode);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " uid: %i, gid: %i",
in->attr.va_uid, in->attr.va_gid);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " at %li, mt %li",
in->attr.va_atime.tv_sec, in->attr.va_mtime.tv_sec);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " ct %li, sz %llu",
in->attr.va_ctime.tv_sec, in->attr.va_size);
}
oh->result = dav_setattr(node, ih->uid, in->attr.va_mode != USHRT_MAX,
in->attr.va_mode & DAV_A_MASK,
in->attr.va_uid != UINT32_MAX, in->attr.va_uid,
in->attr.va_gid != UINT32_MAX, in->attr.va_gid,
in->attr.va_atime.tv_sec != -1,
in->attr.va_atime.tv_sec,
in->attr.va_mtime.tv_sec != -1,
in->attr.va_mtime.tv_sec,
in->attr.va_size != UINT64_MAX,
in->attr.va_size);
return sizeof(struct coda_out_hdr);
}
static uint32_t
coda_statfs(void)
{
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
struct coda_statfs_out *out = (struct coda_statfs_out *) buf;
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_STATFS:");
dav_stat st = dav_statfs();
out->stat.f_blocks = st.blocks;
out->stat.f_bfree = st.bfree;
out->stat.f_bavail = st.bavail;
out->stat.f_files = st.files;
out->stat.f_ffree = st.ffree;
oh->result = 0;
return sizeof(struct coda_statfs_out);
}
/* Functions that will do a downcall to the kernel module. */
/* Downcall to inform the kernel that nodes have been added or removed. */
static void
coda_flush(int device)
{
struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " CODA_FLUSH:");
oh->opcode = CODA_FLUSH;
oh->unique = 0;
oh->result = 0;
ssize_t n = 0;
ssize_t w = 0;
while (n < sizeof(struct coda_out_hdr) && w >= 0) {
w = write(device, buf + n, sizeof(struct coda_out_hdr) - n);
n += w;
}
}
/* Auxiliary functions. */
/* Writes a struct venus_dirent to file with file descriptor fd.
fd : An open file descriptor to write to.
off : The current file size.
name : File name; if NULL, the last, empty entry is written.
return value : New size of the file. -1 in case of an error. */
static off_t
write_dir_entry(int fd, off_t off, const dav_node *node, const char *name)
{
struct venus_dirent entry;
size_t head = offsetof(struct venus_dirent, d_name);
if (name) {
entry.d_fileno = (size_t) node / alignment;
entry.d_type = (S_ISDIR(node->mode)) ? CDT_DIR : CDT_REG;
entry.d_namlen = (strlen(name) > CODA_MAXNAMLEN)
? CODA_MAXNAMLEN : strlen(name);
entry.d_reclen = (head + entry.d_namlen +4) & ~3;
} else {
entry.d_fileno = 0;
entry.d_type = 0;
entry.d_namlen = 0;
entry.d_reclen = (head + 4) & ~3;
}
size_t size = 0;
ssize_t ret = 0;
while (ret >= 0 && size < head) {
ret = write(fd, (char *) &entry + size, head - size);
size += ret;
}
if (size != head)
return -1;
ret = 0;
while (ret >= 0 && size < (head + entry.d_namlen)) {
ret = write(fd, name + size - head, entry.d_namlen - size + head);
size += ret;
}
if (size != (head + entry.d_namlen))
return -1;
ret = 0;
while (ret >= 0 && size < entry.d_reclen) {
ret = write(fd, "\0", 1);
size += ret;
}
if (size != entry.d_reclen)
return -1;
return off + entry.d_reclen;
}
/* Translates attribute from node to attr.
Note: Members va_fileid, v_gen, va_flags, va_rdev and va_filerev have no
meaning for davfs. va_fileid is treated like d_fileno in struct venus_dirent,
the other are set to zero. The meaning of va_type is not clear at all.
Times are only set with 1 second precision, as this is the precision of the
last-modified time in HTTP. */
static void
set_attr(struct coda_vattr *attr, const dav_node *node)
{
attr->va_type = 0;
attr->va_mode = node->mode;
if (S_ISDIR(node->mode)) {
attr->va_nlink = node->nref;
} else {
attr->va_nlink = 1;
}
attr->va_uid = node->uid;
attr->va_gid = node->gid;
attr->va_fileid = (size_t) node / alignment;
attr->va_size = node->size;
attr->va_blocksize = blocksize;
attr->va_atime.tv_sec = node->atime;
attr->va_atime.tv_nsec = 0;
attr->va_mtime.tv_sec = node->mtime;
attr->va_mtime.tv_nsec = 0;
attr->va_ctime.tv_sec = node->ctime;
attr->va_ctime.tv_nsec = 0;
attr->va_gen = 0;
attr->va_flags = 0;
attr->va_rdev = 0;
attr->va_bytes = node->size;
attr->va_filerev = 0;
}

1112
src/dav_fuse.c Normal file

File diff suppressed because it is too large Load Diff

193
src/defaults.h Normal file
View File

@ -0,0 +1,193 @@
/* defauls.h: default values of configuration options and constants.
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_DEFAULTS_H
#define DAV_DEFAULTS_H
/* Misc. */
/*=======*/
#define DAV_HOME "http://dav.sourceforge.net"
/* File system type to be used with 'mount -t' and fstab. */
#define DAV_FS_TYPE "davfs"
/* Mount options set by mount program in case of mounting by an
ordinary user. */
#define DAV_USER_MOPTS (MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV)
/* This mount options will allways be set by davfs2. Different values from
command line and even fstab will be silently ignored. */
#define DAV_MOPTS (MS_MGC_VAL | MS_NOSUID | MS_NODEV)
/* XML namespace for the cache index file. */
#define DAV_XML_NS "http://dav.sf.net/"
/* Directories and Files */
/*=======================*/
/* The device directory. */
#define DAV_DEV_DIR "/dev"
/* The file davfs reads mtab entries from. If not available it will
use _PATH_MOUNTED. */
#define DAV_MOUNTS "/proc/mounts"
/* The directory where the cache files will be stored, when mounted by
a non root users; relative to DAV_USER_DIR.
May be overridden by user config file. */
#define DAV_CACHE "cache"
/* The name of index files. */
#define DAV_INDEX "index"
/* Name of the directory within the davfs2 filesystem that holds local
backup files.
May be overridden by system config file and user config file. */
#define DAV_BACKUP_DIR "lost+found"
/* Buffer size for reading the XML index files of persistent cache. */
#define DAV_XML_BUF_SIZE 16 * 1024
/* Cache Optimization */
/*====================*/
/* Cache size in MiByte.
May be overridden by system config file and user config file.
(1 MiByte = 1,048,576 Byte; Mi = Mebi = Mega Binary according to IEC) */
#define DAV_CACHE_SIZE 50
/* Size of the hash table to store nodes. Should be a power of 2.
May be overridden by system config file and user config file. */
#define DAV_TABLE_SIZE 1024
/* How long in seconds a cached directory is valid. After this time
a new PROPFIND request for this directory must be performed.
May be overridden by system config file and user config file. */
#define DAV_DIR_REFRESH 60
/* Wait at least that many seconds from last file access until a new
GET If-Modified request is send to the server. If set to 0 a request
will be send every time the file is opened. But some applications do
open and close calls in short sequence that cause - mostly - unnecessary
traffic.
May be overridden by system config file and user config file. */
#define DAV_FILE_REFRESH 1
/* How long to delay uploading of locally changed files after closing.
May be overridden by system config file and user config file. */
#define DAV_DELAY_UPLOAD 10
/* Use PROPFIND to get the Last-Modified time of all files in a directory
instead of GET If-Modified_Since for single files.
May be overridden by system config file and user config file. */
#define DAV_GUI_OPTIMIZE 0
/* HTTP */
/*======*/
/* The default proxy port.
May be overridden by system config file, user config file or environment
variable. */
#define DAV_DEFAULT_PROXY_PORT 8080
/* Whether to use a proxy if one is specified.
May be overridden by command line or fstab. */
#define DAV_USE_PROXY 1
/* Whether to ask user for credentials if not given.
May be overridden by command line, fstab or system config file. */
#define DAV_ASKAUTH 1
/* Whether to use locks.
May be overridden by command line or fstab. */
#define DAV_LOCKS 1
/* Send expect 100-continue header in PUT requests.
May be overridden by system config file and user config file. */
#define DAV_EXPECT100 0
/* If If-Match and If-None-Match does not work on the server, set to 1.
Default is 1, as Apache has this bug.
May be overridden by system config file and user config file. */
#define DAV_IF_MATCH_BUG 0
/* Some servers sends a weak invalid etag that turns into a valid strong etag
after one second. With this flag set, the etag will not be used,
otherwise the weakness indicator will be removed and the etag be trated
as if it was strong.
May be overridden by system config file and user config file. */
#define DAV_DROP_WEAK_ETAGS 0
/* Wether to allow a cookie to be set and included in requests.
May be overridden by system config file and user config file. */
#define DAV_ALLOW_COOKIE 0
/* Check on server whether a file exists or has been modified before
locking a new file or changing an existant one.
May be overridden by system config file and user config file. */
#define DAV_PRECHECK 1
/* Ignore the information in the DAV-header, if any, because it
may be a lie.
May be overridden by system config file and user config file. */
#define DAV_IGNORE_DAV_HEADER 0
/* Timeout in seconds used when libneon supports non blocking io
A value of zero means use the TCP default
May be overriden by system config file and user config file. */
#define DAV_CONNECT_TIMEOUT 10
/* Timeout in seconds used when reading from a socket.
May be overridden by system config file and user config file. */
#define DAV_READ_TIMEOUT 30
/* Default retry time after a PROPFIND request failed. When the request fails
again, the retry time will subsequently be increased up to DAV_MAX_RETRY.
May be overridden by system config file and user config file. */
#define DAV_RETRY 30
/* Maximum retry time after a PROPFIND request failed.
May be overridden by system config file and user config file. */
#define DAV_MAX_RETRY 300
/* Preferred live time of locks in seconds, before they have to be refreshed.
May be overridden by system config file and user config file. */
#define DAV_LOCK_TIMEOUT 1800
/* How many seconds before a lock expires it should be refreshed.
May be overridden by system config file and user config file. */
#define DAV_LOCK_REFRESH 60
/* Debug Constants */
/*=================*/
#define DAV_DBG_CONFIG 0x1
#define DAV_DBG_KERNEL 0x2
#define DAV_DBG_CACHE 0x4
#define DAV_DBG_SECRETS 0x8
#endif /* DAV_DEFAULTS_H */

314
src/fuse_kernel.h Normal file
View File

@ -0,0 +1,314 @@
/* This file is taken from FUSE 2.5.3.
From the two alternative licences the BSD licence has been chosen.
#include and #ifdef directives have been removed.
Modifications by Werner Baumann, 2009-04-14. */
/* This file defines the kernel interface of FUSE */
/*
Copyright (C) 2001-2006 Miklos Szeredi. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
#define __u64 uint64_t
#define __u32 uint32_t
#define __s32 int32_t
/** Version number of this interface */
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 5
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
/** The major number of the fuse character device */
#define FUSE_MAJOR 10
/** The minor number of the fuse character device */
#define FUSE_MINOR 229
/* Make sure all structures are padded to 64bit boundary, so 32bit
userspace works under 64bit kernels */
struct fuse_attr {
__u64 ino;
__u64 size;
__u64 blocks;
__u64 atime;
__u64 mtime;
__u64 ctime;
__u32 atimensec;
__u32 mtimensec;
__u32 ctimensec;
__u32 mode;
__u32 nlink;
__u32 uid;
__u32 gid;
__u32 rdev;
};
struct fuse_kstatfs {
__u64 blocks;
__u64 bfree;
__u64 bavail;
__u64 files;
__u64 ffree;
__u32 bsize;
__u32 namelen;
__u32 frsize;
__u32 padding;
__u32 spare[6];
};
#define FATTR_MODE (1 << 0)
#define FATTR_UID (1 << 1)
#define FATTR_GID (1 << 2)
#define FATTR_SIZE (1 << 3)
#define FATTR_ATIME (1 << 4)
#define FATTR_MTIME (1 << 5)
#define FATTR_FH (1 << 6)
/**
* Flags returned by the OPEN request
*
* FOPEN_DIRECT_IO: bypass page cache for this open file
* FOPEN_KEEP_CACHE: don't invalidate the data cache on open
*/
#define FOPEN_DIRECT_IO (1 << 0)
#define FOPEN_KEEP_CACHE (1 << 1)
enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
FUSE_GETATTR = 3,
FUSE_SETATTR = 4,
FUSE_READLINK = 5,
FUSE_SYMLINK = 6,
FUSE_MKNOD = 8,
FUSE_MKDIR = 9,
FUSE_UNLINK = 10,
FUSE_RMDIR = 11,
FUSE_RENAME = 12,
FUSE_LINK = 13,
FUSE_OPEN = 14,
FUSE_READ = 15,
FUSE_WRITE = 16,
FUSE_STATFS = 17,
FUSE_RELEASE = 18,
FUSE_FSYNC = 20,
FUSE_SETXATTR = 21,
FUSE_GETXATTR = 22,
FUSE_LISTXATTR = 23,
FUSE_REMOVEXATTR = 24,
FUSE_FLUSH = 25,
FUSE_INIT = 26,
FUSE_OPENDIR = 27,
FUSE_READDIR = 28,
FUSE_RELEASEDIR = 29,
FUSE_FSYNCDIR = 30,
FUSE_ACCESS = 34,
FUSE_CREATE = 35
};
/* The read buffer is required to be at least 8k, but may be much larger */
/* 2009-04-14, increased size of FUSE_MIN_READ_BUFFER, Werner Baumann */
#define FUSE_MIN_READ_BUFFER 16384
struct fuse_entry_out {
__u64 nodeid; /* Inode ID */
__u64 generation; /* Inode generation: nodeid:gen must
be unique for the fs's lifetime */
__u64 entry_valid; /* Cache timeout for the name */
__u64 attr_valid; /* Cache timeout for the attributes */
__u32 entry_valid_nsec;
__u32 attr_valid_nsec;
struct fuse_attr attr;
};
struct fuse_forget_in {
__u64 nlookup;
};
struct fuse_attr_out {
__u64 attr_valid; /* Cache timeout for the attributes */
__u32 attr_valid_nsec;
__u32 dummy;
struct fuse_attr attr;
};
struct fuse_mknod_in {
__u32 mode;
__u32 rdev;
};
struct fuse_mkdir_in {
__u32 mode;
__u32 padding;
};
struct fuse_rename_in {
__u64 newdir;
};
struct fuse_link_in {
__u64 oldnodeid;
};
struct fuse_setattr_in {
__u32 valid;
__u32 padding;
__u64 fh;
__u64 size;
__u64 unused1;
__u64 atime;
__u64 mtime;
__u64 unused2;
__u32 atimensec;
__u32 mtimensec;
__u32 unused3;
__u32 mode;
__u32 unused4;
__u32 uid;
__u32 gid;
__u32 unused5;
};
struct fuse_open_in {
__u32 flags;
__u32 mode;
};
struct fuse_open_out {
__u64 fh;
__u32 open_flags;
__u32 padding;
};
struct fuse_release_in {
__u64 fh;
__u32 flags;
__u32 padding;
};
struct fuse_flush_in {
__u64 fh;
__u32 flush_flags;
__u32 padding;
};
struct fuse_read_in {
__u64 fh;
__u64 offset;
__u32 size;
__u32 padding;
};
struct fuse_write_in {
__u64 fh;
__u64 offset;
__u32 size;
__u32 write_flags;
};
struct fuse_write_out {
__u32 size;
__u32 padding;
};
#define FUSE_COMPAT_STATFS_SIZE 48
struct fuse_statfs_out {
struct fuse_kstatfs st;
};
struct fuse_fsync_in {
__u64 fh;
__u32 fsync_flags;
__u32 padding;
};
struct fuse_setxattr_in {
__u32 size;
__u32 flags;
};
struct fuse_getxattr_in {
__u32 size;
__u32 padding;
};
struct fuse_getxattr_out {
__u32 size;
__u32 padding;
};
struct fuse_access_in {
__u32 mask;
__u32 padding;
};
struct fuse_init_in {
__u32 major;
__u32 minor;
};
struct fuse_init_out {
__u32 major;
__u32 minor;
__u32 unused[3];
__u32 max_write;
};
struct fuse_in_header {
__u32 len;
__u32 opcode;
__u64 unique;
__u64 nodeid;
__u32 uid;
__u32 gid;
__u32 pid;
__u32 padding;
};
struct fuse_out_header {
__u32 len;
__s32 error;
__u64 unique;
};
struct fuse_dirent {
__u64 ino;
__u64 off;
__u32 namelen;
__u32 type;
char name[0];
};
#define FUSE_NAME_OFFSET ((unsigned) ((struct fuse_dirent *) 0)->name)
#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
#define FUSE_DIRENT_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)

265
src/kernel_interface.c Normal file
View File

@ -0,0 +1,265 @@
/* kernel_interface.c: interface to fuse and coda kernel mocule.
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. */
#include "config.h"
#include <error.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_LIBINTL_H
#include <libintl.h>
#endif
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <string.h>
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#include "defaults.h"
#include "mount_davfs.h"
#include "cache.h"
#include "coda.h"
#include "fuse_kernel.h"
#include "kernel_interface.h"
#ifdef ENABLE_NLS
#define _(String) gettext(String)
#else
#define _(String) String
#endif
/* Private constants */
/*===================*/
/* Name, major number and minor number of the devices to communicate with the
kernel file system. */
#define FUSE_DEV_NAME "fuse"
#define CODA_DEV_NAME "cfs"
#define CODA_MAJOR 67
#define MAX_CODADEVS 5 /* Coda minor number may be from 0 to 4. */
/* Private function prototypes */
/*=============================*/
static int
init_coda(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata);
static int
init_fuse(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata,
size_t *buf_size, const char *url, const char *mpoint,
unsigned long int mopts, uid_t owner, gid_t group, mode_t mode);
/* Public functions */
/*==================*/
int
dav_init_kernel_interface(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata,
char **kernel_fs, size_t *buf_size, const char *url,
const char *mpoint, const dav_args *args)
{
uid_t orig = geteuid();
seteuid(0);
if (!*kernel_fs)
*kernel_fs = strdup("fuse");
if (!*kernel_fs) abort();
int mounted = 0;
if (strcmp(*kernel_fs, "coda") == 0) {
if (init_coda(dev, msg_loop, mdata) != 0) {
error(0, 0, _("trying fuse kernel file system"));
if (init_fuse(dev, msg_loop, mdata, buf_size, url, mpoint,
args->mopts, args->uid, args->gid, args->dir_mode)
== 0) {
free(*kernel_fs);
*kernel_fs = strdup("fuse");
if (!*kernel_fs) abort();
mounted = 1;
error(0, 0, _("fuse device opened successfully"));
} else {
exit(EXIT_FAILURE);
}
}
} else if (strcmp(*kernel_fs, "fuse") == 0) {
if (init_fuse(dev, msg_loop, mdata, buf_size, url, mpoint, args->mopts,
args->uid, args->gid, args->dir_mode) == 0) {
mounted = 1;
} else {
error(0, 0, _("trying coda kernel file system"));
if (init_coda(dev, msg_loop, mdata) == 0) {
free(*kernel_fs);
*kernel_fs = strdup("coda");
if (*kernel_fs == NULL)
abort();
error(0, 0, _("coda device opened successfully"));
} else {
exit(EXIT_FAILURE);
}
}
} else {
error(EXIT_FAILURE, 0, _("unknown kernel file system %s"), *kernel_fs);
}
seteuid(orig);
return mounted;
}
/* Private functions */
/*===================*/
static int
init_coda(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata)
{
*dev = 0;
int minor = 0;
while (*dev <= 0 && minor < MAX_CODADEVS) {
char *path;
if (asprintf(&path, "%s/%s%i", DAV_DEV_DIR, CODA_DEV_NAME, minor) < 0)
abort();
*dev = open(path, O_RDWR | O_NONBLOCK);
free(path);
++minor;
}
if (*dev <= 0) {
system("/sbin/modprobe coda &>/dev/null");
minor = 0;
while (*dev <= 0 && minor < MAX_CODADEVS) {
char *path;
if (asprintf(&path, "%s/%s%i",
DAV_DEV_DIR, CODA_DEV_NAME, minor) < 0)
abort();
*dev = open(path, O_RDWR | O_NONBLOCK);
if (*dev <= 0) {
if (mknod(path, S_IFCHR, makedev(CODA_MAJOR, minor)) == 0) {
chown(path, 0, 0);
chmod(path, S_IRUSR | S_IWUSR);
*dev = open(path, O_RDWR | O_NONBLOCK);
}
}
free(path);
++minor;
}
}
if (*dev <= 0) {
error(0, 0, _("no free coda device to mount"));
return -1;
}
int version = 0;
ioctl(*dev, CIOC_KERNEL_VERSION, &version);
if (version == 3) {
*msg_loop = dav_coda_loop;
} else {
error(0, 0, _("CODA_KERNEL_VERSION %u not supported"), version);
close(*dev);
return -1;
}
struct coda_mount_data *md = malloc(sizeof(struct coda_mount_data));
if (!md) abort();
md->version = CODA_MOUNT_VERSION;
md->fd = *dev;
*mdata = md;
return 0;
}
static int
init_fuse(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata,
size_t *buf_size, const char *url, const char *mpoint,
unsigned long int mopts, uid_t owner, gid_t group, mode_t mode)
{
char *path;
if (asprintf(&path, "%s/%s", DAV_DEV_DIR, FUSE_DEV_NAME) < 0)
abort();
*dev = open(path, O_RDWR | O_NONBLOCK);
if (*dev <= 0) {
system("/sbin/modprobe fuse &>/dev/null");
*dev = open(path, O_RDWR | O_NONBLOCK);
}
if (*dev <= 0) {
if (mknod(path, S_IFCHR, makedev(FUSE_MAJOR, FUSE_MINOR)) == 0) {
chown(path, 0, 0);
chmod(path, S_IRUSR | S_IWUSR);
*dev = open(path, O_RDWR | O_NONBLOCK);
}
}
free(path);
if (*dev <= 0) {
error(0, 0, _("can't open fuse device"));
return -1;
}
if (*buf_size < (FUSE_MIN_READ_BUFFER + 4096)) {
*buf_size = FUSE_MIN_READ_BUFFER + 4096;
}
#if SIZEOF_VOID_P == 8
if (asprintf((char **) mdata, "fd=%i,rootmode=%o,user_id=%i,group_id=%i,"
"allow_other,max_read=%lu", *dev, mode, owner, group,
*buf_size - 4096) < 0)
abort();
#else
if (asprintf((char **) mdata, "fd=%i,rootmode=%o,user_id=%i,group_id=%i,"
"allow_other,max_read=%u", *dev, mode, owner, group,
*buf_size - 4096) < 0)
abort();
#endif
if (mount(url, mpoint, "fuse", mopts, *mdata) == 0) {
*msg_loop = dav_fuse_loop;
return 0;
}
free(*mdata);
close(*dev);
error(0, 0, _("can't mount using fuse kernel file system"));
return -1;
}

96
src/kernel_interface.h Normal file
View File

@ -0,0 +1,96 @@
/* kernel_interface.h: interface to fuse and coda kernel mocule.
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_KERNEL_INTERFACE_H
#define DAV_KERNEL_INTERFACE_H
/* Function type definitions */
/*===========================*/
/* Call back function to be passed to dav_init_kernel_interface(). Will be
called to see whether the file system is still mounted.
return value : 1 is mounted, 0 is not mounted. */
typedef int (*dav_is_mounted_fn)(void);
/* Typedef of the message loop of the specific kernel interfaces. The real
function will be returned by dav_init_kernel_interface().
device : File descriptor of the open fuse device.
buf_size : Size of the buffer for communication with the kernel
module.
idle_t : Time to wait for upcalls before calling dav_tidy_cache().
is_mounted_fn : Call back function to check of still mounted.
keep_on_running : Pointer to run flag.
dbg : send debug messages to syslog if dbg != 0 */
typedef void (*dav_run_msgloop_fn)(int device, size_t bufsize, time_t idle_time,
dav_is_mounted_fn is_mounted,
volatile int *keep_on_running, int dbg);
/* Function prototypes */
/*=====================*/
/* Opens the device for communication with the kernel file system, if possible
mounts the file system and updates the interface data (dev,
dav_ran_msgloop_fn, mdata, kernel_fs and buf_size).
In case of an error it prints an error message and terminates the program.
dev : File descriptor of the open device for communication with the
kernel file system.
msg_loop : The specific message loop function that will process the kernel
upcalls.
mdata : That mount data that will be passed to the mount function.
kernel_fs : Type of the kernel file system to us (fuse or coda). If this
does not work, the other file system will be tried. The name
of the file system that is really used is returned.
If NULL, fuse is tried first.
buf_size : Size of the buffer for communication with the kernel file system
(fuse only). The size passed to this function is checked against
the requirements of the kernel fs and updated if necessary.
url : Server url.
mpoint : Mount point.
mopts : Mount options.
owner : The owner of the file system (fuse only).
group : Group the file system belongs to (fuse only).
mode : Mode of the root node (fuse only).
return value : 0: the file system has not yet been mounted
1: the file system has been mounted successfully. */
int
dav_init_kernel_interface(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata,
char **kernel_fs, size_t *buf_size, const char *url,
const char *mpoint, const dav_args *args);
/* Message loop for coda kernel module CODA_KERNEL_VERSION 3.
Parameters see dav_run_msgloop_fn(). */
void dav_coda_loop(int device, size_t bufsize, time_t idle_time,
dav_is_mounted_fn is_mounted,
volatile int *keep_on_running, int dbg);
/* Message loop for fuse kernel module with major number 7.
Parameters see dav_run_msgloop_fn(). */
void
dav_fuse_loop(int device, size_t bufsize, time_t idle_time,
dav_is_mounted_fn is_mounted, volatile int *keep_on_running,
int dbg);
#endif /* DAV_KERNEL_INTERFACE_H */

2538
src/mount_davfs.c Normal file

File diff suppressed because it is too large Load Diff

157
src/mount_davfs.h Normal file
View File

@ -0,0 +1,157 @@
/* mount_davfs.h: structure to collect arguments and options.
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_MOUNT_DAVFS_H
#define DAV_MOUNT_DAVFS_H
/* Data Types */
/*============*/
/* This data structure holds almost everything davfs gathers while reading and
checking command line and configuration files. (See comment for data origin;
highest precedence first.)
Some data will be copied into global or local variables to be available in
daemon mode. The rest will be freed when forking into daemon mode. */
typedef struct {
char *dav_user; /* System config file */
char *dav_group; /* System config file */
char *ignore_home; /* System config file */
char *conf; /* Command line */
/* Mount options */
int user; /* Command line */
int netdev; /* Command line */
unsigned long int mopts; /* Command line */
char *add_mopts;
char *kernel_fs; /* User config file, system config file */
size_t buf_size; /* User config file, system config file */
/* File mode */
uid_t uid; /* Command line */
gid_t gid; /* Command line */
mode_t dir_umask;
mode_t file_umask;
mode_t dir_mode; /* Command line */
mode_t file_mode; /* Command line */
/* WebDAV-resource */
char *scheme; /* Command line */
char *host; /* Command line */
int port; /* Command line */
char *path; /* Command line */
char *servercert; /* User config file, system config file */
char *secrets; /* User config file */
char *username; /* User secrets file, system secrets file */
char *password; /* User secrets file, system secrets file */
char *clicert; /* User config file, system config file */
char *clicert_pw; /* User secrets file, system secrets file */
char *p_host; /* User config file, sys conf f., environment */
int p_port; /* User config file, sys conf f., environment */
char *p_user; /* User secrets file, system secrets file */
char *p_passwd; /* User secrets file, system secrets file */
int useproxy; /* User config file, sys conf f., command line */
int askauth; /* User config file, sys conf f., command line */
int locks; /* User config file, sys conf f., command line */
char * lock_owner; /* User config file, system config file */
time_t lock_timeout; /* User config file, system config file */
time_t lock_refresh; /* User config file, system config file */
int expect100; /* User config file, system config file */
int if_match_bug; /* User config file, system config file */
int drop_weak_etags; /* User config file, system config file */
int allow_cookie; /* User config file, system config file */
int precheck; /* User config file, system config file */
int ignore_dav_header; /* User config file, system config file */
time_t connect_timeout; /* User config file, system config file */
time_t read_timeout; /* User config file, system config file */
time_t retry; /* User config file, system config file */
time_t max_retry; /* User config file, system config file */
char * s_charset; /* User config file, system config file */
char * header; /* User config file, system config file */
/* Cache */
char *sys_cache; /* System config file */
char *cache_dir; /* User config file */
char *backup_dir; /* User config file, system config file */
size_t cache_size; /* User config file, system config file */
size_t table_size; /* User config file, system config file */
time_t dir_refresh; /* User config file, system config file */
time_t file_refresh; /* User config file, system config file */
int delay_upload; /* User config file, system config file */
int gui_optimize; /* User config file, system config file */
/* Debugging */
int debug; /* User config file, system config file */
int neon_debug; /* User config file, system config file */
} dav_args;
/* Public functions. */
/*===================*/
/* Main launches a daemon program that runs a directory and file cache and
is connected to the WbDAV resource and the kernel file system module.
It must run setuid root. After forking into daemon mode it releases root
permissions permanently. The daemon runs with the uid of the user that owns
the file system. (If invoked by root and the mounted file system is owned
by root, the daemon runs as root. This should be avoided.)
Launching the daemon (and stopping) is done in 5 steps.
Step 1:
- Gathering information from command line, configuration files and
environment.
- Checking this information for consistency and any errors that would
prevent successful running of the daemon.
- Checking whether the the user has permissions to mount.
- Checking whether the neccessary files and directories for running the
daemon are available.
Step 2:
- The modules for connecting to the kernel, connecting to the WebDAV resource
and for caching are initialised.
If an error accurs during step 1 or step 2 an error message is printed and
the program dies immediately. Clean up is left to the operating system.
Step 3:
- Forking into daemon mode.
- While the daemon (child) writes the pid file and starts reading upcalls
from the kernel in an endless loop, the parent process tries to mount the
file system and write an entry into mtab (_PROC_MOUNTS).
- If an error occurs in one of the processes it sends SIGTERM to the other.
While the parent just dies, the daemon will run its normal exit code
(see step 5). In rare cases this might nevertheless leave stale pid files
or entries in mtab that must be cleaned manually by the administrator.
- If mounting is successful the parent process exits with success.
Step 4:
- Running as daemon.
Step 5:
- Terminating.
- The daemon has set a signal handler for SIGTERM and SIGHUP. If it gets one
of these signals it tries to unmount the file system and resets the global
variable keep_on_running. This will terminate the message loop gracefully.
- If the file system is unmounted (by the umount programm), the message
loop will terminate gracefully.
- The close functions of the modules are called, that will clean up the
cache, save cached information if neccessary and close the connections. */
int
main(int argc, char *argv[]);
/* Prints prompt to stdout and reads a line from stdin.
Echoing the user input to stdout is prohibited.
A trailing newline is removed.
return value : the user input. */
char *
dav_user_input_hidden(const char *prompt);
#endif /* DAV_MOUNT_DAVFS_H */

212
src/umount_davfs.c Normal file
View File

@ -0,0 +1,212 @@
/* umount_davfs.c: unmount the davfs file system.
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. */
#include "config.h"
#include <error.h>
#include <errno.h>
#include <getopt.h>
#ifdef HAVE_LIBINTL_H
#include <libintl.h>
#endif
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ne_string.h>
#include "defaults.h"
#ifdef ENABLE_NLS
#define _(String) gettext(String)
#else
#define _(String) String
#define textdomain(Domainname)
#define bindtextdomain(Domainname, Dirname)
#endif
/* This is lazy programming. All the dirty work is left to the real umount
program, while we just sit and wait for mount.davfs to terminate.
umount.davfs is a umount helper. It is usually called by umount and makes
sure, that umount will not return until mount.davfs has synchronized all
files.
It first reads the pid-file and identifies the mount.davfs process. Then
it calls mount again, with option -i (to not be called again), to do the
real unmounting. In a loop it will watch the process list. When the
mount.davfs process terminates, it will return.
If it can't identify the mount.davfs process, it will call umount -i anyway,
but warn the user. */
int
main(int argc, char *argv[])
{
setuid(getuid());
setgid(getgid());
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
char *short_options = "Vhflnrv";
static const struct option options[] = {
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'h'},
{0, 0, 0, 0}
};
int o;
o = getopt_long(argc, argv, short_options, options, NULL);
while (o != -1) {
switch (o) {
case 'V':
printf("%s <%s>\n\n", PACKAGE_STRING, DAV_HOME);
printf(_("This is free software; see the source for copying "
"conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS "
"FOR A PARTICULAR PURPOSE.\n"));
exit(EXIT_SUCCESS);
case 'h':
printf(_("Usage:\n"
" u%s -V,--version : print version string\n"
" u%s -h,--help : print this message\n\n"),
PROGRAM_NAME, PROGRAM_NAME);
printf(_("To umount a WebDAV-resource don't call u%s directly, "
"but use\n"
"`umount' instead.\n"), PROGRAM_NAME);
printf(_(" umount <mountpoint> : umount the WebDAV-resource as "
"specified in\n"
" /etc/fstab.\n"));
exit(EXIT_SUCCESS);
case 'f':
case 'l':
case 'n':
case 'r':
case 'v':
case '?':
break;
default:
error(EXIT_FAILURE, 0, _("unknown error parsing arguments"));
}
o = getopt_long(argc, argv, short_options, options, NULL);
}
if (optind > (argc - 1))
error(EXIT_FAILURE, 0, _("missing argument"));
if (optind < (argc - 1))
error(EXIT_FAILURE, 0, _("too many arguments"));
char *mpoint = canonicalize_file_name(argv[optind]);
if (!mpoint)
mpoint = argv[optind];
if (!mpoint || *mpoint != '/')
error(EXIT_FAILURE, 0, _("can't determine mount point"));
char *m = mpoint;
while (*m == '/')
m++;
char *mp = ne_strdup(m);
m = strchr(mp, '/');
while (m) {
*m = '-';
m = strchr(mp, '/');
}
char *pidfile = ne_concat(DAV_SYS_RUN, "/", mp, ".pid", NULL);
free(mp);
char *umount_command = ne_concat("umount -i ", mpoint, NULL);
char *pid = NULL;
FILE *file = fopen(pidfile, "r");
if (!file || fscanf(file, "%a[0-9]", &pid) != 1 || !pid) {
error(0, 0,
_("\n"
" can't read PID from file %s;\n"
" trying to unmount anyway;\n"
" please wait for %s to terminate"), pidfile, PROGRAM_NAME);
return system(umount_command);
}
fclose(file);
char *ps_command = ne_concat("ps -p ", pid, NULL);
FILE *ps_in = popen(ps_command, "r");
if (!ps_in) {
error(0, 0,
_("\n"
" can't read process list;\n"
" trying to unmount anyway;\n"
" please wait for %s to terminate"), PROGRAM_NAME);
return system(umount_command);
}
int found = 0;
size_t n = 0;
char *ps_line = NULL;
while (!found && getline(&ps_line, &n, ps_in) > 0)
found = (strstr(ps_line, pid) && strstr(ps_line, PROGRAM_NAME));
pclose(ps_in);
if (!found) {
error(0, 0,
_("\n"
" can't find %s-process with pid %s;\n"
" trying to unmount anyway.\n"
" you propably have to remove %s manually"),
PROGRAM_NAME, pid, pidfile);
return system(umount_command);
}
if (system(umount_command) != 0)
exit(EXIT_FAILURE);
printf(_("%s: waiting while %s (pid %s) synchronizes the cache ."),
argv[0], PROGRAM_NAME, pid);
fflush(stdout);
while (found) {
sleep(3);
printf(".");
fflush(stdout);
ps_in = popen(ps_command, "r");
if (!ps_in) {
printf("\n");
error(EXIT_FAILURE, 0, _("an error occured while waiting; "
"please wait for %s to terminate"), PROGRAM_NAME);
}
found = 0;
while (!found && getline(&ps_line, &n, ps_in) > 0)
found = (strstr(ps_line, pid) && strstr(ps_line, PROGRAM_NAME));
pclose(ps_in);
}
printf(" OK\n");
return 0;
}

1915
src/webdav.c Normal file

File diff suppressed because it is too large Load Diff

278
src/webdav.h Normal file
View File

@ -0,0 +1,278 @@
/* webdav.h: send requests to the WebDAV server.
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_WEBDAV_H
#define DAV_WEBDAV_H
/* Data Types */
/*============*/
/* This structure holds the properties retrieved from the server.
Usually a linked list of these is returned by dav_get_collection().
Unused pointers should be set to NULL, integer types to 0. */
typedef struct dav_props dav_props;
struct dav_props {
char *path; /* The unescaped path of the resource. */
char *name; /* The name of the file or directory. Only the last
component (no path), no slashes. */
char *etag; /* The etag string, including quotation characters,
but without the mark for weak etags. */
off_t size; /* File size in bytes (regular files only). */
time_t ctime; /* Creation date. */
time_t mtime; /* Date of last modification. */
int is_dir; /* Boolean; 1 if a directory. */
int is_exec; /* -1 if not specified; 1 is executeable;
0 not executeable. */
dav_props *next; /* Next in the list. */
};
/* Function prototypes */
/*=====================*/
/* Creates and initializes a neon_session, using configuration information
given as parameters, and checks the WebDAV class of the server.
If the server does not support class 2, locking is disabled.
It must only be initialized once, as it depends on global variables.
If an error occurs, the program is terminated.
paramters: if not self explaining, please see mount_davfs.h, struct args. */
void
dav_init_webdav(const dav_args* args);
/* Does an OPTIONS request to check the server capabilities. In case of
success it will set the global variable initialized. If the server
does not support locks, it will remove the lockstore and set locks
to NULL.
path : Path to the root collection.
return value : 0 on success or an apropriate error code. */
int
dav_init_connection(const char *path);
/* Releases all locks (if possible) and closes the session.
Does not free memory held by the session. */
void
dav_close_webdav(void);
/* Converts the character encoding of s from and to the local encoding.
Converter handles are taken from global variables from_utf_8, to_utf_8,
from_server_enc and to_server_enc.
If no conversion is necessary, it just returns a copy of s.
name : string to be converted.
return value : the converted string, newly allocated. */
char *
dav_conv_from_utf_8(const char *s);
char *
dav_conv_to_utf_8(const char *s);
char *
dav_conv_from_server_enc(const char *s);
char *
dav_conv_to_server_enc(const char *s);
/* Deletes file path on the server.
On success locks for this file are removed from the lock store.
path : Absolute path of the file.
expire : If not 0, the resource is assumed to be locked and the lock
will be removed after successful delete.
return value : 0 on success; an appropriate file error code otherwise. */
int
dav_delete(const char *path, time_t *expire);
/* Deletes collection path on the server.
path : Absolute path of the collection.
return value : 0 on success; an appropriate file error code otherwise. */
int dav_delete_dir(const char *path);
/* Frees any resources held by props and finally frees props. */
void
dav_delete_props(dav_props *props);
/* Retrieves properties for the directory named by path and its
direct childs (depth 1) from the server.
The properties are returned as a linked list of dav_props. If successfull,
this list contains at least one entry (the directory itself; its name is
the empty string). The calling function is responsible for freeing the list
and all the strings included.
path : The absolute path of the directory with trailing slash.
*props : Will point to the list of properties on return. NULL in case of
an error.
return value : 0 on success; an appropriate file error code otherwise. */
int
dav_get_collection(const char *path, dav_props **props);
/* Fetches file path from the server, stores it in cache_path and updates
size, etag and mtime.
If etag and/or mtime are supplied, a conditional GET will be performed.
If the file has not been modified on the server, size, etag, mtime and
mime will not be changed.
If the GET request fails none of size, etag and mtime are changed.
cache_path : Name of the cache file to store the file in.
path : Absolute path of the file on the server.
size : Points to the size of the cached file and will be updated if a
new version of the file is retrieved.
etag : Points to the ETag string of the cached version. If a new
version of the file is retrieved this will be replaced by the
new ETag value. May be NULL or point to NULL.
mtime : Points to the Last-Modified value of the cached version. Will
be updated if a new version of the file is retrieved.
May be NULL.
mime : Points to the mime_type string of the cached version. Will
be updated by the value of the Content-Type header, if any.
May be NULL;
modified : Points to a flag that will be set 1 if the file cache_path
has been replaced by a new version. May be NULL.
return value : 0 on success; an appropriate file error code otherwise.
Not-Modified counts as success. */
int
dav_get_file(const char *path, const char *cache_path, off_t *size,
char **etag, time_t *mtime, char **mime, int *modified);
/* Returns the error string from the last WebDAV request.
Note: This will not be usefull in any case, because the last function
called may have done more then one request (e.g. an additional
lock discover. But it is usefull for dav_get_collection(). */
const char *
dav_get_webdav_error(void);
/* Tests for the existence of file path and uptdates etag, mtime and length.
In case of an error etag and mtime are not changed. If the server does not
send ETag or Last-Modified the corresponding value will not be changed.
path : absolute path of the file on the server.
etag : Points to the Etag; will be updated on success. May be NULL.
mtime : Points to mtime; will be updated on success. May be NULL.
length: Points to length; will be updated on success. May be NULL.
mime : Points to mime_type; will be updated on success. May be NULL.
return value : 0 if the file exists; an appropriate file error code
otherwise. */
int
dav_head(const char *path, char **etag, time_t *mtime, off_t *length,
char **mime);
/* Locks the file path on the server with an excluse write lock and updates
expire and exists. If a lock for path allready exists it will be refreshed.
On success expire will be updated to the time when the lock expires.
If the file does not yet exist and server creates a new file (as opposed to
creating a locked-null-resource) exists will be set to 1.
If the file is already locked, but not by this instance of davfs2, it will
try if the lock is from the same user using davfs2, and if so, to use this
lock.
If it can't get a lock it will return an appropriate error code and set
expire to 0.
If the session is initialized with the nolocks option, it does nothing,
but allways returns success and sets expire to 0.
path : absolute path of the file on the server.
expire : Points to the time when the lock expires. 0 if not locked.
Will be updated.
exists : Indicates whether the file exists on the server. If the server
responds with "201 CREATED", it will be set to 1.
return value : 0 on success; an appropriate file error code
otherwise. */
int
dav_lock(const char *path, time_t *expire, int *exists);
/* Refreshes the lock for file path and updates expire.
If no lock can be found for path expire is set to 0.
If it can't refresh the lock it will do nothing.
path : Absolute path of the file on the server.
expire : The time when the lock expires, will be updated. */
void dav_lock_refresh(const char *path, time_t *expire);
/* Creates a new collection on the server.
path : Absolute path of the new collection on the server.
return value : 0 on success; an appropriate file error code otherwise. */
int
dav_make_collection(const char *path);
/* Moves resource src to the new name/location dst.
src : Absolute path of the resource on the server.
dst : New absolute path of the resource on the server.
return value : 0 on success; an appropriate file error code otherwise. */
int
dav_move(const char *src, const char *dst);
/* Stores the contents of file cache_path on the server location path and
updates the value of exists, etag and mtime.
Before uploading the file it tests whether the file on the server has been
changed (compared to the values of exists, etag and mtime). If it has been
changed the file will *not* be uploaded and an error returned instead.
Sometimes a lock may be discovered during dav_put(). In this case expire
will be updated.
path : Absolute path of the file on the server.
cache_path : Name of the local file to be stored on the server.
exists : Indicates whether the file exists on the server. Used to check
for changes on the server. If the upload is successful it will
be set to 1.
etag : The value of ETag used to check for changes on the server.
Updated on success. May be NULL.
mtime : The Last_Modified value used to check for changes on the
server. Updated on success. May be NULL.
mime : The value of mime_type. Updated on successMay be NULL.
If a mime_type is set, the Content-Type header will be sent.
execute : if 1 set execute property, else no change of execute property.
return value : 0 on success; an appropriate file error code otherwise. */
int
dav_put(const char *path, const char *cache_path, int *exists, time_t *expire,
char **etag, time_t *mtime, char **mime, int execute);
/* Makes a PROPFIND request for path to get quota information (RFC 4331)
and places them in available and used. If quota information is not
available, an error is returned and available and used are not changed. */
int
dav_quota(const char *path, off_t *available, off_t *used);
/* Sets or resets the execute property of file path.
path : Absolute path of the file on the server.
set : boolean value; 0 reset execute property; 1 set execute property. */
int
dav_set_execute(const char *path, int set);
/* Tells webdav that no more terminal is available, so errors can only
* be logged. Before this function is invoced webdav tries to
* communicate with the user when problems occur. */
void
dav_set_no_terminal(void);
/* Releases the lock on file path on the serverand sets expire to 0.
path : Absolute path of the file on the server.
return value : 0 if no error occured; an appropriate file error code
otherwise. */
int
dav_unlock(const char *path, time_t *expire);
#endif /* DAV_WEBDAV_H */