1 #define _XOPEN_SOURCE 500
14 #include <ne_session.h>
16 #include <ne_socket.h>
21 #include "filecache.h"
24 #include "statcache.h"
29 off_t server_length
, length
, present
;
38 pthread_mutex_t mutex
;
40 /* This field is locked by files_mutex, not by file_info->mutex */
41 struct file_info
*next
;
44 static struct file_info
*files
= NULL
;
45 static pthread_mutex_t files_mutex
= PTHREAD_MUTEX_INITIALIZER
;
47 int file_cache_sync_unlocked(struct file_info
*fi
);
49 void* file_cache_get(const char *path
) {
50 struct file_info
*f
, *r
= NULL
;
52 pthread_mutex_lock(&files_mutex
);
54 for (f
= files
; f
; f
= f
->next
) {
56 pthread_mutex_lock(&f
->mutex
);
57 if (!f
->dead
&& f
->filename
&& !strcmp(path
, f
->filename
)) {
61 pthread_mutex_unlock(&f
->mutex
);
67 pthread_mutex_unlock(&files_mutex
);
71 static void file_cache_free_unlocked(struct file_info
*fi
) {
72 assert(fi
&& fi
->dead
&& fi
->ref
== 0);
79 pthread_mutex_destroy(&fi
->mutex
);
83 void file_cache_unref(void *f
) {
84 struct file_info
*fi
= f
;
87 pthread_mutex_lock(&fi
->mutex
);
92 if (!fi
->ref
&& fi
->dead
) {
93 file_cache_sync_unlocked(fi
);
94 file_cache_free_unlocked(fi
);
97 pthread_mutex_unlock(&fi
->mutex
);
100 static void file_cache_unlink(struct file_info
*fi
) {
101 struct file_info
*s
, *prev
;
104 pthread_mutex_lock(&files_mutex
);
106 for (s
= files
, prev
= NULL
; s
; s
= s
->next
) {
109 prev
->next
= s
->next
;
119 pthread_mutex_unlock(&files_mutex
);
122 int file_cache_close(void *f
) {
123 struct file_info
*fi
= f
;
127 file_cache_unlink(f
);
129 pthread_mutex_lock(&fi
->mutex
);
131 pthread_mutex_unlock(&fi
->mutex
);
136 void* file_cache_open(const char *path
, int flags
) {
137 struct file_info
*fi
;
138 char tempfile
[PATH_MAX
];
143 if ((fi
= file_cache_get(path
))) {
144 if (flags
& O_RDONLY
|| flags
& O_RDWR
) fi
->readable
= 1;
145 if (flags
& O_WRONLY
|| flags
& O_RDWR
) fi
->writable
= 1;
149 if (!(session
= session_get())) {
154 fi
= malloc(sizeof(struct file_info
));
155 memset(fi
, 0, sizeof(struct file_info
));
158 fi
->filename
= strdup(path
);
160 snprintf(tempfile
, sizeof(tempfile
), "%s/fusedav-cache-XXXXXX", "/tmp");
161 if ((fi
->fd
= mkstemp(tempfile
)) < 0)
165 req
= ne_request_create(session
, "HEAD", path
);
168 ne_add_response_header_handler(req
, "Content-Length", ne_duplicate_header
, &length
);
170 if (ne_request_dispatch(req
) != NE_OK
) {
171 fprintf(stderr
, "HEAD failed: %s\n", ne_get_error(session
));
177 fprintf(stderr
, "HEAD did not return content length.\n");
182 fi
->server_length
= fi
->length
= atoi(length
);
184 ne_request_destroy(req
);
187 if (flags
& O_RDONLY
|| flags
& O_RDWR
) fi
->readable
= 1;
188 if (flags
& O_WRONLY
|| flags
& O_RDWR
) fi
->writable
= 1;
190 pthread_mutex_init(&fi
->mutex
, NULL
);
192 pthread_mutex_lock(&files_mutex
);
195 pthread_mutex_unlock(&files_mutex
);
204 ne_request_destroy(req
);
219 static int load_up_to_unlocked(struct file_info
*fi
, off_t l
) {
220 ne_content_range range
;
224 if (!(session
= session_get())) {
229 if (l
> fi
->server_length
)
230 l
= fi
->server_length
;
232 if (l
<= fi
->present
)
235 if (lseek(fi
->fd
, fi
->present
, SEEK_SET
) != fi
->present
)
238 range
.start
= fi
->present
;
241 if (ne_get_range(session
, fi
->filename
, &range
, fi
->fd
)) {
242 fprintf(stderr
, "GET failed: %s\n", ne_get_error(session
));
251 int file_cache_read(void *f
, char *buf
, size_t size
, off_t offset
) {
252 struct file_info
*fi
= f
;
255 assert(fi
&& buf
&& size
);
257 pthread_mutex_lock(&fi
->mutex
);
259 if (load_up_to_unlocked(fi
, offset
+size
) < 0)
262 if ((r
= pread(fi
->fd
, buf
, size
, offset
)) < 0)
267 pthread_mutex_unlock(&fi
->mutex
);
272 int file_cache_write(void *f
, const char *buf
, size_t size
, off_t offset
) {
273 struct file_info
*fi
= f
;
278 pthread_mutex_lock(&fi
->mutex
);
285 if (load_up_to_unlocked(fi
, offset
) < 0)
288 if ((r
= pwrite(fi
->fd
, buf
, size
, offset
)) < 0)
291 if (offset
+size
> fi
->present
)
292 fi
->present
= offset
+size
;
294 if (offset
+size
> fi
->length
)
295 fi
->length
= offset
+size
;
302 pthread_mutex_unlock(&fi
->mutex
);
307 int file_cache_truncate(void *f
, off_t s
) {
308 struct file_info
*fi
= f
;
312 pthread_mutex_lock(&fi
->mutex
);
315 r
= ftruncate(fi
->fd
, fi
->length
);
317 pthread_mutex_unlock(&fi
->mutex
);
322 int file_cache_sync_unlocked(struct file_info
*fi
) {
327 if (!(session
= session_get())) {
342 if (load_up_to_unlocked(fi
, (off_t
) -1) < 0)
345 if (lseek(fi
->fd
, 0, SEEK_SET
) == (off_t
)-1)
349 if (ne_put(session
, fi
->filename
, fi
->fd
)) {
350 fprintf(stderr
, "PUT failed: %s\n", ne_get_error(session
));
355 stat_cache_invalidate(fi
->filename
);
356 dir_cache_invalidate_parent(fi
->filename
);
365 int file_cache_sync(void *f
) {
366 struct file_info
*fi
= f
;
370 pthread_mutex_lock(&fi
->mutex
);
371 r
= file_cache_sync_unlocked(fi
);
372 pthread_mutex_unlock(&fi
->mutex
);
377 int file_cache_close_all(void) {
380 pthread_mutex_lock(&files_mutex
);
383 struct file_info
*fi
= files
;
385 pthread_mutex_lock(&fi
->mutex
);
387 pthread_mutex_unlock(&fi
->mutex
);
389 pthread_mutex_unlock(&files_mutex
);
390 file_cache_close(fi
);
391 file_cache_unref(fi
);
392 pthread_mutex_lock(&files_mutex
);
395 pthread_mutex_unlock(&files_mutex
);