Code

git: remove $Id$ svn cruft
[fusedav.git] / src / filecache.c
index 429385d63e25118b7aa1035bd98bd46ea65b251f..3b1e90728a4ccd8fc7b6317198e4102bd6113a39 100644 (file)
@@ -1,4 +1,30 @@
-#define _XOPEN_SOURCE 500
+/***
+  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
 
 #include <errno.h>
 #include <string.h>
@@ -8,6 +34,8 @@
 #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;
 
@@ -44,15 +72,15 @@ struct file_info {
 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++;
@@ -63,7 +91,7 @@ void* file_cache_get(const char *path) {
         if (r)
             break;
     }
-    
+
     pthread_mutex_unlock(&files_mutex);
     return f;
 }
@@ -102,7 +130,7 @@ static void file_cache_unlink(struct file_info *fi) {
     assert(fi);
 
     pthread_mutex_lock(&files_mutex);
-    
+
     for (s = files, prev = NULL; s; s = s->next) {
         if (s == fi) {
             if (prev)
@@ -112,10 +140,10 @@ static void file_cache_unlink(struct file_info *fi) {
 
             break;
         }
-        
+
         prev = s;
     }
-    
+
     pthread_mutex_unlock(&files_mutex);
 }
 
@@ -134,23 +162,23 @@ int file_cache_close(void *f) {
 }
 
 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;
-    ne_request *req;
+    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;
@@ -165,37 +193,32 @@ void* file_cache_open(const char *path, int flags) {
     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:
@@ -203,32 +226,31 @@ 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;
 
@@ -237,8 +259,9 @@ static int load_up_to_unlocked(struct file_info *fi, off_t l) {
 
     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;
@@ -251,7 +274,7 @@ static int load_up_to_unlocked(struct file_info *fi, off_t l) {
 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);
@@ -263,7 +286,7 @@ int file_cache_read(void *f, char *buf, size_t size, off_t offset) {
         goto finish;
 
 finish:
-    
+
     pthread_mutex_unlock(&fi->mutex);
 
     return r;
@@ -284,7 +307,7 @@ int file_cache_write(void *f, const char *buf, size_t size, off_t offset) {
 
     if (load_up_to_unlocked(fi, offset) < 0)
         goto finish;
-        
+
     if ((r = pwrite(fi->fd, buf, size, offset)) < 0)
         goto finish;
 
@@ -296,19 +319,18 @@ int file_cache_write(void *f, const char *buf, size_t size, off_t offset) {
 
     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;
@@ -322,12 +344,8 @@ int file_cache_truncate(void *f, off_t 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;
@@ -338,14 +356,18 @@ int file_cache_sync_unlocked(struct file_info *fi) {
         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;
@@ -358,7 +380,7 @@ int file_cache_sync_unlocked(struct file_info *fi) {
     r = 0;
 
 finish:
-    
+
     return r;
 }
 
@@ -370,7 +392,7 @@ int file_cache_sync(void *f) {
     pthread_mutex_lock(&fi->mutex);
     r = file_cache_sync_unlocked(fi);
     pthread_mutex_unlock(&fi->mutex);
-    
+
     return r;
 }
 
@@ -381,7 +403,7 @@ int file_cache_close_all(void) {
 
     while (files) {
         struct file_info *fi = files;
-        
+
         pthread_mutex_lock(&fi->mutex);
         fi->ref++;
         pthread_mutex_unlock(&fi->mutex);
@@ -396,3 +418,11 @@ int file_cache_close_all(void) {
 
     return r;
 }
+
+off_t file_cache_get_size(void *f) {
+    struct file_info *fi = f;
+
+    assert(fi);
+
+    return fi->length;
+}