diff --git a/src/filecache.c b/src/filecache.c
index 985d575ac1cbfc8867104c146ad94bce3e3c00b0..3b1e90728a4ccd8fc7b6317198e4102bd6113a39 100644 (file)
--- a/src/filecache.c
+++ b/src/filecache.c
-/* $Id$ */
-
/***
- This file is part of fusedav.
-
- fusedav 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 2 of the License, or
- (at your option) any later version.
-
- fusedav 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 fusedav; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Copyright (c) 2004-2006 Lennart Poettering
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#define _XOPEN_SOURCE 500
-
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <assert.h>
#include <pthread.h>
+#include <inttypes.h>
+#include <limits.h>
#include <ne_props.h>
#include <ne_uri.h>
#include <ne_basic.h>
#include "filecache.h"
+#include "statcache.h"
#include "fusedav.h"
#include "session.h"
-#include "statcache.h"
struct file_info {
char *filename;
int fd;
off_t server_length, length, present;
-
+
int readable;
int writable;
static struct file_info *files = NULL;
static pthread_mutex_t files_mutex = PTHREAD_MUTEX_INITIALIZER;
-int file_cache_sync_unlocked(struct file_info *fi);
+static int file_cache_sync_unlocked(struct file_info *fi);
void* file_cache_get(const char *path) {
struct file_info *f, *r = NULL;
pthread_mutex_lock(&files_mutex);
-
+
for (f = files; f; f = f->next) {
-
+
pthread_mutex_lock(&f->mutex);
if (!f->dead && f->filename && !strcmp(path, f->filename)) {
f->ref++;
if (r)
break;
}
-
+
pthread_mutex_unlock(&files_mutex);
return f;
}
assert(fi);
pthread_mutex_lock(&files_mutex);
-
+
for (s = files, prev = NULL; s; s = s->next) {
if (s == fi) {
if (prev)
break;
}
-
+
prev = s;
}
-
+
pthread_mutex_unlock(&files_mutex);
}
}
void* file_cache_open(const char *path, int flags) {
- struct file_info *fi;
+ struct file_info *fi = NULL;
char tempfile[PATH_MAX];
- char *length = NULL;
+ const char *length = NULL;
ne_request *req = NULL;
ne_session *session;
+ if (!(session = session_get(1))) {
+ errno = EIO;
+ goto fail;
+ }
+
if ((fi = file_cache_get(path))) {
if (flags & O_RDONLY || flags & O_RDWR) fi->readable = 1;
if (flags & O_WRONLY || flags & O_RDWR) fi->writable = 1;
return fi;
}
- if (!(session = session_get())) {
- errno = -EIO;
- return NULL;
- }
-
fi = malloc(sizeof(struct file_info));
memset(fi, 0, sizeof(struct file_info));
fi->fd = -1;
req = ne_request_create(session, "HEAD", path);
assert(req);
- ne_add_response_header_handler(req, "Content-Length", ne_duplicate_header, &length);
-
if (ne_request_dispatch(req) != NE_OK) {
fprintf(stderr, "HEAD failed: %s\n", ne_get_error(session));
errno = ENOENT;
goto fail;
}
- if (!length) {
- fprintf(stderr, "HEAD did not return content length.\n");
- errno = EPROTO;
- goto fail;
- }
-
- fi->server_length = fi->length = atoi(length);
+ if (!(length = ne_get_response_header(req, "Content-Length")))
+ /* dirty hack, since Apache doesn't send the file size if the file is empty */
+ fi->server_length = fi->length = 0;
+ else
+ fi->server_length = fi->length = atoi(length);
ne_request_destroy(req);
- free(length);
-
+
if (flags & O_RDONLY || flags & O_RDWR) fi->readable = 1;
if (flags & O_WRONLY || flags & O_RDWR) fi->writable = 1;
pthread_mutex_init(&fi->mutex, NULL);
-
+
pthread_mutex_lock(&files_mutex);
fi->next = files;
files = fi;
pthread_mutex_unlock(&files_mutex);
fi->ref = 1;
-
+
return fi;
fail:
if (req)
ne_request_destroy(req);
- if (length)
- free(length);
-
if (fi) {
if (fi->fd >= 0)
close(fi->fd);
free(fi->filename);
free(fi);
}
-
+
return NULL;
}
static int load_up_to_unlocked(struct file_info *fi, off_t l) {
- ne_content_range range;
- assert(fi);
+
+ ne_content_range64 range;
ne_session *session;
- if (!(session = session_get())) {
+ assert(fi);
+
+ if (!(session = session_get(1))) {
errno = EIO;
return -1;
}
if (l > fi->server_length)
l = fi->server_length;
-
+
if (l <= fi->present)
return 0;
range.start = fi->present;
range.end = l-1;
-
- if (ne_get_range(session, fi->filename, &range, fi->fd)) {
+ range.total = 0;
+
+ if (ne_get_range64(session, fi->filename, &range, fi->fd) != NE_OK) {
fprintf(stderr, "GET failed: %s\n", ne_get_error(session));
errno = ENOENT;
return -1;
int file_cache_read(void *f, char *buf, size_t size, off_t offset) {
struct file_info *fi = f;
ssize_t r = -1;
-
+
assert(fi && buf && size);
pthread_mutex_lock(&fi->mutex);
goto finish;
finish:
-
+
pthread_mutex_unlock(&fi->mutex);
return r;
if (load_up_to_unlocked(fi, offset) < 0)
goto finish;
-
+
if ((r = pwrite(fi->fd, buf, size, offset)) < 0)
goto finish;
fi->modified = 1;
- r = 0;
-
finish:
pthread_mutex_unlock(&fi->mutex);
-
+
return r;
}
int file_cache_truncate(void *f, off_t s) {
struct file_info *fi = f;
- assert(fi);
int r;
+ assert(fi);
+
pthread_mutex_lock(&fi->mutex);
fi->length = s;
int file_cache_sync_unlocked(struct file_info *fi) {
int r = -1;
ne_session *session;
- assert(fi);
- if (!(session = session_get())) {
- errno = EIO;
- goto finish;
- }
+ assert(fi);
if (!fi->writable) {
errno = EBADF;
r = 0;
goto finish;
}
-
+
if (load_up_to_unlocked(fi, (off_t) -1) < 0)
goto finish;
if (lseek(fi->fd, 0, SEEK_SET) == (off_t)-1)
goto finish;
-
+ if (!(session = session_get(1))) {
+ errno = EIO;
+ goto finish;
+ }
+
if (ne_put(session, fi->filename, fi->fd)) {
fprintf(stderr, "PUT failed: %s\n", ne_get_error(session));
errno = ENOENT;
r = 0;
finish:
-
+
return r;
}
pthread_mutex_lock(&fi->mutex);
r = file_cache_sync_unlocked(fi);
pthread_mutex_unlock(&fi->mutex);
-
+
return r;
}
while (files) {
struct file_info *fi = files;
-
+
pthread_mutex_lock(&fi->mutex);
fi->ref++;
pthread_mutex_unlock(&fi->mutex);
return r;
}
+
+off_t file_cache_get_size(void *f) {
+ struct file_info *fi = f;
+
+ assert(fi);
+
+ return fi->length;
+}