c5a33943441d9461dcd1e13eee335a7f46af2314
[sahlberg/remote-cache.git] / migrate / remote-cache.c
1 /*
2    fuse module to perform the vfs part of read-only remote caching for NFS
3   
4    Copyright Ronnie Sahlberg 2008
5   
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #define FUSE_USE_VERSION 26
21
22 /* we use a local lock file to limit how many files we are migrating
23    across simultaneously
24 */
25 #define FILE_MIGRATE_MAX_CONCURRENT     100
26 #define FILE_MIGRATE_LIMITER_DIR "/var/lib/remote-cache"
27 #define FILE_MIGRATE_LIMITER     "/var/lib/remote-cache/lockfile"
28
29 #ifndef _GNU_SOURCE
30 #define _GNU_SOURCE
31 #endif
32 #include <fuse.h>
33 #include <stdio.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/wait.h>
39 #include <sys/statvfs.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <strings.h>
44 #include <dirent.h>
45 #include <utime.h>
46 #include <signal.h>
47 #include <pwd.h>
48 #include <grp.h>
49 #include "migrate.h"
50 #include "../lib/tdb/include/tdb.h"
51 #include "../lib/talloc/talloc.h"
52 #include "../lib/util/debug.h"
53 #include "popt.h"
54
55 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
56
57 /* this is the directory where we cache data */
58 static const char *cache  = NULL;
59
60 /* this is where the remote nfs server is mounted */
61 static const char *remote = NULL;
62
63 /* this is the directory where we present the cached image and which
64    we re-export through our local nfs server to the clients */
65 static const char *export = NULL;
66
67
68 static int debug_level = 0;
69
70 /* the maximum time in seconds we cache a directory.
71    defaults to 0 which means 'forever'
72 */
73 static int max_dir_cache;
74
75 /* minimum number of inodes in the cache filesystem before we will stop 
76    caching more directory structures.
77 */
78 static int dir_min_inodes = 100;
79
80 /* minimum number of blocks in the cache filesystem before we will stop 
81    caching more directory structures.
82 */
83 static int dir_min_blocks = 1000;
84
85 /* minimum number of inodes in the cache filesystem before we will stop 
86    caching more files.
87 */
88 static int file_min_inodes = 100;
89
90 /* minimum number of blocks in the cache filesystem before we will stop 
91    caching more files.
92 */
93 static int file_min_blocks = 10000;
94
95 /* maximum size in MB of files to be copied to the local cache.
96    0 means there is no size limit.
97 */
98 static int file_max_size = 0;
99
100 /* if 0, we check the mtime of the parent directory instead of the
101    file itself.  This speeds up things when we have an environment
102    where files are created/deleted but never modified.
103 */
104 static int file_check_parent_mtime = 0;
105
106 /* Dont migrate files that were modified less than this many
107    seconds ago.
108 */
109 static int file_min_mtime_age = 120;
110
111 /* Should we allow read/write semantics ? */
112 static int read_write = 0;
113
114 static int sigchild_initialized = 0;
115 static int debug_initialized = 0;
116 static int log_fd = -1;
117
118 struct tdb_context *groups_db = NULL;
119
120 extern int this_log_level;
121 enum debug_level { 
122         DEBUG_EMERG   = -3,
123         DEBUG_ALERT   = -2, 
124         DEBUG_CRIT    = -1,
125         DEBUG_ERR     =  0,
126         DEBUG_WARNING =  1,
127         DEBUG_NOTICE  =  2,     
128         DEBUG_INFO    =  3,
129         DEBUG_DEBUG   =  4,
130 };
131 #define DEBUG(lvl, x) \
132         do {\
133                 if ((lvl) <= debug_level) {\
134                         this_log_level = (lvl);\
135                         if (!debug_initialized) {\
136                                 dup2(log_fd, 2);\
137                                 debug_initialized=1;\
138                         }\
139                         do_debug x;\
140         }} while (0)
141
142
143 static int rate_limit_is_ok(void)
144 {
145         /* only print one message every 60 seconds */
146         static time_t last_time = 0;
147         static time_t this_time = 0;
148
149         this_time = time(NULL);
150         
151         if (this_time < last_time) {
152                 /* a job for s hawkins */
153                 last_time = this_time;
154                 return 1;
155         }
156
157         if (this_time > (last_time+60)) {
158                 last_time = this_time;
159                 return 1;
160         }
161
162         return 0;
163 }
164
165 static void unlink_object(const char *path)
166 {
167         TALLOC_CTX *mem_ctx = talloc_new(NULL);
168         char *cmd;
169         int ret;
170         struct stat st;
171
172         bzero(&st, sizeof(st));
173         ret = lstat(path, &st);
174         if ((ret == -1) && (errno == ENOENT)) {
175                 errno = 0;
176                 talloc_free(mem_ctx);
177                 return;
178         }
179
180         if ( (st.st_mode & S_IFMT) == S_IFREG) {
181                 unlink(path);
182                 talloc_free(mem_ctx);
183                 return;
184         }
185
186         cmd = talloc_asprintf(mem_ctx, "rm -rf %s", path);
187         ret = system(cmd);
188         if (ret != 0) {
189                 DEBUG(DEBUG_DEBUG,("%s failed with ret:%d\n", cmd, ret));
190         }
191         talloc_free(mem_ctx);
192 }
193
194
195 #define MAX_GROUPS 256
196 struct group_list {
197         time_t ts;
198         int num_groups;
199         gid_t groups[MAX_GROUPS];
200 };
201
202 static int
203 switch_to_real_user(void)
204 {
205         int ret;
206         uid_t uid = fuse_get_context()->uid;
207         struct group_list gl;
208         TDB_DATA data = {NULL,0};
209
210         gl.num_groups = MAX_GROUPS;
211
212         /* make sure we have a group mapping database */
213         if (groups_db == NULL) {
214                 DEBUG(DEBUG_ERR,("Initializing group mapping cache database\n"));
215                 groups_db = tdb_open("groups", 10000, TDB_INTERNAL, O_RDWR|O_CREAT, 0);
216                 if (groups_db == NULL) {
217                         DEBUG(DEBUG_ERR,("Failed to initialize group mapping database.\n"));
218                 }
219         }
220
221         if (groups_db) {
222                 TDB_DATA key, newdata;
223                 struct passwd *pw;
224
225                 key.dptr = (uint8_t *)&uid;
226                 key.dsize= sizeof(uid);
227
228                 tdb_chainlock(groups_db, key);
229                 data = tdb_fetch(groups_db, key);
230
231                 /* we already have a record for thus uid, check if it is still
232                    valid
233 5B              */
234                 if (data.dptr != NULL) {
235                         if (data.dsize != sizeof(gl)) {
236                                 DEBUG(DEBUG_ERR,("Wrong size of gl structure  was:%d expected:%d\n", (int)data.dsize, (int)sizeof(gl)));
237                                 free(data.dptr);
238                                 data.dptr = NULL;
239                                 tdb_chainunlock(groups_db, key);
240                                 goto finished_groups;
241                         }
242
243                         memcpy(&gl, data.dptr, sizeof(gl));
244                         free(data.dptr);
245                         data.dptr = NULL;
246
247                         if (gl.num_groups >= MAX_GROUPS) {
248                                 gl.num_groups = MAX_GROUPS;
249                                 DEBUG(DEBUG_ERR,("Invalid number of groups in gl structure (%d)\n", gl.num_groups));
250                         }
251
252                         if (gl.ts > time(NULL)-36000) { 
253                                 tdb_chainunlock(groups_db, key);
254                                 goto finished_groups;
255                         }
256                 }                               
257
258                 /* we need to re-read the list of groups from the system and
259                    store it in the cache
260                  */
261                 pw = getpwuid(uid);
262                 if (pw == NULL) {
263                         tdb_chainunlock(groups_db, key);
264                         goto finished_groups;
265                 }
266
267                 getgrouplist(pw->pw_name, pw->pw_gid, gl.groups, &gl.num_groups);
268                 gl.ts = time(NULL);
269
270                 newdata.dptr  = (uint8_t *)&gl;
271                 newdata.dsize = sizeof(gl);
272                 if (tdb_store(groups_db, key, newdata, TDB_REPLACE)) {
273                         DEBUG(DEBUG_ERR,("Failed to write gl structure to cahce tdb\n"));
274                         tdb_chainunlock(groups_db, key);
275                         goto finished_groups;
276                 }
277
278                 tdb_chainunlock(groups_db, key);
279         }
280 finished_groups:
281
282         ret = setgid(fuse_get_context()->gid);
283         if (ret != 0) {
284                 DEBUG(DEBUG_ERR, (__location__ " failed to setegid\n"));
285                 ret = -EACCES;
286                 goto finished;
287         }
288
289         if (gl.num_groups != MAX_GROUPS) {
290                 ret = setgroups(gl.num_groups, gl.groups);
291                 if (ret != 0) {
292                         DEBUG(DEBUG_ERR, (__location__ " failed to setgroups\n"));
293                         ret = -EACCES;
294                         goto finished;
295                 }
296         }
297
298         ret = seteuid(uid);
299         if (ret != 0) {
300                 DEBUG(DEBUG_ERR, (__location__ " failed to seteuid\n"));
301                 ret = -EACCES;
302                 goto finished;
303         }
304
305 finished:
306         return ret;
307 }
308
309 static int
310 switch_back_to_root(void )
311 {
312         /* switch back to root */
313         seteuid(0);
314         setgid(0);
315
316         return 0;
317 }
318
319 #if 0
320 static int XXXremote_cache_getattr(const char *path, struct stat *st)
321 {
322         TALLOC_CTX *mem_ctx = talloc_new(NULL);
323         char *new_path;
324         char *old_path;
325         struct stat old_st;
326         struct stat new_st;
327         int old_ret, new_ret;
328
329         new_path = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
330         old_path = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
331
332         bzero(&new_st, sizeof(new_st));
333         new_ret = lstat(new_path, &new_st);
334         bzero(&old_st, sizeof(old_st));
335         old_ret = lstat(old_path, &old_st);
336
337         DEBUG(DEBUG_DEBUG, ("GETATTR: %s (%s:%d:%d -> %s:%d:%d)\n", path, new_path, (int)new_st.st_mtime, (int)new_st.st_size, old_path, (int)old_st.st_mtime, (int)old_st.st_size));
338
339         if ( (old_ret !=0) || (new_ret!=0) 
340         || (new_st.st_mtime!=old_st.st_mtime)
341         || (new_st.st_size!=old_st.st_size) ){
342                 DEBUG(DEBUG_DEBUG, (__location__ " Need to migrate %s\n", new_path));
343 ...
344                 new_ret = lstat(new_path, &new_st);
345         }
346
347         memcpy(st, &new_st, sizeof(new_st));
348
349         talloc_free(mem_ctx);
350         return -new_ret;
351 }
352 #endif
353
354 #define MAX_NAME_LEN 255
355 struct cached_dir_entry {
356         char filename[MAX_NAME_LEN+1];
357         struct stat st;
358 };
359
360 #define CACHE_DIR_NAME ".   DIRCACHE"
361
362 int open_dir_cache_ro(TALLOC_CTX *mem_ctx, const char *path, struct stat *old_st
363 )
364 {
365         int ret;
366         int cache_fd = -1;
367         char *cache_path = NULL;
368         struct stat cache_st;
369
370         cache_path = talloc_asprintf(mem_ctx, "%s/%s/%s", cache, path, CACHE_DIR_NAME);
371
372         /* get size and timestamps of the cache file if it exists */
373         bzero(&cache_st, sizeof(cache_st));
374         ret = lstat(cache_path, &cache_st);
375         if (ret == -1) {
376                 DEBUG(DEBUG_ERR, (__location__ " Failed lstat(%s) %s(%u)\n", cache_path, strerror(errno), errno));
377                 return -1;
378         }
379         if (cache_st.st_mtime != old_st->st_mtime) {
380                 /* dont use the cache, its too old */
381                 return -1;
382         }
383
384         cache_fd = open(cache_path, O_RDONLY);
385         return cache_fd;
386 }
387
388
389
390
391 int open_parent_cache_ro(TALLOC_CTX *mem_ctx, const char *path)
392 {
393         char *ppath;
394         char *sptr;
395         char *parent_path;
396         struct stat parent_st;
397         int cache_fd = -1;
398         int ret;
399
400         ppath = talloc_strdup(mem_ctx, path);
401         sptr = rindex(ppath, '/');
402         if (sptr == NULL) {
403                 return -1;
404         }
405         *sptr = 0;
406         if (ppath[0] == 0) {
407                 return -1;
408         }
409
410         parent_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, ppath);
411         ret = lstat(parent_path, &parent_st);
412         if (ret == -1) {
413                 errno = 0;
414                 return -1;
415         }
416
417         cache_fd = open_dir_cache_ro(mem_ctx, ppath, &parent_st);
418         return cache_fd;
419 }
420
421 int unlink_parent_dir_cache(TALLOC_CTX *mem_ctx, const char *path)
422 {
423         char *ppath;
424         char *sptr;
425         char *cache_path;
426         int ret;
427
428         ppath = talloc_strdup(mem_ctx, path);
429         sptr = rindex(ppath, '/');
430         if (sptr == NULL) {
431                 return -1;
432         }
433         *sptr = 0;
434         if (ppath[0] == 0) {
435                 return -1;
436         }
437
438         cache_path   = talloc_asprintf(mem_ctx, "%s/%s", ppath, CACHE_DIR_NAME);
439
440         ret = unlink(cache_path);
441         DEBUG(DEBUG_DEBUG,("unlink_parent_dir_cache(%s) == %d\n", cache_path, ret));
442         return ret;
443 }
444
445
446 int lookup_attribute_in_parent(TALLOC_CTX *mem_ctx, const char *path, struct stat *st)
447 {
448         int cache_fd = -1;
449         struct cached_dir_entry cache_dirent;
450         char *sptr;
451         int ret = 0;
452
453         sptr = talloc_strdup(mem_ctx, path);
454         if (sptr == NULL) {
455                 ret = -1;
456                 goto finished;
457         }
458
459         sptr = rindex(sptr, '/');
460         if (sptr == NULL) {
461                 ret = -1;
462                 goto finished;
463         }
464
465         sptr++;
466         if (*sptr == 0) {
467                 ret = -1;
468                 goto finished;
469         }
470         
471         cache_fd = open_parent_cache_ro(mem_ctx, path);
472         if (cache_fd == -1) {
473                 ret = -1;
474                 goto finished;
475         }
476
477         while(read(cache_fd, &cache_dirent, sizeof(cache_dirent)) == sizeof(cache_dirent)) {
478                 if (!strcmp(cache_dirent.filename, sptr)) {
479                         memcpy(st, &cache_dirent.st, sizeof(cache_dirent.st));
480                         goto finished;
481                 }
482         }
483         ret = -1;
484
485 finished:
486         if (cache_fd) {
487                 close(cache_fd);
488         }
489         errno = 0;
490         return ret;
491 }
492
493
494 /* GETATTR, always return the data for the old object on the original share
495    let the linux NFS clients cache the metadata using normal attribute caching
496    unless file_check_parent_mtime is set in which case we just verify
497    the parents mtime and then return the cached attributes for the object.
498 */
499 static int remote_cache_getattr(const char *path, struct stat *st)
500 {
501         TALLOC_CTX *mem_ctx = talloc_new(NULL);
502         char *old_path;
503         char *new_path;
504         char *cache_path;
505         struct stat old_st;
506         struct stat cache_st;
507         int ret;
508
509         if (file_check_parent_mtime) {
510                 /* try to get the attributes from the parents cache
511                    (if the parents cache is "current"
512                 */
513                 ret = lookup_attribute_in_parent(mem_ctx, path, &old_st);
514                 if (ret != -1) {
515                 DEBUG(DEBUG_DEBUG, (__location__ " GETATTR:[%s] from parent cache\n", path));
516                         goto finished;
517                 }                       
518         }
519
520         
521         /*
522          * read the attributes from the remote site
523          */
524         old_path = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
525         new_path = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
526
527         bzero(&old_st, sizeof(old_st));
528         ret = lstat(old_path, &old_st);
529         if (ret == -1) {
530                 ret = -errno;
531                 if (errno == ENOENT) {
532                         DEBUG(DEBUG_INFO,(__location__ " File '%s' is removed from the remote site. Remove local cache copy (if any)\n", old_path));
533                         unlink_object(new_path);
534                 }
535         }
536
537         DEBUG(DEBUG_DEBUG, (__location__ " GETATTR: from remote site %s (%s:%d:%d) ret:%d\n", path, old_path, (int)old_st.st_mtime, (int)old_st.st_size, ret));
538
539         /*
540          * if it was a file, then we also check the cached copy if it has
541          * expired
542          */
543         if ( (old_st.st_mode & S_IFMT) != S_IFREG) {
544                 goto finished;
545         }
546
547         /*
548          * read the attributes from the local cache directory
549          */
550         cache_path = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
551
552         bzero(&cache_st, sizeof(cache_st));
553         if (lstat(cache_path, &cache_st) != 0) {
554                 goto finished;
555         }
556
557         /*
558          * check that the locally cached copy is valid
559          */
560         if ((cache_st.st_mtime != old_st.st_mtime)
561         ||  (cache_st.st_size != old_st.st_size)) {
562                 DEBUG(DEBUG_INFO, (__location__ " locally cached file %s has expired  (time:%u:%u size:%u:%u)\n", cache_path, (unsigned int)cache_st.st_mtime, (unsigned int)old_st.st_mtime, (unsigned int)cache_st.st_size, (unsigned int)old_st.st_size));
563                 unlink_object(cache_path);              
564         }
565
566
567 finished:
568         memcpy(st, &old_st, sizeof(old_st));
569
570         talloc_free(mem_ctx);
571         return ret;
572 }
573
574 static int remote_cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
575 {
576         TALLOC_CTX *mem_ctx = talloc_new(NULL);
577         int ret;
578         char *new_path = NULL;
579         char *old_path = NULL;
580         char *obj_path = NULL;
581         char *cache_path = NULL;
582         DIR *dir = NULL;
583         struct stat old_st;
584         struct stat cache_st;
585         struct dirent *dirent = NULL;
586         int cache_fd = -1;
587         struct cached_dir_entry cache_dirent;
588         struct flock lock;
589         struct statvfs vfs;
590
591         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
592         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
593         cache_path = talloc_asprintf(mem_ctx, "%s/%s/%s", cache, path, CACHE_DIR_NAME);
594
595         DEBUG(DEBUG_DEBUG, (__location__ " READDIR %s\n", path));
596
597 try_again:
598
599         /* check the age of the directory cache.
600            purge all cached directories older than max_dir_cache
601         */
602         if (max_dir_cache != 0) {
603                 time_t ltime;
604
605                 ltime = time(NULL); 
606                 ret = lstat(cache_path, &cache_st);
607                 if (ret != 0) {
608                         DEBUG(DEBUG_ERR, (__location__ " remote_cache_readdir: failed to stat cache file %s ret %d\n", cache_path, ret));
609                         ret = -errno;
610                         goto read_remote_build_cache;
611                 }
612                 if (ltime < cache_st.st_ctime) {
613                         DEBUG(DEBUG_ERR, (__location__ " dircache %s has ctime (%u) in the future (ltime:%u)\n", cache_path, (int)cache_st.st_ctime, (int)ltime));
614                         unlink(cache_path);
615                 }
616                 if (ltime > (cache_st.st_ctime + max_dir_cache)) {
617                         DEBUG(DEBUG_ERR, ("Cache has expired for directory %s. Flushing cache\n", new_path));
618                         unlink(cache_path);
619                 }                       
620         }
621
622         /*
623          * try to open the directory cache file and read from it
624          */
625         ret = lstat(cache_path, &cache_st);
626         if (ret != 0) {
627                 DEBUG(DEBUG_ERR, (__location__ " remote_cache_readdir: failed to stat cache file %s %s\n", cache_path, strerror(errno)));
628                 goto read_remote_build_cache;
629         }
630         ret = lstat(old_path, &old_st);
631         if (ret != 0) {
632                 DEBUG(DEBUG_ERR, (__location__ " remote_cache_readdir: failed to stat cache file %s %s\n", cache_path, strerror(errno)));
633                 goto read_remote_build_cache;
634         }
635         if (cache_st.st_mtime != old_st.st_mtime) {
636                 /* dont use the cache, its too old */
637                 DEBUG(DEBUG_ERR, (__location__ " Directory %s has expired from the cache.\n", old_path));
638                 unlink(cache_path);
639                 goto read_remote_build_cache;
640         }
641
642         ret = switch_to_real_user();
643         if (ret != 0) {
644                 DEBUG(DEBUG_ERR, (__location__ "SETEUID failed\n"));
645                 switch_back_to_root();
646                 goto finished;
647         }
648         cache_fd = open(cache_path, O_RDONLY);
649         if ((cache_fd == -1) && (errno == EACCES)) {
650                 ret = -errno;
651                 switch_back_to_root();
652                 goto finished;
653         }
654         if (cache_fd != -1) {
655                 while(read(cache_fd, &cache_dirent, sizeof(cache_dirent)) == sizeof(cache_dirent)) {
656                         filler(buf, &cache_dirent.filename[0], &cache_dirent.st, 0);
657                 }
658                 switch_back_to_root();
659                 goto finished;
660         }
661         switch_back_to_root();
662
663
664
665         /*
666          * as root, read the directory from the remote site and store it
667          * in our cache
668          */
669 read_remote_build_cache:
670         /* if we have run out of space, we cant build a local cache */
671         ret = statvfs(cache, &vfs);
672         if (ret != 0) {
673                 DEBUG(DEBUG_ERR, (__location__ " statfs(%s) failed\n", cache));
674                 ret = 0;
675                 goto read_remote;
676         }
677         if (vfs.f_bfree < dir_min_blocks) {
678                 if( rate_limit_is_ok() ){
679                         DEBUG(DEBUG_CRIT, ("Cache is full. Only %d blocks left in %s. Can not build local cache of directory %s/%s\n", (int)vfs.f_bfree, cache, export, path));
680                 }
681
682                 goto read_remote;
683         }
684         if (vfs.f_ffree < dir_min_inodes) {
685                 if( rate_limit_is_ok() ){
686                         DEBUG(DEBUG_CRIT, ("Cache is full. Only %d inodes left in %s. Can not build local cache of directory %s/%s\n", (int)vfs.f_ffree, cache, export, path));
687                 }
688
689                 goto read_remote;
690         }
691
692
693
694
695         /*
696          * stat the remote directory and create it in the cache
697          */
698         ret = lstat(old_path, &old_st);
699         if (ret != 0) {
700                 DEBUG(DEBUG_ERR, (__location__ " remote_cache_readdir: failed to stat cache file %s %s\n", cache_path, strerror(errno)));
701                 ret = -errno;
702                 goto finished;
703         }
704         mkdir(new_path, 0);
705         if (chown(new_path, old_st.st_uid, old_st.st_gid) == -1) {
706                 DEBUG(DEBUG_ERR, ("CHOWN for new directory %s failed with %s\n", new_path, strerror(errno)));
707                 unlink(cache_path);
708                 goto finished;
709         }
710         if (chmod(new_path, old_st.st_mode) == -1) {
711                 DEBUG(DEBUG_ERR, ("CHMOD for new directory %s failed with %s\n", new_path, strerror(errno)));
712                 unlink(cache_path);
713                 goto finished;
714         }
715
716
717         /*
718          * create the dir cache file
719          */
720         cache_fd = open(cache_path, O_RDWR|O_CREAT);
721         if (cache_fd == -1) {
722         DEBUG(DEBUG_ERR, (__location__ " Failed to create/open directory cache\n"));
723                 goto try_again;
724         }
725         if (fchown(cache_fd, old_st.st_uid, old_st.st_gid) == -1) {
726                 DEBUG(DEBUG_ERR, ("CHOWN for dir cache %s failed with errno:%u\n", cache_path, errno));
727                 unlink(cache_path);
728                 goto finished;
729         }
730         if (fchmod(cache_fd, old_st.st_mode) == -1) {
731                 DEBUG(DEBUG_ERR, ("CHMOD for dir cache %s failed with errno:%u\n", cache_path, errno));
732                 unlink(cache_path);
733                 goto finished;
734         }
735
736         lock.l_type = F_WRLCK;
737         lock.l_whence = SEEK_SET;
738         lock.l_start = 0;
739         lock.l_len = 1;
740         lock.l_pid = getpid();
741         if (fcntl(cache_fd, F_SETLK, &lock) != 0) {
742         DEBUG(DEBUG_ERR, (__location__ " Failed to get lock on dircache file  %s   try again later\n", new_path));
743                 sleep(1);
744                 close(cache_fd);
745                 goto try_again;
746         }
747
748 read_remote:
749         dir = opendir(old_path);
750         if (dir == NULL) {
751                 DEBUG(DEBUG_ERR, (__location__ " remote_cache_readdir: failed to open old directory %s\n", old_path));
752                 unlink(cache_path);
753                 ret = -errno;
754                 goto finished;
755         }
756
757         errno = 0;
758         while ((dirent  = readdir(dir)) != NULL) {
759                 talloc_free(obj_path);
760                 obj_path = NULL;
761
762                 if (strlen(dirent->d_name) > MAX_NAME_LEN) {
763                         DEBUG(DEBUG_ERR, (__location__ " Too long name : %s. skipping entry for %s\n",
764                                 dirent->d_name, cache_path));
765                         continue;
766                 }
767                 memcpy(&cache_dirent.filename[0],dirent->d_name, strlen(dirent->d_name)+1);
768
769
770                 obj_path = talloc_asprintf(mem_ctx, "%s/%s", old_path, dirent->d_name);
771
772                 ret = lstat(obj_path, &cache_dirent.st);
773                 if (ret != 0) {
774                         DEBUG(DEBUG_ERR, (__location__ " remote_cache_readdir: failed to stat %s ret %d\n", obj_path, ret));
775                         unlink(cache_path);
776                         ret = -errno;
777                         goto finished;
778                 }
779                 
780                 if (cache_fd != -1) {
781                         int r;
782                         r = write(cache_fd, &cache_dirent, sizeof(cache_dirent));
783                         if (r != sizeof(cache_dirent)) {
784                                 DEBUG(DEBUG_ERR, (__location__ " write of cached dirent failed for %s\n", cache_path));
785                                 close(cache_fd);
786                                 cache_fd = -1;
787                                 unlink(cache_path);
788                         }
789                 }
790
791         }
792         if (errno != 0) {
793                 DEBUG(DEBUG_ERR, (__location__ " remote_cache_readdir: readdir returned NULL and set errno to :%d for %s\n", errno, cache_path));
794                 unlink(cache_path);
795                 ret = -errno;
796         }
797
798         /* if all went well, update the timestamps of our cache to match the
799            directory on the remote server
800         */
801         if (cache_fd != -1) {
802                 struct utimbuf times;
803                 int r;
804
805                 close(cache_fd);
806                 cache_fd = -1;
807                 times.actime  = old_st.st_atime;
808                 times.modtime = old_st.st_mtime;
809                 r = utime(cache_path, &times);
810                 if (r == -1) {
811                         DEBUG(DEBUG_ERR, (__location__ " update cache time failed for %s\n", cache_path));
812                         unlink(cache_path);
813                 }
814         }
815
816         /* and finally, try it again and hopefully read it from the cache
817          * as the real user this time.
818          */
819         errno = 0;
820         goto try_again;
821
822 finished:
823         if (cache_fd != -1) {
824                 close(cache_fd);
825         }
826         if (dir) {
827                 closedir(dir);
828         }
829
830         talloc_free(mem_ctx);
831         return ret;
832 }
833
834 static int remote_cache_statfs(const char *path, struct statvfs *buf)
835 {
836         TALLOC_CTX *mem_ctx = talloc_new(NULL);
837         char *old_path = NULL;
838         int ret;
839
840 //qqq   DEBUG(DEBUG_DEBUG, (__location__ " STATFS called\n"));
841         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
842         ret = statvfs(old_path, buf);
843         if (ret == -1) {
844                 ret = -errno;
845                 goto finished;
846         }
847
848 finished:
849         talloc_free(mem_ctx);
850         return ret;
851 }
852
853 static int remote_cache_readlink(const char *path, char *buf, size_t len)
854 {
855         TALLOC_CTX *mem_ctx = talloc_new(NULL);
856         char *old_path = NULL;
857         ssize_t lsize;
858         int ret = 0;
859
860         DEBUG(DEBUG_DEBUG, (__location__ " READLINK %s\n", path));
861         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
862         lsize = readlink(old_path, buf, len);
863         if (lsize == -1) {
864                 ret = -errno;
865                 goto finished;
866         }
867
868 finished:
869         talloc_free(mem_ctx);
870         return ret;
871 }
872
873 static int remote_cache_access(const char *path, int mask)
874 {
875         int ret;
876         TALLOC_CTX *mem_ctx = talloc_new(NULL);
877         char *old_path = NULL;
878         struct stat old_st;
879         gid_t my_gid;
880         uid_t my_uid;
881         int r_is_ok;
882         int w_is_ok;
883         int x_is_ok;
884
885         DEBUG(DEBUG_DEBUG, (__location__ " ACCESS %s mask 0x%08x\n", path, mask));
886
887         if (!read_write) {
888                 if (mask & W_OK) {
889                         DEBUG(DEBUG_DEBUG, (__location__ " Access failed W was not allowed\n"));
890                         ret = -EROFS;
891                         goto finished;
892                 }
893         }
894
895         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
896
897         bzero(&old_st, sizeof(old_st));
898         ret = lstat(old_path, &old_st);
899         if (ret == -1) {
900                 DEBUG(DEBUG_ERR, (__location__ " Failed lstat(%s) %s(%u)\n", old_path, strerror(errno), errno));
901                 ret = -errno;
902                 goto finished;
903         }
904
905         my_uid = fuse_get_context()->uid;
906         my_gid = fuse_get_context()->gid;
907
908         /* check the r bit */
909         r_is_ok = 0;
910         if (mask & R_OK) {
911                 if (old_st.st_mode & S_IROTH) {
912                         r_is_ok = 1;
913                 }
914                 if ((old_st.st_mode & S_IRGRP)
915                 &&  (old_st.st_gid == my_gid) ) {
916                         r_is_ok = 1;
917                 }
918                 if ((old_st.st_mode & S_IRUSR)
919                 &&  (old_st.st_uid == my_uid) ) {
920                         r_is_ok = 1;
921                 }
922                 if (my_uid == 0) {
923                         r_is_ok = 1;
924                 }
925         } else {
926                 r_is_ok = 1;
927         }
928
929         /* check the w bit */
930         w_is_ok = 0;
931         if (mask & W_OK) {
932                 if (old_st.st_mode & S_IWOTH) {
933                         w_is_ok = 1;
934                 }
935                 if ((old_st.st_mode & S_IWGRP)
936                 &&  (old_st.st_gid == my_gid) ) {
937                         w_is_ok = 1;
938                 }
939                 if ((old_st.st_mode & S_IWUSR)
940                 &&  (old_st.st_uid == my_uid) ) {
941                         w_is_ok = 1;
942                 }
943                 if (my_uid == 0) {
944                         w_is_ok = 1;
945                 }
946         } else {
947                 w_is_ok = 1;
948         }
949
950         if (w_is_ok == 0) {
951                 DEBUG(DEBUG_DEBUG, (__location__ " Access failed W was not allowed\n"));
952                 ret = -EACCES;
953                 goto finished;
954         }
955
956         /* check the x bit */
957         x_is_ok = 0;
958         if (mask & X_OK) {
959                 if (old_st.st_mode & S_IXOTH) {
960                         x_is_ok = 1;
961                 }
962                 if ((old_st.st_mode & S_IXGRP)
963                 &&  (old_st.st_gid == my_gid) ) {
964                         x_is_ok = 1;
965                 }
966                 if ((old_st.st_mode & S_IXUSR)
967                 &&  (old_st.st_uid == my_uid) ) {
968                         x_is_ok = 1;
969                 }
970                 if (my_uid == 0) {
971                         x_is_ok = 1;
972                 }
973         } else {
974                 x_is_ok = 1;
975         }
976
977         if (x_is_ok == 0) {
978                 DEBUG(DEBUG_DEBUG, (__location__ " Access failed X was not allowed\n"));
979                 ret = -EACCES;
980                 goto finished;
981         }
982
983 finished:
984         talloc_free(mem_ctx);
985         return ret;
986 }
987
988
989 void child_migrate_file(TALLOC_CTX *mem_ctx, char *old_path, char *new_path)
990 {
991         int ret;
992         int fd, lfd;
993         struct flock lock;
994         struct flock llock;
995         char *migrate_cmd = NULL;
996
997
998         DEBUG(DEBUG_INFO, (__location__ " Migration child %d for file %s->%s\n", getpid(), old_path, new_path));
999         fd = open(new_path, O_RDWR|O_CREAT, 0600);      
1000         if (fd == -1) {
1001                 DEBUG(DEBUG_ERR, (__location__ " Failed to open/create file to migrate on local cache\n"));
1002                 exit(0);
1003         }
1004
1005         lock.l_type = F_WRLCK;
1006         lock.l_whence = SEEK_SET;
1007         lock.l_start = 0;
1008         lock.l_len = 1;
1009         lock.l_pid = getpid();
1010         if (fcntl(fd, F_SETLK, &lock) != 0) {
1011                 DEBUG(DEBUG_ERR, (__location__ " Failed to get lock on file in migrate child  %s\n", new_path));
1012                 close(fd);
1013                 exit(10);
1014         }
1015
1016         lfd = open(FILE_MIGRATE_LIMITER, O_RDWR);       
1017         if (lfd == -1) {
1018                 DEBUG(DEBUG_ERR, (__location__ " Failed to open migration limiter lock file\n"));
1019                 close(fd);
1020                 exit(0);
1021         }
1022
1023         llock.l_type = F_WRLCK;
1024         llock.l_whence = SEEK_SET;
1025         llock.l_start = random()%FILE_MIGRATE_MAX_CONCURRENT;
1026         llock.l_len = 1;
1027         llock.l_pid = getpid();
1028         if (fcntl(lfd, F_SETLK, &llock) != 0) {
1029                 DEBUG(DEBUG_ERR, (__location__ " Failed to get migration lock. Too many concurrent migrations.\n"));
1030                 perror("error ");
1031                 close(lfd);
1032                 close(fd);
1033                 exit(10);
1034         }
1035
1036
1037         migrate_cmd = talloc_asprintf(mem_ctx, "rsync -ptgo \"%s\" \"%s\"", old_path, new_path);
1038         ret = system(migrate_cmd);
1039         if (ret != 0) {
1040                 DEBUG(DEBUG_ERR, (__location__ " migration %s -> %s failed\n", old_path, new_path));
1041         }
1042
1043         lock.l_type = F_UNLCK;
1044         if (fcntl(fd, F_SETLK, &lock) != 0) {
1045                 DEBUG(DEBUG_ERR, (__location__ " Failed to unlock file in migrate child  %s\n", new_path));
1046                 close(lfd);
1047                 close(fd);
1048                 exit(10);
1049         }
1050
1051         llock.l_type = F_UNLCK;
1052         if (fcntl(lfd, F_SETLK, &llock) != 0) {
1053                 DEBUG(DEBUG_ERR, (__location__ " Failed to unlock file in migrate child  %s\n", new_path));
1054                 close(lfd);
1055                 close(fd);
1056                 exit(10);
1057         }
1058
1059         DEBUG(DEBUG_INFO, (__location__ " migration of %s -> %s complete\n", old_path, new_path));
1060         close(lfd);
1061         close(fd);
1062         exit(10);
1063 }
1064
1065 static void
1066 sigchld_handler (int signum)
1067 {
1068         int wait_stat;
1069
1070         /* reap all children */
1071         while( wait3(&wait_stat, WNOHANG, NULL) != -1);
1072 }
1073
1074
1075 int try_migrate_file(TALLOC_CTX *mem_ctx, char *old_path, char *new_path)
1076 {
1077         pid_t pid;
1078         struct sigaction sa;
1079         int ret;
1080
1081         DEBUG(DEBUG_INFO, (__location__ " TRY to migrate %s -> %s\n", old_path, new_path));
1082
1083         if (!sigchild_initialized) {
1084                 sa.sa_handler = sigchld_handler;
1085                 sigfillset(&sa.sa_mask);
1086                 sa.sa_flags = SA_RESTART;
1087                 ret = sigaction( SIGCHLD, &sa, NULL);
1088                 if (ret < 0) {
1089                         printf("failed to set up CIGCHLD handler\n");
1090                         return -1;
1091                 }
1092                 sigchild_initialized = 1;
1093         }
1094
1095         pid = fork();
1096         if (pid == -1) {
1097                 DEBUG(DEBUG_ERR, (__location__ " failed to fork migration child\n"));
1098                 goto finished;
1099         }
1100         if (pid != 0) {
1101                 goto finished;
1102         }
1103
1104         /* child process */
1105         child_migrate_file(mem_ctx, old_path, new_path);
1106         exit(0);
1107
1108 finished:
1109         errno = 0;
1110         return 0;
1111 }
1112
1113
1114 static int remote_cache_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
1115 {
1116         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1117         char *new_path = NULL;
1118         char *old_path = NULL;
1119         struct stat cache_st;
1120         struct stat old_st;
1121         struct stat new_st;
1122         int ret = 0;
1123         int fd = -1;
1124         struct statvfs vfs;
1125         time_t ltime;
1126
1127         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1128         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1129
1130
1131         DEBUG(DEBUG_DEBUG, (__location__ " READ: %s offset:%d length:%d\n", path, (int)offset, (int)size));
1132
1133
1134         /*
1135          * If we should check the mtime of the file itself
1136          * instead of using the trick to check the mtime of the parent
1137          * directory instead. Note, that trick only works if files are
1138          * created and deleted but never modified.
1139          */
1140         if (file_check_parent_mtime == 0) {
1141                 /* read attributes from local cache */
1142                 bzero(&new_st, sizeof(new_st));
1143                 ret = lstat(new_path, &new_st);
1144                 if (ret == -1) {
1145                         DEBUG(DEBUG_DEBUG, (__location__ " Failed to lstat(%s) %s\n", new_path, strerror(errno)));
1146                         goto read_from_remote_site;
1147                 }
1148
1149                 /* read attributes from remote site */
1150                 bzero(&old_st, sizeof(old_st));
1151                 ret = lstat(old_path, &old_st);
1152                 if (ret == -1) {
1153                         DEBUG(DEBUG_ERR, (__location__ " Failed to lstat(%s) %s\n", old_path, strerror(errno)));
1154                         goto finished;
1155                 }
1156
1157
1158                 if ((new_st.st_mtime != old_st.st_mtime)
1159                 ||  (new_st.st_size != old_st.st_size)) {
1160                         DEBUG(DEBUG_ERR, (__location__ " locally cached file %s has expired  (time:%u:%u size:%u:%u)\n", new_path, (unsigned int)new_st.st_mtime, (unsigned int)old_st.st_mtime, (unsigned int)new_st.st_size, (unsigned int)old_st.st_size));
1161                         unlink_object(new_path);                
1162                         goto read_from_remote_site;
1163                 }
1164
1165                 goto read_from_local_cache;
1166         }
1167
1168
1169         /* we use the trick to check the mtime of the parent directory
1170          * instead of the file itself. This reduses the pressure on the
1171          * attribute cache and speeds things up quite a lot.
1172          * This can only be used when files are created/deleted but never
1173          * modified.
1174          */
1175         ret = lookup_attribute_in_parent(mem_ctx, path, &cache_st);
1176         if (ret == -1) {
1177                 DEBUG(DEBUG_ERR, (__location__ " READ: %s not found in parent cache\n", path));
1178                 goto read_from_remote_site;
1179         }                       
1180
1181         bzero(&new_st, sizeof(new_st));
1182         ret = lstat(new_path, &new_st);
1183         if (ret == -1) {
1184                 DEBUG(DEBUG_ERR, (__location__ " Failed to lstat(%s) %s\n", new_path, strerror(errno)));
1185                 goto read_from_remote_site;
1186         }
1187         if ((new_st.st_mtime != cache_st.st_mtime)
1188         ||  (new_st.st_size != cache_st.st_size)) {
1189                 DEBUG(DEBUG_ERR, (__location__ " can not read from local cached file\n"));
1190                 goto read_from_remote_site;
1191         }
1192
1193
1194 read_from_local_cache:
1195         /*
1196          * read from local cache
1197          */
1198         errno = 0;
1199         DEBUG(DEBUG_DEBUG, (__location__ " READ: %s from local cache\n", path));
1200         ret = switch_to_real_user();
1201         if (ret != 0) {
1202                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1203                 goto finished;
1204         }
1205
1206         fd = open(new_path, O_RDONLY);
1207         if (fd == -1) {
1208                 if (errno != EACCES) {
1209                         DEBUG(DEBUG_ERR, (__location__ " READ: failed to open %s %s(%u)\n", new_path, strerror(errno), errno));
1210                 }
1211                 ret = -errno;
1212                 goto finished;
1213         }
1214         ret = pread(fd, buf, size, offset);
1215         if (ret < 0) {
1216                 DEBUG(DEBUG_ERR, (__location__ " remote_cache_read: local pread returned %d\n", ret));
1217                 ret = -errno;
1218                 goto finished;
1219         }
1220         goto finished;
1221
1222
1223         /* 
1224          * read from remote site
1225          * start a background job to migrate the entire file
1226          */
1227 read_from_remote_site:
1228         ret = switch_to_real_user();
1229         if (ret != 0) {
1230                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1231                 goto finished;
1232         }
1233
1234         errno = 0;
1235         DEBUG(DEBUG_DEBUG, (__location__ " READ: %s from remote site\n", path));
1236         fd = open(old_path, O_RDONLY);
1237         if (fd == -1) {
1238                 DEBUG(DEBUG_ERR, (__location__ " READ: failed to open remote file %s %s\n", old_path, strerror(errno)));
1239                 ret = -errno;
1240                 goto finished;
1241         }
1242         /* should forcibly invalidate parents cache here ? */
1243
1244         ret = pread(fd, buf, size, offset);
1245         if (ret < 0) {
1246                 DEBUG(DEBUG_ERR, (__location__ " remote_cache_read: remote pread returned %d\n", ret));
1247                 ret = -errno;
1248                 goto finished;
1249         }
1250
1251         switch_back_to_root();
1252
1253         if (lstat(old_path, &cache_st) == -1) {
1254                 DEBUG(DEBUG_ERR, (__location__ " Failed to stat remote file %s when trying to migrate\n", old_path));
1255                 goto finished;
1256         }
1257
1258         if ( (file_max_size > 0)
1259         &&   (cache_st.st_size>>20) > file_max_size) {
1260                 if( rate_limit_is_ok() ){
1261                         DEBUG(DEBUG_ERR,("file %s is too big for the cache %u MB\n", old_path, (int)(cache_st.st_size>>20)));
1262                 }
1263                 goto finished;
1264         }
1265
1266         /* if we have run out of space, we cant build a local cache */
1267         if (statvfs(cache, &vfs) != 0) {
1268                 DEBUG(DEBUG_ERR, (__location__ " statfs(%s) failed\n", cache));
1269                 goto finished;
1270         }
1271         if (vfs.f_bfree < file_min_blocks) {
1272                 if( rate_limit_is_ok() ){
1273                         DEBUG(DEBUG_CRIT, ("Cache is full. Only %d blocks left in %s. Can not add file %s to the cache\n", (int)vfs.f_bfree, cache, old_path));
1274                 }
1275
1276                 goto finished;
1277         }
1278         if (vfs.f_ffree < file_min_inodes) {
1279                 if( rate_limit_is_ok() ){
1280                         DEBUG(DEBUG_CRIT, ("Cache is full. Only %d inodes left in %s. Can not add file %s to the cache\n", (int)vfs.f_ffree, cache, old_path));
1281                 }
1282
1283                 goto finished;
1284         }
1285
1286         /* only migrate the file if it was last modified 
1287          * file_min_mtime_age seconds ago
1288          */
1289         bzero(&old_st, sizeof(old_st));
1290         if (lstat(old_path, &old_st) == -1) {
1291                 DEBUG(DEBUG_ERR, (__location__ " Failed to lstat(%s) %s\n", old_path, strerror(errno)));
1292                 errno = 0;
1293                 goto finished;
1294         }
1295         ltime = time(NULL);
1296         if (ltime < (old_st.st_mtime + file_min_mtime_age)) {
1297                 DEBUG(DEBUG_INFO, (__location__ " file '%s' has changed too recently (%d seconds ago, limit is %d seconds). Skipping migration\n", old_path, (int)(ltime-old_st.st_mtime), file_min_mtime_age));
1298
1299                 goto finished;
1300         }
1301
1302         try_migrate_file(mem_ctx, old_path, new_path);
1303
1304
1305 finished:
1306         switch_back_to_root();
1307
1308         if (fd != -1) {
1309                 close(fd);
1310                 fd = -1;
1311         }
1312         talloc_free(mem_ctx);
1313         return ret;
1314 }
1315
1316 static int remote_cache_mknod(const char *path, mode_t mode, dev_t rdev)
1317 {
1318         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1319         char *new_path = NULL;
1320         char *old_path = NULL;
1321         int ret;
1322
1323         if (!read_write) {      
1324                 talloc_free(mem_ctx);
1325                 return -EROFS;
1326         }
1327
1328         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1329         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1330
1331
1332         DEBUG(DEBUG_DEBUG, (__location__ " MKNOD:%s mode:%o rdev:%x\n", path, (int)mode, (int)rdev));
1333
1334         ret = switch_to_real_user();
1335         if (ret != 0) {
1336                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1337                 goto finished;
1338         }
1339
1340
1341         ret = mknod(old_path, mode, rdev);
1342         if (ret != 0) {
1343                 DEBUG(DEBUG_DEBUG,(__location__ " MKNOD %s mode:%o rdev:%x failed with errno:%u\n", old_path, mode, (int)rdev, errno));
1344                 ret = -errno;
1345                 goto finished;
1346         }
1347
1348         /* if the mknod was successful we try to delete any local cached
1349            entries for this name
1350         */
1351         switch_back_to_root();
1352         unlink_object(new_path);
1353         unlink_parent_dir_cache(mem_ctx, new_path);
1354
1355 finished:
1356         switch_back_to_root();
1357         talloc_free(mem_ctx);
1358         return ret;
1359 }
1360
1361
1362
1363 static int remote_cache_mkdir(const char *path, mode_t mode)
1364 {
1365         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1366         char *new_path = NULL;
1367         char *old_path = NULL;
1368         int ret;
1369
1370         if (!read_write) {
1371                 talloc_free(mem_ctx);
1372                 return -EROFS;
1373         }
1374
1375         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1376         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1377
1378
1379         DEBUG(DEBUG_DEBUG, (__location__ " MKDIR:%s mode:%o\n", path, (int)mode));
1380
1381         ret = switch_to_real_user();
1382         if (ret != 0) {
1383                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1384                 goto finished;
1385         }
1386
1387
1388         ret = mkdir(old_path, mode);
1389         if (ret != 0) {
1390                 DEBUG(DEBUG_DEBUG,(__location__ " MKDIR %s mode:%o failed with errno:%u\n", old_path, mode, errno));
1391                 ret = -errno;
1392                 goto finished;
1393         }
1394
1395         /* if the mkdir was successful we try to delete any local cached
1396            entries for this name
1397         */
1398         switch_back_to_root();
1399         unlink_object(new_path);
1400         unlink_parent_dir_cache(mem_ctx, new_path);
1401
1402 finished:
1403         switch_back_to_root();
1404         talloc_free(mem_ctx);
1405         return ret;
1406 }
1407
1408
1409 static int remote_cache_rmdir(const char *path)
1410 {
1411         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1412         char *new_path = NULL;
1413         char *old_path = NULL;
1414         int ret;
1415
1416         if (!read_write) {
1417                 talloc_free(mem_ctx);
1418                 return -EROFS;
1419         }
1420
1421         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1422         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1423
1424
1425         DEBUG(DEBUG_DEBUG, (__location__ " RMDIR:%s\n", path));
1426
1427         ret = switch_to_real_user();
1428         if (ret != 0) {
1429                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1430                 goto finished;
1431         }
1432
1433
1434         ret = rmdir(old_path);
1435         if (ret != 0) {
1436                 DEBUG(DEBUG_DEBUG,(__location__ " RMDIR %s failed with errno:%u\n", old_path, errno));
1437                 ret = -errno;
1438                 goto finished;
1439         }
1440
1441         /* if the rmdir was successful we try to delete any local cached
1442            entries for this name
1443         */
1444         switch_back_to_root();
1445         unlink_object(new_path);
1446         unlink_parent_dir_cache(mem_ctx, new_path);
1447
1448 finished:
1449         switch_back_to_root();
1450         talloc_free(mem_ctx);
1451         return ret;
1452 }
1453
1454
1455
1456 static int remote_cache_unlink(const char *path)
1457 {
1458         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1459         char *new_path = NULL;
1460         char *old_path = NULL;
1461         int ret;
1462
1463         if (!read_write) {
1464                 talloc_free(mem_ctx);
1465                 return -EROFS;
1466         }
1467
1468         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1469         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1470
1471
1472         DEBUG(DEBUG_DEBUG, (__location__ " UNLINK:%s\n", path));
1473
1474         ret = switch_to_real_user();
1475         if (ret != 0) {
1476                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1477                 goto finished;
1478         }
1479
1480         /* unlink the file on the remote site */
1481         ret = unlink(old_path);
1482         if (ret != 0) {
1483                 DEBUG(DEBUG_DEBUG,(__location__ " UNLINK %s failed with errno:%u\n", old_path, errno));
1484                 ret = -errno;
1485                 goto finished;
1486         }
1487
1488         /* if the unlink was successful we try to delete any local cached
1489            entries for this name and remove the cache for this directory
1490         */
1491         switch_back_to_root();
1492         unlink_object(new_path);
1493         unlink_parent_dir_cache(mem_ctx, new_path);
1494
1495 finished:
1496         switch_back_to_root();
1497         talloc_free(mem_ctx);
1498         return ret;
1499 }
1500
1501 static int remote_cache_chmod(const char *path, mode_t mode)
1502 {
1503         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1504         char *new_path = NULL;
1505         char *old_path = NULL;
1506         int ret;
1507
1508         if (!read_write) {
1509                 talloc_free(mem_ctx);
1510                 return -EROFS;
1511         }
1512
1513         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1514         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1515
1516
1517         DEBUG(DEBUG_DEBUG, (__location__ " CHMOD:%s mode:%o\n", path, mode));
1518
1519         ret = switch_to_real_user();
1520         if (ret != 0) {
1521                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1522                 goto finished;
1523         }
1524
1525
1526         ret = chmod(old_path, mode);
1527         if (ret != 0) {
1528                 DEBUG(DEBUG_DEBUG,(__location__ " CHMOD %s mode %o failed with errno:%u\n", old_path, mode, errno));
1529                 ret = -errno;
1530                 goto finished;
1531         }
1532
1533         /* if the chmod was successful we try to delete any local cached
1534            entries for this name
1535         */
1536         switch_back_to_root();
1537         unlink_object(new_path);
1538         unlink_parent_dir_cache(mem_ctx, new_path);
1539
1540 finished:
1541         switch_back_to_root();
1542         talloc_free(mem_ctx);
1543         return ret;
1544 }
1545
1546 static int remote_cache_chown(const char *path, uid_t uid, gid_t gid)
1547 {
1548         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1549         char *new_path = NULL;
1550         char *old_path = NULL;
1551         int ret;
1552
1553         if (!read_write) {
1554                 talloc_free(mem_ctx);
1555                 return -EROFS;
1556         }
1557
1558         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1559         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1560
1561
1562         DEBUG(DEBUG_DEBUG, (__location__ " CHOWN:%s uid %d gid %d\n", path, uid, gid));
1563
1564         ret = switch_to_real_user();
1565         if (ret != 0) {
1566                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1567                 goto finished;
1568         }
1569
1570
1571         ret = chown(old_path, uid, gid);
1572         if (ret != 0) {
1573                 DEBUG(DEBUG_DEBUG,(__location__ " CHOWN %s uid %d gid %d failed with errno:%u\n", old_path, uid, gid, errno));
1574                 ret = -errno;
1575                 goto finished;
1576         }
1577
1578         /* if the chown was successful we try to delete any local cached
1579            entries for this name
1580         */
1581         switch_back_to_root();
1582         unlink_object(new_path);
1583         unlink_parent_dir_cache(mem_ctx, new_path);
1584
1585 finished:
1586         switch_back_to_root();
1587         talloc_free(mem_ctx);
1588         return ret;
1589 }
1590
1591 static int remote_cache_create(const char *path, mode_t mode, struct fuse_file_info *fi)
1592 {
1593         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1594         char *new_path = NULL;
1595         char *old_path = NULL;
1596         int ret;
1597         int fd;
1598
1599         if (!read_write) {
1600                 talloc_free(mem_ctx);
1601                 return -EROFS;
1602         }
1603
1604         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1605         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1606
1607
1608         DEBUG(DEBUG_DEBUG, (__location__ " CREATE %s mode %o\n", path, mode));
1609
1610         ret = switch_to_real_user();
1611         if (ret != 0) {
1612                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1613                 goto finished;
1614         }
1615
1616
1617         fd = creat(old_path, mode);
1618         if (fd == -1) {
1619                 DEBUG(DEBUG_DEBUG,(__location__ " CREATE %s mode %o failed with errno:%u\n", old_path, mode, errno));
1620                 ret = -errno;
1621                 goto finished;
1622         }
1623         close(fd);
1624
1625         /* if the creat was successful we try to delete any local cached
1626            entries for this name
1627         */
1628         ret = 0;
1629         switch_back_to_root();
1630         unlink_object(new_path);
1631         unlink_parent_dir_cache(mem_ctx, new_path);
1632
1633 finished:
1634         switch_back_to_root();
1635         talloc_free(mem_ctx);
1636         return ret;
1637 }
1638
1639 static int remote_cache_utime(const char *path, struct utimbuf *times)
1640 {
1641         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1642         char *new_path = NULL;
1643         char *old_path = NULL;
1644         int ret;
1645
1646         if (!read_write) {
1647                 talloc_free(mem_ctx);
1648                 return -EROFS;
1649         }
1650
1651         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1652         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1653
1654
1655         DEBUG(DEBUG_DEBUG, (__location__ " UTIME %s\n", path));
1656
1657         ret = switch_to_real_user();
1658         if (ret != 0) {
1659                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1660                 goto finished;
1661         }
1662
1663
1664         ret = utime(old_path, times);
1665         if (ret != 0) {
1666                 DEBUG(DEBUG_DEBUG,(__location__ " UTIME %s failed with errno:%u\n", old_path, errno));
1667                 ret = -errno;
1668                 goto finished;
1669         }
1670
1671         /* if the utime was successful we try to delete any local cached
1672            entries for this name
1673         */
1674         switch_back_to_root();
1675         unlink_object(new_path);
1676         unlink_parent_dir_cache(mem_ctx, new_path);
1677
1678 finished:
1679         switch_back_to_root();
1680         talloc_free(mem_ctx);
1681         return ret;
1682 }
1683
1684 static int remote_cache_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
1685 {
1686         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1687         char *new_path = NULL;
1688         char *old_path = NULL;
1689         int fd = -1;
1690         int ret;
1691
1692         if (!read_write) {
1693                 talloc_free(mem_ctx);
1694                 return -EROFS;
1695         }
1696
1697         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1698         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1699
1700
1701         DEBUG(DEBUG_DEBUG, (__location__ " WRITE %s offset %d len %d\n", path, (int)offset, (int)size));
1702
1703         ret = switch_to_real_user();
1704         if (ret != 0) {
1705                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1706                 goto finished;
1707         }
1708
1709
1710         fd = open(old_path, O_RDWR);
1711         if (fd == -1) {
1712                 if (errno != EACCES) {
1713                         DEBUG(DEBUG_ERR, (__location__ " WRITE: failed to open %s %s(%u)\n", new_path, strerror(errno), errno));
1714                 }
1715                 ret = -errno;
1716                 goto finished;
1717         }
1718         ret = pwrite(fd, buf, size, offset);
1719         if (ret < 0) {
1720                 DEBUG(DEBUG_ERR, (__location__ " remote_cache_write: local pwrite returned %d\n", ret));
1721                 ret = -errno;
1722                 goto finished;
1723         }
1724
1725
1726         /* if the pwrite was successful we try to delete any local cached
1727            entries for this name
1728         */
1729         switch_back_to_root();
1730         unlink_object(new_path);
1731         unlink_parent_dir_cache(mem_ctx, new_path);
1732
1733 finished:
1734         switch_back_to_root();
1735         if (fd != -1) {
1736                 int r;
1737                 r=close(fd);
1738         }
1739         talloc_free(mem_ctx);
1740         return ret;
1741 }
1742
1743 static int remote_cache_truncate(const char *path, off_t offset)
1744 {
1745         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1746         char *new_path = NULL;
1747         char *old_path = NULL;
1748         int ret;
1749
1750         if (!read_write) {
1751                 talloc_free(mem_ctx);
1752                 return -EROFS;
1753         }
1754
1755         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1756         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1757
1758
1759         DEBUG(DEBUG_DEBUG, (__location__ " TRUNCATE %s offset %d\n", path, (int)offset));
1760
1761         ret = switch_to_real_user();
1762         if (ret != 0) {
1763                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1764                 goto finished;
1765         }
1766
1767
1768         ret = truncate(old_path, offset);
1769         if (ret != 0) {
1770                 DEBUG(DEBUG_DEBUG,(__location__ " TRUNCATE %s offset %d failed with errno:%u\n", old_path, (int)offset, errno));
1771                 ret = -errno;
1772                 goto finished;
1773         }
1774
1775         /* if the truncate was successful we try to delete any local cached
1776            entries for this name
1777         */
1778         switch_back_to_root();
1779         unlink_object(new_path);
1780         unlink_parent_dir_cache(mem_ctx, new_path);
1781
1782 finished:
1783         switch_back_to_root();
1784         talloc_free(mem_ctx);
1785         return ret;
1786 }
1787
1788 static int remote_cache_ftruncate(const char *path, off_t offset, struct fuse_file_info *fi)
1789 {
1790         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1791         char *new_path = NULL;
1792         char *old_path = NULL;
1793         int ret;
1794
1795         if (!read_write) {
1796                 talloc_free(mem_ctx);
1797                 return -EROFS;
1798         }
1799
1800         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1801         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1802
1803
1804         DEBUG(DEBUG_DEBUG, (__location__ " FTRUNCATE %s offset %d\n", path, (int)offset));
1805
1806         ret = switch_to_real_user();
1807         if (ret != 0) {
1808                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1809                 goto finished;
1810         }
1811
1812
1813         ret = truncate(old_path, offset);
1814         if (ret != 0) {
1815                 DEBUG(DEBUG_DEBUG,(__location__ " FTRUNCATE %s offset %d failed with errno:%u\n", old_path, (int)offset, errno));
1816                 ret = -errno;
1817                 goto finished;
1818         }
1819
1820         /* if the ftruncate was successful we try to delete any local cached
1821            entries for this name
1822         */
1823         switch_back_to_root();
1824         unlink_object(new_path);
1825         unlink_parent_dir_cache(mem_ctx, new_path);
1826
1827 finished:
1828         switch_back_to_root();
1829         talloc_free(mem_ctx);
1830         return ret;
1831 }
1832
1833 static int remote_cache_link(const char *path, const char *newpath)
1834 {
1835         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1836         char *new_path = NULL;
1837         char *old_path = NULL;
1838         char *new_newpath = NULL;
1839         char *old_newpath = NULL;
1840         int ret;
1841
1842         if (!read_write) {
1843                 talloc_free(mem_ctx);
1844                 return -EROFS;
1845         }
1846
1847         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1848         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1849         new_newpath= talloc_asprintf(mem_ctx, "%s/%s", cache, newpath);
1850         old_newpath= talloc_asprintf(mem_ctx, "%s/%s", remote, newpath);
1851
1852
1853         DEBUG(DEBUG_DEBUG, (__location__ " LINK %s -> %s\n", path, newpath));
1854
1855         ret = switch_to_real_user();
1856         if (ret != 0) {
1857                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1858                 goto finished;
1859         }
1860
1861         ret = link(old_path, old_newpath);
1862         if (ret != 0) {
1863                 DEBUG(DEBUG_DEBUG,(__location__ " LINK %s -> %s failed with errno:%u\n", old_path, old_newpath, errno));
1864                 ret = -errno;
1865                 goto finished;
1866         }
1867
1868         /* if the link was successful we try to delete any local cached
1869            entries for this name
1870         */
1871         switch_back_to_root();
1872         unlink_object(new_newpath);
1873         unlink_parent_dir_cache(mem_ctx, new_newpath);
1874
1875 finished:
1876         switch_back_to_root();
1877         talloc_free(mem_ctx);
1878         return ret;
1879 }
1880
1881
1882 static int remote_cache_symlink(const char *linkname, const char *path)
1883 {
1884         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1885         char *new_newpath = NULL;
1886         char *old_newpath = NULL;
1887         int ret;
1888
1889         if (!read_write) {
1890                 talloc_free(mem_ctx);
1891                 return -EROFS;
1892         }
1893
1894         new_newpath= talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1895         old_newpath= talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1896
1897
1898         DEBUG(DEBUG_DEBUG, (__location__ " SYMLINK %s -> %s\n", linkname, path));
1899
1900         ret = switch_to_real_user();
1901         if (ret != 0) {
1902                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1903                 goto finished;
1904         }
1905
1906         ret = symlink(linkname, old_newpath);
1907         if (ret != 0) {
1908                 DEBUG(DEBUG_DEBUG,(__location__ " SYMLINK %s -> %s failed with errno:%u\n", linkname, old_newpath, errno));
1909                 ret = -errno;
1910                 goto finished;
1911         }
1912
1913         /* if the symlink was successful we try to delete any local cached
1914            entries for this name
1915         */
1916         switch_back_to_root();
1917         unlink_object(new_newpath);
1918         unlink_parent_dir_cache(mem_ctx, new_newpath);
1919
1920 finished:
1921         switch_back_to_root();
1922         talloc_free(mem_ctx);
1923         return ret;
1924 }
1925
1926 static int remote_cache_rename(const char *path, const char *newpath)
1927 {
1928         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1929         char *new_path = NULL;
1930         char *old_path = NULL;
1931         char *new_newpath = NULL;
1932         char *old_newpath = NULL;
1933         int ret;
1934
1935         if (!read_write) {
1936                 talloc_free(mem_ctx);
1937                 return -EROFS;
1938         }
1939
1940         new_path   = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
1941         old_path   = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
1942         new_newpath= talloc_asprintf(mem_ctx, "%s/%s", cache, newpath);
1943         old_newpath= talloc_asprintf(mem_ctx, "%s/%s", remote, newpath);
1944
1945
1946         DEBUG(DEBUG_DEBUG, (__location__ " RENAME %s -> %s\n", path, newpath));
1947
1948         ret = switch_to_real_user();
1949         if (ret != 0) {
1950                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1951                 goto finished;
1952         }
1953
1954         ret = rename(old_path, old_newpath);
1955         if (ret != 0) {
1956                 DEBUG(DEBUG_DEBUG,(__location__ " RENAME %s -> %s failed with errno:%u\n", old_path, old_newpath, errno));
1957                 ret = -errno;
1958                 goto finished;
1959         }
1960
1961         /* if the link was successful we try to delete any local cached
1962            entries for this name
1963         */
1964         switch_back_to_root();
1965         unlink_object(new_path);
1966         unlink_object(new_newpath);
1967         unlink_parent_dir_cache(mem_ctx, new_path);
1968
1969 finished:
1970         switch_back_to_root();
1971         talloc_free(mem_ctx);
1972         return ret;
1973 }
1974
1975
1976 static int remote_cache_lock(const char *path, struct fuse_file_info *ffi, int cmd, struct flock *fl)
1977 {
1978 return 0;
1979 #if 0
1980         int fd;
1981         int ret;
1982
1983         if (!read_write) {
1984                 return -EROFS;
1985         }
1986
1987         DEBUG(DEBUG_DEBUG, ("LOCK %s cmd:%s(%d)\n", path, cmd==F_GETLK?"F_GETLK":cmd==F_SETLKW?"F_SETLKW":cmd==F_SETLK?"F_SETLK":"unknown", cmd));
1988
1989         ret = switch_to_real_user();
1990         if (ret != 0) {
1991                 DEBUG(DEBUG_ERR, (__location__ " SETEUID failed\n"));
1992                 goto finished;
1993         }
1994
1995         fd = *((int *)(&ffi->fh));
1996         if (fd == -1) {
1997                 DEBUG(DEBUG_ERR,(__location__ " ERROR file to lock is not open %s\n", path));
1998                 ret = -errno;
1999                 goto finished;
2000         }
2001
2002         ret = fcntl(fd, cmd, fl);
2003         if (ret == -1) {
2004                 DEBUG(DEBUG_ERR,(__location__ " FCNTL lock failed with errno:%d for fd:%d for file %s\n", errno, fd, path));
2005                 ret = -errno;
2006                 goto finished;
2007         }
2008
2009 finished:
2010         switch_back_to_root();
2011         return ret;
2012 #endif
2013 }
2014
2015
2016 static struct fuse_operations remote_cache_ops = {
2017         .getattr        = remote_cache_getattr,
2018         .readdir        = remote_cache_readdir,
2019         .statfs         = remote_cache_statfs,
2020         .readlink       = remote_cache_readlink,
2021         .access         = remote_cache_access,
2022         .read           = remote_cache_read,
2023
2024
2025         .unlink         = remote_cache_unlink,
2026         .create         = remote_cache_create,
2027         .mknod          = remote_cache_mknod,
2028         .mkdir          = remote_cache_mkdir,
2029         .rmdir          = remote_cache_rmdir,
2030         .rename         = remote_cache_rename,
2031         .chmod          = remote_cache_chmod,
2032         .chown          = remote_cache_chown,
2033         .utime          = remote_cache_utime,
2034         .write          = remote_cache_write,
2035         .truncate       = remote_cache_truncate,
2036         .ftruncate      = remote_cache_ftruncate,
2037         .symlink        = remote_cache_symlink,
2038         .link           = remote_cache_link,
2039
2040
2041
2042         .lock           = remote_cache_lock,
2043 //      .open           = remote_cache_open,
2044 //      .release        = remote_cache_release,
2045
2046
2047
2048 //      .flush          = migrate_flush,
2049 //      .fsync          = migrate_fsync,
2050 //      .setxattr       = migrate_setxattr,
2051 //      .getxattr       = migrate_getxattr,
2052 //      .listxattr      = migrate_listxattr,
2053 //      .removexattr    = migrate_removexattr,
2054 //      .opendir        = migrate_opendir,
2055 //      .releasedir     = migrate_releasedir,
2056 //      .fsyncdir       = migrate_fsyncdir,
2057 //      .fgetattr       = migrate_fgetattr,
2058 //      .utimens        = migrate_utimens,
2059 };
2060
2061
2062 static void usage(void)
2063 {
2064         fprintf(stderr, "remote-cache [OPTIONS]\n");
2065         fprintf(stderr, "  --export=directory : the directory to re-export the data through\n");
2066         fprintf(stderr, "  --cache=directory  : the local directory to cache data in\n");
2067         fprintf(stderr, "  --remote=directory : the remote doirectory to cache\n");
2068         exit(10);
2069 }
2070
2071
2072 int main(int argc, const char *argv[])
2073 {
2074         int ret;
2075         const char *fuse_argv[] = {
2076                 "remote_cache",
2077                 "<export>",
2078                 "-oallow_other",
2079                 "-odefault_permissions",
2080                 "-ouse_ino",
2081                 "-omax_write=32768",
2082                 "-okernel_cache",
2083                 "-obig_writes",
2084                 NULL
2085         };
2086         struct poptOption popt_options[] = {
2087                 POPT_AUTOHELP
2088                 { "export", 'e', POPT_ARG_STRING, &export, 0, "export directory", "directory" },
2089                 { "cache", 'c', POPT_ARG_STRING, &cache, 0, "directory to store the cached data", "directory" },
2090                 { "remote", 'r', POPT_ARG_STRING, &remote, 0, "directory where the remote nfs data is mounted", "directory" },
2091                 { "max-dir-cache", 0, POPT_ARG_INT, &max_dir_cache, 0, "maximum number of seconds to cache a directory.", "integer" },
2092                 { "dir-min-inodes", 0, POPT_ARG_INT, &dir_min_inodes, 0, "minimum free inodes to cache directory (default 100)", "integer" },
2093                 { "dir-min-blocks", 0, POPT_ARG_INT, &dir_min_blocks, 0, "minimum free blocks to cache directory (default 1000)", "integer" },
2094                 { "file-min-inodes", 0, POPT_ARG_INT, &file_min_inodes, 0, "minimum free inodes to cache more files (default 100)", "integer" },
2095                 { "file-min-blocks", 0, POPT_ARG_INT, &file_min_blocks, 0, "minimum free blocks to cache more files (default 10000)", "integer" },
2096                 { "file-max-size", 0, POPT_ARG_INT, &file_max_size, 0, "maximum size in MB of files to cache", "integer" },
2097                 { "file-min-mtime-age", 0, POPT_ARG_INT, &file_min_mtime_age, 0, "minimum age in seconds since last change for migration", "integer" },
2098                 { "debug", 'd', POPT_ARG_INT, &debug_level, 0, "debug level", "integer" },
2099                 { "file-check-parent-mtime", 0, POPT_ARG_NONE, &file_check_parent_mtime, 0, "check mtime of remote file instead of parent directory mtime", NULL },
2100                 { "read-write", 0, POPT_ARG_NONE, &read_write, 0, "read/write cache", NULL },
2101
2102                 POPT_TABLEEND
2103         };
2104         poptContext pc;
2105         int opt;
2106         const char **extra_argv;
2107         int extra_argc = 0;
2108         struct stat st;
2109
2110 #ifdef REMOTE_CACHE_VERS
2111 #define STR(x) #x
2112 #define XSTR(x) STR(x)
2113         printf("remote-cache version %s\n", XSTR(REMOTE_CACHE_VERS));
2114 #endif
2115
2116         pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
2117         while ((opt = poptGetNextOpt(pc)) != -1) {
2118                 switch (opt) {
2119                 default:
2120                         fprintf(stderr, "Invalid option %s: %s\n", 
2121                                 poptBadOption(pc, 0), poptStrerror(opt));
2122                         exit(1);
2123                 }
2124         }
2125
2126         /* setup the remaining options for the main program to use */
2127         extra_argv = poptGetArgs(pc);
2128         if (extra_argv) {
2129                 extra_argv++;
2130                 while (extra_argv[extra_argc]) extra_argc++;
2131         }
2132
2133         if (export == NULL) {
2134                 fprintf(stderr, "You must specify --export\n");
2135                 usage();
2136         }
2137         bzero(&st, sizeof(st));
2138         ret = lstat(export, &st);
2139         if (ret == -1) {
2140                 fprintf(stderr, "Could not stat() --export %s\n", export);
2141                 perror("error: ");
2142                 fprintf(stderr, "Aborting\n");
2143                 exit(10);
2144         }
2145         if ((st.st_mode & S_IFMT) != S_IFDIR) {
2146                 fprintf(stderr, "--export %s is not a directory\n", export);
2147                 fprintf(stderr, "Aborting\n");
2148                 exit(10);
2149         }
2150
2151
2152         if (cache == NULL) {
2153                 fprintf(stderr, "You must specify --cache\n");
2154                 usage();
2155         }
2156         bzero(&st, sizeof(st));
2157         ret = lstat(cache, &st);
2158         if (ret == -1) {
2159                 fprintf(stderr, "Could not stat() --cache %s\n", cache);
2160                 perror("error: ");
2161                 fprintf(stderr, "Aborting\n");
2162                 exit(10);
2163         }
2164         if ((st.st_mode & S_IFMT) != S_IFDIR) {
2165                 fprintf(stderr, "--cache %s is not a directory\n", cache);
2166                 fprintf(stderr, "Aborting\n");
2167                 exit(10);
2168         }
2169
2170         if (remote == NULL) {
2171                 fprintf(stderr, "You must specify --remote\n");
2172                 usage();
2173         }
2174         bzero(&st, sizeof(st));
2175         ret = lstat(remote, &st);
2176         if (ret == -1) {
2177                 fprintf(stderr, "Could not stat() --remote %s\n", remote);
2178                 perror("error: ");
2179                 fprintf(stderr, "Aborting\n");
2180                 exit(10);
2181         }
2182         if ((st.st_mode & S_IFMT) != S_IFDIR) {
2183                 fprintf(stderr, "--remote %s is not a directory\n", remote);
2184                 fprintf(stderr, "Aborting\n");
2185                 exit(10);
2186         }
2187
2188
2189         ret = mkdir(FILE_MIGRATE_LIMITER_DIR, 0777);
2190         if ((ret != 0) && (errno != EEXIST)) {
2191                 printf("ERROR: could not create lock file directory %s\n", FILE_MIGRATE_LIMITER_DIR);
2192                 perror("foo");
2193                 exit (10);
2194         }
2195         errno = 0;
2196         ret = creat(FILE_MIGRATE_LIMITER, 0777);
2197         if (ret == -1) {
2198                 printf("ERROR: could not create lock file %s\n", FILE_MIGRATE_LIMITER);
2199                 exit (10);
2200         }
2201         close(ret);
2202         chmod(FILE_MIGRATE_LIMITER, 0777);
2203
2204         if (dir_min_inodes < 1) {
2205                 printf("ERROR: --dir-min-inodes must be > 0\n");
2206                 exit(10);
2207         }
2208
2209         if (dir_min_blocks < 1) {
2210                 printf("ERROR: --dir-min-blocks must be > 0\n");
2211                 exit(10);
2212         }
2213
2214         if (file_min_inodes < 1) {
2215                 printf("ERROR: --file-min-inodes must be > 0\n");
2216                 exit(10);
2217         }
2218
2219         if (file_min_blocks < 1) {
2220                 printf("ERROR: --file-min-blocks must be > 0\n");
2221                 exit(10);
2222         }
2223
2224         fuse_argv[1] = export;
2225
2226         printf("Remote caching of %s to temp storage %s exporting through %s\n", remote, cache, export);
2227
2228         printf("here we go ...\n");
2229
2230         log_fd = creat("/var/log/log.remote-cache", 0777);
2231         if (log_fd == -1) {
2232                 fprintf(stderr, "Could not open logfile. Aborting\n");
2233                 exit(10);
2234         }
2235
2236         return fuse_main(8, discard_const(fuse_argv), &remote_cache_ops, NULL);
2237 }