Back to index

avfs  1.0.1
remote.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 2000-2001  Miklos Szeredi <miklos@szeredi.hu>
00004 
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 */
00008 
00009 #include "remote.h"
00010 #include "version.h"
00011 #include "namespace.h"
00012 #include "cache.h"
00013 
00014 #include <unistd.h>
00015 #include <fcntl.h>
00016 #include <sys/stat.h>
00017 
00018 #define REM_ST_VALID 20
00019 #define REM_DIR_VALID 10
00020 
00021 struct remsig {
00022     avtimestruc_t modif;
00023     avoff_t size;
00024 };
00025 
00026 struct rementry {
00027     char *name;
00028     int type;
00029     struct rementry *next;
00030 };
00031 
00032 struct remdir {
00033     avtime_t valid;
00034     struct rementry *dirlist;
00035 };
00036 
00037 struct remattr {
00038     avtime_t valid;
00039     int negative;
00040     struct avstat st;
00041     char *linkname;
00042 };
00043 
00044 struct remfile {
00045     struct remsig sig;
00046     char *localname;
00047     void *data;
00048 };
00049 
00050 struct remnode {
00051     avmutex lock;
00052     avmutex filelock;
00053     struct remnode *next;
00054     struct remnode *prev;
00055     struct entry *ent;
00056     avino_t ino;
00057     struct remattr attr;
00058     struct remdir dir;
00059     struct cacheobj *file;
00060 };
00061 
00062 struct remfs {
00063     struct namespace *ns;
00064     struct remnode list;
00065     struct remote *rem;
00066     struct avfs *avfs;
00067 };
00068 
00069 static AV_LOCK_DECL(rem_lock);
00070 
00071 static void rem_free_dir(struct remdir *dir)
00072 {
00073     struct rementry *re;
00074     
00075     while((re = dir->dirlist) != NULL) {
00076         dir->dirlist = re->next;
00077         av_free(re->name);
00078         av_free(re);
00079     }
00080 }
00081 
00082 static void rem_free_node(struct remnode *nod)
00083 {
00084     av_namespace_set(nod->ent, NULL);
00085     av_unref_obj(nod->ent);
00086     rem_free_dir(&nod->dir);
00087     av_free(nod->attr.linkname);
00088     av_unref_obj(nod->file);
00089 
00090     AV_FREELOCK(nod->lock);
00091     AV_FREELOCK(nod->filelock);
00092 }
00093 
00094 static struct remnode *rem_new_node(struct remfs *fs)
00095 {
00096     struct remnode *nod;
00097 
00098     AV_NEW_OBJ(nod, rem_free_node);
00099     AV_INITLOCK(nod->lock);
00100     AV_INITLOCK(nod->filelock);
00101     nod->ino = av_new_ino(fs->avfs);
00102     nod->attr.valid = 0;
00103     nod->attr.linkname = NULL;
00104     nod->dir.valid = 0;
00105     nod->file = NULL;
00106 
00107     return nod;
00108 }
00109 
00110 static void rem_remove_node(struct remnode *nod)
00111 {
00112     struct remnode *next = nod->next;
00113     struct remnode *prev = nod->prev;
00114     
00115     next->prev = prev;
00116     prev->next = next;
00117 }
00118 
00119 static void rem_insert_node(struct remfs *fs, struct remnode *nod)
00120 {
00121     struct remnode *next = fs->list.next;
00122     struct remnode *prev = &fs->list;
00123     
00124     next->prev = nod;
00125     prev->next = nod;
00126     nod->prev = prev;
00127     nod->next = next;
00128 }
00129 
00130 static struct remnode *rem_get_node(struct remfs *fs, struct entry *ent)
00131 {
00132     struct remnode *nod;
00133 
00134     AV_LOCK(rem_lock);
00135     nod = (struct remnode *) av_namespace_get(ent);
00136     if(nod != NULL)
00137         rem_remove_node(nod);
00138     else {
00139         nod = rem_new_node(fs);
00140         nod->ent = ent;
00141         av_namespace_set(ent, nod);
00142         if((fs->rem->flags & REM_NOCASE) != 0)
00143             av_namespace_setflags(ent, NSF_NOCASE, 0);
00144         av_ref_obj(ent);
00145     }
00146     rem_insert_node(fs, nod);
00147     av_ref_obj(nod);
00148     AV_UNLOCK(rem_lock);
00149 
00150     return nod;
00151 }
00152 
00153 static void rem_get_locked_node(struct remfs *fs, struct entry *ent,
00154                                 struct remnode **nodep,
00155                                 struct remnode **parentp)
00156 {
00157     struct remnode *nod;
00158     struct remnode *parent;
00159     struct entry *pent;
00160 
00161     pent = av_namespace_lookup(fs->ns, ent, NULL);
00162     if(pent != NULL) {
00163         parent = rem_get_node(fs, pent);
00164         av_unref_obj(pent);
00165     }
00166     else
00167         parent = NULL;
00168 
00169     nod = rem_get_node(fs, ent);
00170 
00171     if(parent != NULL)
00172         AV_LOCK(parent->lock);
00173     AV_LOCK(nod->lock);
00174 
00175     *nodep = nod;
00176     *parentp = parent;
00177 }
00178 
00179 static void rem_put_locked_node(struct remnode *nod, struct remnode *parent)
00180 {
00181     AV_UNLOCK(nod->lock);
00182     if(parent != NULL)
00183         AV_UNLOCK(parent->lock);
00184 
00185     av_unref_obj(nod);
00186     av_unref_obj(parent);
00187 }
00188 
00189 
00190 static void rem_free_dirlist(struct remdirlist *dl)
00191 {
00192     int i;
00193 
00194     for(i = 0; i < dl->num; i++) {
00195         av_free(dl->ents[i].name);
00196         av_free(dl->ents[i].linkname);
00197     }
00198 
00199     av_free(dl->ents);
00200     av_free(dl->hostpath.host);
00201     av_free(dl->hostpath.path);
00202 }
00203 
00204 static void rem_fill_attr(struct remfs *fs, struct remnode *nod,
00205                           struct remdirent *de, avtime_t now)
00206 {
00207     struct remattr *attr = &nod->attr;
00208 
00209     attr->valid = now + REM_ST_VALID;
00210     attr->negative = 0;
00211     attr->st = de->attr;
00212     attr->st.ino = nod->ino;
00213     attr->st.dev = fs->avfs->dev;
00214     av_free(attr->linkname);
00215     attr->linkname = av_strdup(de->linkname);
00216 }
00217 
00218 static void rem_fill_root(struct remfs *fs, struct remnode *nod)
00219 {
00220     struct remattr *attr = &nod->attr;
00221     
00222     attr->valid = AV_MAXTIME;
00223     attr->negative = 0;
00224     attr->st.ino = nod->ino;
00225     attr->st.dev = fs->avfs->dev;
00226     attr->st.mode = AV_IFDIR | 0777;
00227     attr->st.nlink = 2;
00228     attr->st.uid = 0;
00229     attr->st.gid = 0;
00230     attr->st.size = 0;
00231     attr->st.blksize = 512;
00232     attr->st.blocks = 0;
00233     attr->st.atime.sec = 0;
00234     attr->st.atime.nsec = 0;
00235     attr->st.mtime = attr->st.atime;
00236     attr->st.ctime = attr->st.atime;
00237 }
00238 
00239 static int rem_list_single(struct remfs *fs, struct remnode *nod,
00240                            struct remdirlist *dl)
00241 {
00242     int i;
00243 
00244     for(i = 0; i < dl->num; i++) {
00245         struct remdirent *de = &dl->ents[i];
00246 
00247         if(strcmp(de->name, dl->hostpath.path) == 0) {
00248             rem_fill_attr(fs, nod, de, av_time());
00249             return 0;
00250         }
00251     }
00252 
00253     return -ENOENT;
00254 }
00255 
00256 static void rem_dir_add(struct remdir *dir, struct remdirent *de)
00257 {
00258     struct rementry **rep;
00259     struct rementry *re;
00260     
00261     for(rep = &dir->dirlist; *rep != NULL; rep = &(*rep)->next);
00262     
00263     AV_NEW(re);
00264     re->name = av_strdup(de->name);
00265     re->type = AV_TYPE(de->attr.mode);
00266     re->next = NULL;
00267     
00268     *rep = re;
00269 }
00270 
00271 static void rem_dir_add_beg(struct remdir *dir, const char *name, int type)
00272 {
00273     struct rementry *re;
00274 
00275     AV_NEW(re);
00276     re->name = av_strdup(name);
00277     re->type = type;
00278     re->next = dir->dirlist;
00279 
00280     dir->dirlist = re;
00281 }
00282 
00283 static int rem_list_dir(struct remfs *fs, struct remnode *nod,
00284                          struct remnode *child,  struct remdirlist *dl,
00285                          struct remnode *need)
00286 {
00287     int i;
00288     avtime_t now = av_time();
00289     int found = 0;
00290     int gotdots = 0;
00291 
00292     rem_free_dir(&nod->dir);
00293     for(i = 0; i < dl->num; i++) {
00294         struct remdirent *de = &dl->ents[i];
00295         
00296         rem_dir_add(&nod->dir, de);
00297         if(strcmp(de->name, ".") == 0) {
00298             rem_fill_attr(fs, nod, de, now);
00299             if(nod == need)
00300                 found = 1;
00301 
00302             gotdots = 1;
00303         }
00304         else if(strcmp(de->name, "..") == 0)
00305             gotdots = 1;
00306         else {
00307             struct entry *cent;
00308             struct remnode *cnod;
00309 
00310             cent = av_namespace_lookup(fs->ns, nod->ent, de->name);
00311             cnod = rem_get_node(fs, cent);
00312             av_unref_obj(cent);
00313             if(cnod != child) {
00314                 AV_LOCK(cnod->lock);
00315                 rem_fill_attr(fs, cnod, de, now);
00316                 AV_UNLOCK(cnod->lock);
00317             }
00318             else
00319                 rem_fill_attr(fs, cnod, de, now);
00320 
00321             if(cnod == need)
00322                 found = 1;
00323 
00324             av_unref_obj(cnod);
00325         }
00326     }
00327     
00328     if(!gotdots) {
00329         rem_dir_add_beg(&nod->dir, "..", AV_TYPE(AV_IFDIR));
00330         rem_dir_add_beg(&nod->dir, ".", AV_TYPE(AV_IFDIR));
00331     }
00332 
00333     nod->dir.valid = now + REM_DIR_VALID;
00334 
00335     if(found)
00336         return 0;
00337     else
00338         return -ENOENT;
00339 }
00340 
00341 static void rem_get_hostpath(struct entry *ent, struct remhostpath *hp)
00342 {
00343     char *hostpath = av_namespace_getpath(ent);
00344     char *s;
00345 
00346     s = strchr(hostpath, '/');
00347     if(s == NULL) {
00348         hp->host = av_strdup(hostpath);
00349         hp->path = av_strdup("/");
00350     }
00351     else {
00352         *s = '\0';
00353         hp->host = av_strdup(hostpath);
00354         *s = '/';
00355         hp->path = av_strdup(s);
00356     }
00357     av_free(hostpath);
00358 }
00359 
00360 static void rem_dir_only(struct remdirlist *dl)
00361 {
00362     if((dl->flags & REM_LIST_SINGLE) != 0) {
00363         char *dir = dl->hostpath.path;
00364         if(strcmp(dir, "/") == 0)
00365             dl->flags = 0;
00366         else {
00367             char *s;
00368             s = strrchr(dir, '/');
00369             if(s == dir)
00370                 s++;
00371             *s = '\0';
00372             dl->flags = REM_LIST_PARENT;
00373         }
00374     }
00375 }
00376 
00377 static int rem_get_attr(struct remfs *fs, struct remnode *nod,
00378                         struct remnode *parent)
00379 {
00380     int res;
00381     struct remote *rem = fs->rem;
00382     struct remdirlist dl;
00383     
00384     dl.flags = REM_LIST_SINGLE;
00385     dl.num = 0;
00386     dl.ents = NULL;
00387     rem_get_hostpath(nod->ent, &dl.hostpath);
00388     if((rem->flags & REM_DIR_ONLY) != 0)
00389         rem_dir_only(&dl);
00390 
00391     res = rem->list(rem, &dl);
00392     if(res == 0) {
00393         if((dl.flags & REM_LIST_SINGLE) != 0)
00394             res = rem_list_single(fs, nod, &dl);
00395         else if((dl.flags & REM_LIST_PARENT) != 0)
00396             res = rem_list_dir(fs, parent, nod, &dl, nod);
00397         else
00398             res = rem_list_dir(fs, nod, NULL, &dl, nod);
00399 
00400         /* It can happen, that the root directory cannot be listed */
00401         if(parent == NULL && res == -ENOENT) {
00402             rem_fill_root(fs, nod);
00403             res = 0;
00404         }
00405     }
00406 
00407     rem_free_dirlist(&dl);
00408     
00409     if(res == -ENOENT) {
00410         nod->attr.valid = av_time() + REM_ST_VALID;
00411         nod->attr.negative = 1;
00412     }
00413 
00414     return res;
00415 }
00416 
00417 static int rem_check_node(struct remfs *fs, struct remnode *nod,
00418                           struct remnode *parent)
00419 {
00420     int res;
00421     avtime_t now = av_time();
00422 
00423     if(now < nod->attr.valid) {
00424         if(nod->attr.negative)
00425             res = -ENOENT;
00426         else
00427             res = 0;
00428     }
00429     else {
00430         nod->attr.valid = 0;
00431         res = rem_get_attr(fs, nod, parent);
00432     }
00433     
00434     return res;
00435 }
00436 
00437 static int rem_signature_valid(struct remsig *sig, struct avstat *stbuf)
00438 {
00439     if(sig->modif.sec != stbuf->mtime.sec ||
00440        sig->modif.nsec != stbuf->mtime.nsec ||
00441        sig->size != stbuf->size)
00442         return 0;
00443     else
00444         return 1;
00445 }
00446 
00447 static int rem_get_dir(struct remfs *fs, struct remnode *nod)
00448 {
00449     int res;
00450     struct remote *rem = fs->rem;
00451     struct remdirlist dl;
00452     
00453     dl.flags = 0;
00454     dl.num = 0;
00455     dl.ents = NULL;
00456     rem_get_hostpath(nod->ent, &dl.hostpath);
00457     
00458     res = rem->list(rem, &dl);
00459     if(res == 0)
00460         rem_list_dir(fs, nod, NULL, &dl, NULL);
00461 
00462     rem_free_dirlist(&dl);
00463 
00464     return res;
00465 }
00466 
00467 static int rem_check_dir(struct remfs *fs, struct remnode *nod)
00468 {
00469     int res;
00470     avtime_t now = av_time();
00471 
00472     if(now < nod->dir.valid)
00473         res = 0;
00474     else
00475         res = rem_get_dir(fs, nod);
00476     
00477     return res;
00478 }
00479 
00480 static int rem_node_type(struct remfs *fs, struct entry *ent)
00481 {
00482     int res;
00483     struct remnode *nod;
00484     struct remnode *parent;
00485 
00486     rem_get_locked_node(fs, ent, &nod, &parent);
00487     if(nod->attr.valid != 0 && !nod->attr.negative)
00488         res = 0;
00489     else 
00490         res = rem_check_node(fs, nod, parent);
00491 
00492     if(res == 0)
00493         res = AV_TYPE(nod->attr.st.mode);
00494     rem_put_locked_node(nod, parent);
00495 
00496     return res;
00497 }
00498 
00499 static struct entry *rem_ventry_entry(ventry *ve)
00500 {
00501     return (struct entry *) ve->data;
00502 }
00503 
00504 static struct entry *rem_vfile_entry(vfile *vf)
00505 {
00506     return (struct entry *) vf->data;
00507 }
00508 
00509 static struct remfs *rem_ventry_filesys(ventry *ve)
00510 {
00511     return (struct remfs *) ve->mnt->avfs->data;
00512 }
00513 
00514 static struct remfs *rem_vfile_filesys(vfile *vf)
00515 {
00516     return (struct remfs *) vf->mnt->avfs->data;
00517 }
00518 
00519 static int rem_lookup(ventry *ve, const char *name, void **newp)
00520 {
00521     int res;
00522     int type;
00523     struct entry *prev = rem_ventry_entry(ve);
00524     struct remfs *fs = rem_ventry_filesys(ve);
00525     struct entry *ent;
00526  
00527     if(prev != NULL) {
00528         res = rem_node_type(fs, prev);
00529         if(res < 0)
00530             return res;
00531         
00532         if(name != NULL && res != AV_TYPE(AV_IFDIR))
00533             return -ENOTDIR;
00534     }
00535 
00536     ent = av_namespace_lookup_all(fs->ns, prev, name);
00537     
00538     if(ent == NULL)
00539         type = 0;
00540     else {
00541         type = rem_node_type(fs, ent);
00542         if(type < 0) {
00543             av_unref_obj(ent);
00544             return type;
00545         }
00546     }
00547     av_unref_obj(prev);
00548     
00549     *newp = ent;
00550     return type;
00551 }
00552 
00553 static int rem_getpath(ventry *ve, char **resp)
00554 {
00555     struct entry *ent = rem_ventry_entry(ve);
00556 
00557     *resp = av_namespace_getpath(ent);
00558 
00559     return 0;
00560 }
00561 
00562 static void rem_putent(ventry *ve)
00563 {
00564     struct entry *ent = rem_ventry_entry(ve);
00565 
00566     av_unref_obj(ent);
00567 }
00568 
00569 static int rem_copyent(ventry *ve, void **resp)
00570 {
00571     struct entry *ent = rem_ventry_entry(ve);
00572     
00573     av_ref_obj(ent);
00574     *resp =  (void *) ent;
00575 
00576     return 0;
00577 }
00578 
00579 static void rem_check_file(struct remfs * fs, struct entry *ent)
00580 {
00581     int res;
00582     struct remnode *nod;
00583     struct remnode *parent;
00584     struct remfile *fil;
00585 
00586     rem_get_locked_node(fs, ent, &nod, &parent);
00587     fil = av_cacheobj_get(nod->file);
00588     if(fil != NULL) {
00589         res = rem_check_node(fs, nod, parent);
00590         if(res < 0 || !rem_signature_valid(&fil->sig, &nod->attr.st)) {
00591             av_unref_obj(nod->file);
00592             nod->file = NULL;
00593         }
00594         av_unref_obj(fil);
00595     }
00596     rem_put_locked_node(nod, parent);
00597 }
00598 
00599 static int rem_open(ventry *ve, int flags, avmode_t mode, void **resp)
00600 {
00601     int res;
00602     struct entry *ent = rem_ventry_entry(ve);
00603     struct remfs *fs = rem_ventry_filesys(ve);
00604     int accmode = (flags & AVO_ACCMODE);
00605 
00606     res = rem_node_type(fs, ent);
00607     if(res < 0)
00608         return res;
00609 
00610     if((flags & AVO_DIRECTORY) != 0) {
00611         if(res != AV_TYPE(AV_IFDIR))
00612             return -ENOTDIR;
00613     }
00614     else {
00615         if(accmode == AVO_WRONLY || accmode == AVO_RDWR)
00616             return -EROFS;
00617 
00618         rem_check_file(fs, ent);
00619     }
00620 
00621     av_ref_obj(ent);
00622 
00623     *resp = (void *) ent;
00624     return 0;
00625 }
00626 
00627 static struct entry *rem_dirent_lookup(struct namespace *ns,
00628                                        struct entry *parent, const char *name)
00629 {
00630     struct entry *ent;
00631 
00632     ent = av_namespace_lookup_all(ns, parent, name);
00633     if(ent == NULL) {
00634         ent = parent;
00635         av_ref_obj(ent);
00636     }
00637 
00638     return ent;
00639 }
00640 
00641 static struct rementry *rem_nth_entry(struct remdir *dir, int n)
00642 {
00643     struct rementry *re;
00644     int i;
00645 
00646     re = dir->dirlist;
00647     for(i = 0; i < n && re != NULL; i++)
00648         re = re->next;
00649     
00650     return re;
00651 }
00652 
00653 static int rem_get_direntry(struct remfs *fs, struct remnode *nod,
00654                             vfile *vf, struct avdirent *buf)
00655 {
00656     struct rementry *re;
00657     struct entry *cent;
00658     struct remnode *cnod;
00659 
00660     re = rem_nth_entry(&nod->dir, vf->ptr);
00661     if(re == NULL)
00662         return 0;
00663     
00664     cent = rem_dirent_lookup(fs->ns, nod->ent, re->name);
00665     cnod = rem_get_node(fs, cent);
00666     av_unref_obj(cent);
00667     
00668     buf->name = av_strdup(re->name);
00669     buf->type = re->type;
00670     buf->ino = cnod->ino;
00671     av_unref_obj(cnod);
00672     
00673     vf->ptr ++;
00674 
00675     return 1;
00676 }
00677 
00678 static int rem_readdir(vfile *vf, struct avdirent *buf)
00679 {
00680     int res;
00681     struct entry *ent = rem_vfile_entry(vf);
00682     struct remfs *fs = rem_vfile_filesys(vf);
00683     struct remnode *nod;
00684 
00685     nod = rem_get_node(fs, ent);
00686     AV_LOCK(nod->lock);
00687     res = rem_check_dir(fs, nod);
00688     if(res == 0)
00689         res = rem_get_direntry(fs, nod, vf, buf);
00690     AV_UNLOCK(nod->lock);
00691     av_unref_obj(nod);
00692 
00693     return res;
00694 }
00695 
00696 static int rem_close(vfile *vf)
00697 {
00698     struct entry *ent = rem_vfile_entry(vf);
00699 
00700     av_unref_obj(ent);
00701 
00702     return 0;
00703 }
00704 
00705 static void rem_get_signature(struct remfs *fs, struct entry *ent,
00706                               struct remsig *sig)
00707 {
00708     int res;
00709     struct remnode *nod;
00710     struct remnode *parent;
00711 
00712     rem_get_locked_node(fs, ent, &nod, &parent);
00713     res = rem_check_node(fs, nod, parent);
00714     if(res == 0) {
00715         sig->modif = nod->attr.st.mtime;
00716         sig->size = nod->attr.st.size;
00717     }
00718     else
00719         sig->size = -1;
00720     rem_put_locked_node(nod, parent);
00721 }
00722 
00723 static void rem_delete_file(struct remfile *fil)
00724 {
00725     av_del_tmpfile(fil->localname);
00726     av_unref_obj(fil->data);
00727 }
00728 
00729 static avoff_t rem_local_size(const char *localname)
00730 {
00731     int res;
00732     struct stat stbuf;
00733     
00734     res = stat(localname, &stbuf);
00735     if(res == 0) {
00736         /* Ramfs returns 0 diskusage */
00737         if(stbuf.st_blocks == 0)
00738             return stbuf.st_size;
00739         else
00740             return stbuf.st_blocks * 512;
00741     }
00742     else
00743         return -1;
00744     
00745 }
00746 
00747 static int rem_get_file(struct remfs *fs, struct remnode *nod,
00748                         struct remfile **resp)
00749 {
00750     int res;
00751     struct remfile *fil;
00752     struct remote *rem = fs->rem;
00753     struct remgetparam gp;
00754     char *objname;
00755     
00756     fil = (struct remfile *) av_cacheobj_get(nod->file);
00757     if(fil != NULL) {
00758         *resp = fil;
00759         return 0;
00760     }
00761 
00762     rem_get_hostpath(nod->ent, &gp.hostpath);
00763     objname = av_stradd(NULL, rem->name, ":", gp.hostpath.host,
00764                           gp.hostpath.path, NULL);
00765     
00766     if(rem->get != NULL) 
00767         res = rem->get(rem, &gp);
00768     else
00769         res = -ENOENT;
00770     av_free(gp.hostpath.host);
00771     av_free(gp.hostpath.path);
00772 
00773     if(res < 0) {
00774         av_free(objname);
00775         return res;
00776     }
00777 
00778     AV_NEW_OBJ(fil, rem_delete_file);
00779     fil->localname = gp.localname;
00780     fil->data = gp.data;
00781     rem_get_signature(fs, nod->ent, &fil->sig);
00782 
00783     av_unref_obj(nod->file);
00784     nod->file = av_cacheobj_new(fil, objname);
00785     av_free(objname);
00786 
00787     if(res == 0)
00788         av_cacheobj_setsize(nod->file, rem_local_size(fil->localname));
00789 
00790     *resp = fil;
00791 
00792     return 0;
00793 }
00794 
00795 static int rem_wait_data(struct remfs *fs, struct remnode *nod,
00796                          struct remfile *fil, avoff_t end)
00797 {
00798     int res;
00799     struct remote *rem = fs->rem;
00800     
00801     if(fil->data == NULL)
00802         return 0;
00803 
00804     res = rem->wait(rem, fil->data, end);
00805     if(res < 0)
00806         return res;
00807 
00808     if(res == 0) {
00809         av_unref_obj(fil->data);
00810         fil->data = NULL;
00811         av_cacheobj_setsize(nod->file, rem_local_size(fil->localname));
00812     }
00813 
00814     return 0;
00815 }
00816 
00817 static avssize_t rem_real_read(struct remfile *fil, vfile *vf, char *buf,
00818                                avsize_t nbyte)
00819 {
00820     avssize_t res;
00821     avoff_t sres;
00822     int fd;
00823 
00824     fd = open(fil->localname, O_RDONLY);
00825     if(fd == -1)
00826         return -errno;
00827     
00828     sres = lseek(fd, vf->ptr, SEEK_SET);
00829     if(sres == -1)
00830         res = -errno;
00831     else {
00832        res = read(fd, buf, nbyte);
00833         if(res == -1)
00834             res = -errno;
00835         else 
00836             vf->ptr += res;
00837     }
00838     close(fd);
00839 
00840     return res;
00841 }
00842 
00843 static avssize_t rem_read(vfile *vf, char *buf, avsize_t nbyte)
00844 {
00845     avssize_t res;
00846     struct remfs *fs = rem_vfile_filesys(vf);
00847     struct entry *ent = rem_vfile_entry(vf);
00848     struct remnode *nod;
00849     struct remfile *fil = NULL;
00850 
00851     nod = rem_get_node(fs, ent);
00852     AV_LOCK(nod->filelock);
00853     res = rem_get_file(fs, nod, &fil);
00854     if(res == 0) {
00855         res = rem_wait_data(fs, nod, fil, vf->ptr + nbyte);
00856         if(res == 0)
00857             res = rem_real_read(fil, vf, buf, nbyte);
00858 
00859         if(res < 0) {
00860             av_unref_obj(nod->file);
00861             nod->file = NULL;
00862         }
00863         av_unref_obj(fil);
00864     }
00865     AV_UNLOCK(nod->filelock);
00866     av_unref_obj(nod);
00867 
00868     return res;
00869 }
00870 
00871 
00872 static int rem_getattr(vfile *vf, struct avstat *buf, int attrmask)
00873 {
00874     int res;
00875     struct remfs *fs = rem_vfile_filesys(vf);
00876     struct entry *ent = rem_vfile_entry(vf);
00877     struct remnode *nod;
00878     struct remnode *parent;
00879 
00880     rem_get_locked_node(fs, ent, &nod, &parent);
00881     res = rem_check_node(fs, nod, parent);
00882     if(res == 0)
00883         *buf = nod->attr.st;
00884     rem_put_locked_node(nod, parent);
00885     
00886     return res;
00887 }
00888 
00889 static int rem_access(ventry *ve, int amode)
00890 {
00891     int res;
00892     struct remfs *fs = rem_ventry_filesys(ve);
00893     struct entry *ent = rem_ventry_entry(ve);
00894 
00895     res = rem_node_type(fs, ent);
00896     if(res < 0)
00897         return res;
00898 
00899     if((amode & AVW_OK) != 0)
00900         return -EACCES;
00901 
00902     return 0;
00903 }
00904 
00905 
00906 static int rem_readlink(ventry *ve, char **bufp)
00907 {
00908     int res;
00909     struct remfs *fs = rem_ventry_filesys(ve);
00910     struct entry *ent = rem_ventry_entry(ve);
00911     struct remnode *nod;
00912     struct remnode *parent;
00913 
00914     rem_get_locked_node(fs, ent, &nod, &parent);
00915     res = rem_check_node(fs, nod, parent);
00916     if(res == 0) {
00917         if(!AV_ISLNK(nod->attr.st.mode))
00918             res = -EINVAL;
00919         else
00920             *bufp = av_strdup(nod->attr.linkname);
00921     }
00922     rem_put_locked_node(nod, parent);
00923 
00924     return res;
00925 }
00926 
00927 static void rem_log_tree(struct namespace *ns, struct entry *ent)
00928 {
00929     char *path;
00930     struct entry *next;
00931 
00932     while(ent != NULL) {
00933         path = av_namespace_getpath(ent);
00934         av_log(AVLOG_ERROR, "    %s", path);
00935         av_free(path);
00936         rem_log_tree(ns, av_namespace_subdir(ns, ent));
00937         next = av_namespace_next(ent);
00938         av_unref_obj(ent);
00939         ent = next;
00940     }
00941 }
00942 
00943 static void rem_destroy(struct avfs *avfs)
00944 {
00945     struct remfs *fs = (struct remfs *) avfs->data;
00946     struct remote *rem = fs->rem;
00947     struct remnode *nod;
00948     struct entry *root;
00949 
00950     AV_LOCK(rem_lock);
00951     nod = fs->list.next;
00952     while(nod != &fs->list) {
00953         struct remnode *next = nod->next;
00954         
00955         av_unref_obj(nod);
00956         nod = next;
00957     }
00958     AV_UNLOCK(rem_lock);
00959     
00960     root = av_namespace_subdir(fs->ns, NULL);
00961     if(root != NULL) {
00962         av_log(AVLOG_ERROR, "%s: busy entries after destroy:", avfs->name);
00963         rem_log_tree(fs->ns, root);
00964     }
00965     av_unref_obj(fs->ns);
00966 
00967     rem->destroy(rem);
00968     av_free(fs);
00969 }
00970 
00971 void av_remote_add(struct remdirlist *dl, const char *name,
00972                      const char *linkname, struct avstat *attr)
00973 {
00974     struct remdirent *de;
00975 
00976     dl->ents = av_realloc(dl->ents, sizeof(*dl->ents) * (dl->num + 1));
00977     de = &dl->ents[dl->num];
00978     dl->num++;
00979 
00980     de->name = av_strdup(name);
00981     de->linkname = av_strdup(linkname);
00982     de->attr = *attr;
00983 }
00984 
00985 
00986 int av_remote_init(struct vmodule *module, struct remote *rem,
00987                      struct avfs **resp)
00988 {
00989     int res;
00990     struct avfs *avfs;
00991     struct remfs *fs;
00992 
00993     res = av_new_avfs(rem->name, NULL, AV_VER, AVF_ONLYROOT | AVF_NOLOCK,
00994                         module, &avfs);
00995     if(res < 0) {
00996         rem->destroy(rem);
00997         return res;
00998     }
00999 
01000     AV_NEW(fs);
01001     fs->ns = av_namespace_new();
01002     fs->list.next = fs->list.prev = &fs->list;
01003     fs->rem = rem;
01004     fs->avfs = avfs;
01005 
01006     avfs->data = fs;
01007     avfs->destroy = rem_destroy;
01008 
01009     avfs->lookup    = rem_lookup;
01010     avfs->putent    = rem_putent;
01011     avfs->copyent   = rem_copyent;
01012     avfs->getpath   = rem_getpath;
01013 
01014     avfs->open      = rem_open;
01015 
01016     avfs->close     = rem_close;
01017     avfs->read      = rem_read;
01018     avfs->readdir   = rem_readdir;
01019     avfs->getattr   = rem_getattr;
01020 
01021     avfs->access    = rem_access;
01022     avfs->readlink  = rem_readlink;
01023 
01024     av_add_avfs(avfs);
01025     
01026     *resp = avfs;
01027 
01028     return 0;
01029 }