Back to index

avfs  1.0.1
volatile.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 2000  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 "avfs.h"
00010 #include "version.h"
00011 
00012 /* a generic information node */
00013 /* analogous to the "on-disk inode" in a disk filesystem */
00014 struct volnode {
00015     struct avstat st;
00016     struct volentry *subdir;  /* only dir */
00017     struct volentry *parent;  /* only dir */
00018     char *content;            /* only regular & symlink */
00019 };
00020 
00021 /* our ventry.data handle */
00022 /* represents a named reference to a volnode */
00023 struct volentry {
00024     char *name;
00025     struct volnode *node;
00026     struct volentry *next;
00027     struct volentry **prevp;
00028     struct volentry *parent;
00029 };
00030 
00031 /* our vmount.data handle */
00032 struct volfs {
00033     struct volentry *root;
00034     struct avfs *avfs;
00035 };
00036 
00037 /* av_obj.destr for volentry */
00038 static void vol_unlink_entry(struct volentry *ent)
00039 {
00040     if(ent->prevp != NULL)
00041         *ent->prevp = ent->next;
00042     if(ent->next != NULL)
00043         ent->next->prevp = ent->prevp;
00044     av_unref_obj(ent->parent);
00045     av_free(ent->name);
00046 
00047     ent->prevp = NULL;
00048     ent->next = NULL;
00049     ent->parent = NULL;
00050     ent->name = NULL;
00051 }
00052 
00053 /* constructor for volentry */
00054 static struct volentry *vol_new_entry(const char *name)
00055 {
00056     struct volentry *ent;
00057 
00058     AV_NEW_OBJ(ent, vol_unlink_entry);
00059 
00060     ent->node = NULL;
00061     ent->next = NULL;
00062     ent->prevp = NULL;
00063     ent->parent = NULL;
00064     ent->name = av_strdup(name);
00065 
00066     return ent;
00067 }
00068 
00069 /* av_obj.destr for volnode */
00070 static void vol_free_node(struct volnode *nod)
00071 {
00072     av_free(nod->content);
00073 }
00074 
00075 /* constructor for volnode */
00076 static struct volnode *vol_new_node(struct avstat *initstat)
00077 {
00078     struct volnode *nod;
00079 
00080     AV_NEW_OBJ(nod, vol_free_node);
00081 
00082     nod->st = *initstat;
00083     nod->subdir = NULL;
00084     nod->parent = NULL;
00085     nod->content = NULL;
00086 
00087     return nod;
00088 }
00089 
00090 /* link ent to nod */
00091 static void vol_link_node(struct volentry *ent, struct volnode *nod)
00092 {
00093     av_ref_obj(ent);
00094     av_ref_obj(nod);
00095     ent->node = nod;
00096     
00097     if(AV_ISDIR(nod->st.mode)) {
00098         nod->st.nlink = 2;
00099         if(ent->parent != NULL) {
00100             nod->parent = ent->parent;
00101             ent->parent->node->st.nlink ++;
00102         }
00103         else 
00104             nod->parent = ent;
00105     }
00106     else
00107         nod->st.nlink ++;
00108 
00109     if(ent->parent != NULL)
00110         ent->parent->node->st.size ++;    
00111 }
00112 
00113 static void vol_unlink_node(struct volentry *ent)
00114 {
00115     struct volnode *nod = ent->node;
00116     
00117     if(AV_ISDIR(nod->st.mode)) {
00118         nod->st.nlink = 0;
00119         if(nod->parent != NULL)
00120             nod->parent->node->st.nlink --;
00121     }
00122     else
00123         nod->st.nlink --;
00124 
00125     if(ent->parent != NULL)
00126         ent->parent->node->st.size --;
00127 
00128 
00129     ent->node = NULL;
00130     av_unref_obj(nod);
00131     av_unref_obj(ent);
00132 }
00133 
00134 /* called by vol_destroy */
00135 static void vol_free_tree(struct volentry *ent)
00136 {
00137     struct volnode *nod = ent->node;
00138 
00139     if(nod != NULL) {
00140         while(nod->subdir != NULL)
00141             vol_free_tree(nod->subdir);
00142         
00143         vol_unlink_entry(ent);
00144         vol_unlink_node(ent);
00145     }
00146 }
00147 
00148 static int vol_make_node(struct volfs *fs, struct volentry *ent, avmode_t mode)
00149 {
00150     struct volnode *nod;
00151     struct avstat initstat;
00152 
00153     if(ent->name == NULL)
00154         return -ENOENT;
00155 
00156     av_default_stat(&initstat);
00157     
00158     initstat.dev = fs->avfs->dev;
00159     initstat.ino = av_new_ino(fs->avfs);
00160 
00161     nod = vol_new_node(&initstat);
00162     nod->st.mode = mode;
00163     
00164     vol_link_node(ent, nod);
00165     av_unref_obj(nod);
00166 
00167     return 0;
00168 }
00169 
00170 static struct volentry *vol_ventry_volentry(ventry *ve)
00171 {
00172     return (struct volentry *) ve->data;
00173 }
00174 
00175 static struct volnode *vol_vfile_volnode(vfile *vf)
00176 {
00177     return (struct volnode *) vf->data;
00178 }
00179 
00180 static struct volfs *vol_ventry_volfs(ventry *ve)
00181 {
00182     return (struct volfs *) ve->mnt->avfs->data;
00183 }
00184 
00185 /****************************************************************/
00186 /* start of avfs ops                                            */
00187 
00188 /* called by vol_do_lookup */
00189 static struct volentry *vol_get_entry(struct volentry *parent,
00190                                       const char *name)
00191 {
00192     struct volentry **entp;
00193     struct volentry *ent;
00194 
00195     if(strcmp(name, ".") == 0) {
00196         ent = parent;
00197        av_ref_obj(ent);
00198        return ent;
00199     }
00200     if(strcmp(name, "..") == 0) {
00201         ent = parent->parent;
00202        av_ref_obj(ent);
00203        return ent;
00204     }
00205     for(entp = &parent->node->subdir; *entp != NULL; entp = &(*entp)->next)
00206        if(strcmp(name, (*entp)->name) == 0) {
00207            ent = *entp;
00208            av_ref_obj(ent);
00209            return ent;
00210        }
00211 
00212     /* lookup failed, so create a new entry and add it to the
00213        directory list temporarily */
00214  
00215     ent = vol_new_entry(name);
00216     
00217     *entp = ent;
00218     ent->prevp = entp;
00219     ent->parent = parent;
00220     av_ref_obj(parent);
00221 
00222     return ent;
00223 }
00224 
00225 /* called by vol_lookup */
00226 static int vol_do_lookup(struct volentry *parent, const char *name,
00227                          struct volentry **entp)
00228 {
00229     if(parent->node == NULL)
00230         return -ENOENT;
00231 
00232     if(name == NULL) {
00233         *entp = parent->parent;
00234         av_ref_obj(*entp);
00235         return 0;
00236     }
00237 
00238     if(!AV_ISDIR(parent->node->st.mode))
00239         return -ENOTDIR;
00240 
00241     *entp = vol_get_entry(parent, name);
00242     
00243     return 0;
00244 }
00245 
00246 /* called by vol_lookup */
00247 static struct volentry *vol_get_root(ventry *ve)
00248 {
00249     struct volfs *fs = vol_ventry_volfs(ve);
00250     struct volentry *root = fs->root;
00251 
00252     av_ref_obj(root);
00253 
00254     return root;
00255 }
00256 
00257 static int vol_lookup(ventry *ve, const char *name, void **newp)
00258 {
00259     int res = 0;
00260     struct volentry *parent = vol_ventry_volentry(ve);
00261     struct volentry *ent;
00262     
00263     if(parent == NULL) {
00264         if(name[0] != '\0' || ve->mnt->opts[0] != '\0')
00265             return -ENOENT;
00266 
00267         ent = vol_get_root(ve);
00268     }
00269     else {
00270         res = vol_do_lookup(parent, name, &ent);
00271         if(res < 0)
00272             return res;
00273         
00274         av_unref_obj(parent);
00275     }
00276 
00277     *newp = ent;
00278 
00279     if(ent != NULL && ent->node != NULL)
00280         return AV_TYPE(ent->node->st.mode);
00281     else
00282         return 0;
00283 }
00284 
00285 /* called by vol_getpath */
00286 static char *vol_create_path(struct volentry *ent)
00287 {
00288     char *path;
00289     
00290     if(ent->parent == NULL)
00291         return av_strdup("");
00292     
00293     path = vol_create_path(ent->parent);
00294 
00295     return av_stradd(path, "/", ent->name, NULL);
00296 }
00297 
00298 static int vol_getpath(ventry *ve, char **resp)
00299 {
00300     struct volentry *ent = vol_ventry_volentry(ve);
00301 
00302     *resp = vol_create_path(ent);
00303 
00304     return 0;
00305 }
00306 
00307 static void vol_putent(ventry *ve)
00308 {
00309     struct volentry *ent = vol_ventry_volentry(ve);
00310 
00311     av_unref_obj(ent);
00312 }
00313 
00314 static int vol_copyent(ventry *ve, void **resp)
00315 {
00316     struct volentry *ent = vol_ventry_volentry(ve);
00317     
00318     av_ref_obj(ent);
00319 
00320     *resp = (void *) ent;
00321 
00322     return 0;
00323 }
00324 
00325 /* called by vol_open and vol_truncate */
00326 static void vol_truncate_node(struct volnode *nod, avoff_t length)
00327 {
00328     nod->st.size = length;
00329     nod->st.blocks = AV_DIV(nod->st.size, 512);
00330     av_curr_time(&nod->st.mtime);
00331 }
00332 
00333 /* called by vol_open_check_type */
00334 static int vol_need_write(int flags)
00335 {
00336     if((flags & AVO_ACCMODE) == AVO_WRONLY ||
00337        (flags & AVO_ACCMODE) == AVO_RDWR ||
00338        (flags & AVO_TRUNC) != 0)
00339         return 1;
00340     
00341     return 0;
00342 }
00343 
00344 /* called by vol_open_check */
00345 static int vol_open_check_type(avmode_t mode, int flags)
00346 {
00347     if((flags & AVO_DIRECTORY) != 0 && !AV_ISDIR(mode))
00348         return -ENOTDIR;
00349     
00350     switch(mode & AV_IFMT) {
00351     case AV_IFREG:
00352         return 0;
00353         
00354     case AV_IFDIR:
00355         if(vol_need_write(flags))
00356             return -EISDIR;
00357         return 0;
00358 
00359     case AV_IFLNK:
00360         if((flags & AVO_ACCMODE) != AVO_NOPERM || !(flags & AVO_NOFOLLOW))
00361             return -ENOENT;
00362         return 0;
00363 
00364     default:
00365         /* FIFO, char/bockdev, socket */
00366         if((flags & AVO_ACCMODE) != AVO_NOPERM)
00367             return -ENXIO;
00368         return 0;
00369     }
00370 }
00371 
00372 /* called by vol_open */
00373 static int vol_open_check(struct volnode *nod, int flags)
00374 {
00375     if(nod == NULL) {
00376         if(!(flags & AVO_CREAT))
00377             return -ENOENT;
00378         return 0;
00379     }
00380 
00381     if((flags & AVO_EXCL) != 0)
00382         return -EEXIST;
00383 
00384     return vol_open_check_type(nod->st.mode, flags);
00385 }
00386 
00387 static int vol_open(ventry *ve, int flags, avmode_t mode, void **resp)
00388 {
00389     int res;
00390     struct volfs *fs = vol_ventry_volfs(ve);
00391     struct volentry *ent = vol_ventry_volentry(ve);
00392     
00393     /* check permissions */
00394     res = vol_open_check(ent->node, flags);
00395     if(res < 0)
00396         return res;
00397 
00398     /* create the file if it doesn't exist yet */
00399     if(ent->node == NULL) {
00400         res = vol_make_node(fs, ent, mode | AV_IFREG);
00401         if(res < 0)
00402             return res;
00403     }
00404     else if((flags & AVO_TRUNC) != 0)
00405         vol_truncate_node(ent->node, 0);
00406 
00407     av_ref_obj(ent->node);
00408     
00409     *resp = ent->node;
00410 
00411     return 0;
00412 }
00413 
00414 static int vol_close(vfile *vf)
00415 {
00416     struct volnode *nod = vol_vfile_volnode(vf);
00417 
00418     av_unref_obj(nod);
00419 
00420     return 0;
00421 }
00422 
00423 static avssize_t vol_read(vfile *vf, char *buf, avsize_t nbyte)
00424 {
00425     avoff_t nact;
00426     struct volnode *nod = vol_vfile_volnode(vf);
00427 
00428     if(AV_ISDIR(nod->st.mode))
00429         return -EISDIR;
00430     
00431     if(vf->ptr >= nod->st.size)
00432        return 0;
00433     
00434     nact = AV_MIN(nbyte, (avsize_t) (nod->st.size - vf->ptr));
00435     
00436     memcpy(buf, nod->content + vf->ptr, nact);
00437     
00438     vf->ptr += nact;
00439     
00440     return nact;
00441 }
00442 
00443 static avssize_t vol_write(vfile *vf, const char *buf, avsize_t nbyte)
00444 {
00445     avoff_t end;
00446     struct volnode *nod = vol_vfile_volnode(vf);
00447 
00448     if((vf->flags & AVO_APPEND) != 0)
00449         vf->ptr = nod->st.size;
00450 
00451     end = vf->ptr + nbyte;
00452     if(end > nod->st.size) {
00453         nod->content = av_realloc(nod->content, end);
00454         nod->st.size = end;
00455         nod->st.blocks = AV_DIV(nod->st.size, 512);
00456     }
00457 
00458     memcpy(nod->content + vf->ptr, buf, nbyte);
00459 
00460     av_curr_time(&nod->st.mtime);
00461 
00462     vf->ptr = end;
00463 
00464     return nbyte;
00465 }
00466 
00467 static int vol_truncate(vfile *vf, avoff_t length)
00468 {
00469     struct volnode *nod = vol_vfile_volnode(vf);
00470 
00471     if(length < nod->st.size)
00472         vol_truncate_node(nod, length);
00473 
00474     return 0;
00475 }
00476 
00477 /* called by vol_nth_entry */
00478 static struct volnode *vol_special_entry(int n, struct volnode *nod,
00479                                       const char **namep)
00480 {
00481     if(n == 0) {
00482         *namep = ".";
00483         return nod;
00484     }
00485     else {
00486         *namep = "..";
00487         return nod->parent->node;
00488     }
00489 }
00490 
00491 /* called by vol_readdir */
00492 static struct volnode *vol_nth_entry(int n, struct volnode *nod,
00493                                      const char **namep)
00494 {
00495     struct volentry *ent;
00496     int i;
00497 
00498     if(nod->parent != NULL) {
00499         if(n  < 2)
00500             return vol_special_entry(n, nod, namep);
00501 
00502         n -= 2;
00503     }
00504 
00505     ent = nod->subdir;
00506     for(i = 0; i < n && ent != NULL; i++)
00507         ent = ent->next;
00508     
00509     if(ent == NULL)
00510         return NULL;
00511 
00512     *namep = ent->name;
00513     return ent->node;
00514 }
00515 
00516 static int vol_readdir(vfile *vf, struct avdirent *buf)
00517 {
00518     struct volnode *parent = vol_vfile_volnode(vf);
00519     struct volnode *nod;
00520     const char *name;
00521     
00522     if(!AV_ISDIR(parent->st.mode))
00523         return -ENOTDIR;
00524     
00525     nod = vol_nth_entry(vf->ptr, parent, &name);
00526     if(nod == NULL)
00527         return 0;
00528 
00529     buf->name = av_strdup(name);
00530     buf->ino = nod->st.ino;
00531     buf->type = AV_TYPE(nod->st.mode);
00532     
00533     vf->ptr ++;
00534     
00535     return 1;
00536 }
00537 
00538 static int vol_getattr(vfile *vf, struct avstat *buf, int attrmask)
00539 {
00540     struct volnode *nod = vol_vfile_volnode(vf);
00541 
00542     *buf = nod->st;
00543 
00544     return 0;
00545 }
00546 
00547 static void vol_set_attributes(struct avstat *dest, const struct avstat *src,
00548                                int attrmask)
00549 {
00550     if((attrmask & AVA_ATIME) != 0)
00551         dest->atime = src->atime;
00552     if((attrmask & AVA_MTIME) != 0)
00553         dest->mtime = src->mtime;
00554     if((attrmask & AVA_MODE) != 0)
00555         dest->mode = (dest->mode & AV_IFMT) | src->mode;
00556     if((attrmask & AVA_UID) != 0)
00557         dest->uid = src->uid;
00558     if((attrmask & AVA_GID) != 0)
00559         dest->gid = src->gid;
00560 }
00561 
00562 static int vol_setattr(vfile *vf, struct avstat *buf, int attrmask)
00563 {
00564     struct volnode *nod = vol_vfile_volnode(vf);
00565 
00566     vol_set_attributes(&nod->st, buf, attrmask);
00567     
00568     return 0;
00569 }
00570 
00571 static int vol_access(ventry *ve, int amode)
00572 {
00573     struct volnode *nod = vol_ventry_volentry(ve)->node;
00574 
00575     if(nod == NULL) 
00576         return -ENOENT;
00577     
00578     return 0;
00579 }
00580 
00581 static int vol_readlink(ventry *ve, char **bufp)
00582 {
00583     struct volnode *nod = vol_ventry_volentry(ve)->node;
00584 
00585     if(nod == NULL)
00586         return -ENOENT;
00587 
00588     if(!AV_ISLNK(nod->st.mode))
00589         return -EINVAL;
00590 
00591     *bufp = av_strdup(nod->content);
00592 
00593     return 0;
00594 }
00595 
00596 static int vol_unlink(ventry *ve)
00597 {
00598     struct volentry *ent = vol_ventry_volentry(ve);
00599 
00600     if(ent->node == NULL)
00601         return -ENOENT;
00602 
00603     if(AV_ISDIR(ent->node->st.mode))
00604         return -EISDIR;
00605     
00606     vol_unlink_node(ent);
00607 
00608     return 0;
00609 }
00610 
00611 /* called by vol_rmdir */
00612 static int vol_check_rmdir(struct volentry *ent)
00613 {
00614     struct volnode *nod = ent->node;
00615 
00616     if(nod == NULL)
00617         return -ENOENT;
00618 
00619     if(!AV_ISDIR(nod->st.mode)) 
00620         return -ENOTDIR;
00621 
00622     if(nod->subdir != NULL)
00623         return -ENOTEMPTY;
00624 
00625     if(ent->parent == NULL)
00626         return -EBUSY;
00627 
00628     return 0;
00629 }
00630 
00631 static int vol_rmdir(ventry *ve)
00632 {
00633     int res;
00634     struct volentry *ent = vol_ventry_volentry(ve);
00635 
00636     res = vol_check_rmdir(ent);
00637     if(res < 0) 
00638         return res;
00639 
00640     vol_unlink_node(ent);
00641     
00642     return 0;
00643 }
00644 
00645 static int vol_mkdir(ventry *ve, avmode_t mode)
00646 {
00647     int res;
00648     struct volfs *fs = vol_ventry_volfs(ve);
00649     struct volentry *ent = vol_ventry_volentry(ve);
00650     
00651     if(ent->node != NULL)
00652         return -EEXIST;
00653     
00654     res = vol_make_node(fs, ent, mode | AV_IFDIR);
00655     if(res < 0)
00656         return res;
00657 
00658     return 0;
00659 }
00660 
00661 static int vol_mknod(ventry *ve, avmode_t mode, avdev_t dev)
00662 {
00663     int res;
00664     struct volfs *fs = vol_ventry_volfs(ve);
00665     struct volentry *ent = vol_ventry_volentry(ve);
00666     
00667     if(ent->node != NULL)
00668         return -EEXIST;
00669     
00670     res = vol_make_node(fs, ent, mode);
00671     if(res < 0)
00672         return res;
00673 
00674     ent->node->st.rdev = dev;
00675 
00676     return 0;
00677 }
00678 
00679 /* called by vol_check_rename */
00680 static int vol_is_subdir(struct volentry *dir, struct volentry *basedir)
00681 {
00682     while(1) {
00683         if(dir == basedir)
00684             return 1;
00685 
00686         if(dir->parent == NULL)
00687             break;
00688 
00689         dir = dir->parent;
00690     }
00691 
00692     return 0;
00693 }
00694 
00695 /* called by vol_rename */
00696 static int vol_check_rename(struct volentry *ent, struct volentry *newent)
00697 {
00698     if(ent->node == NULL)
00699         return -ENOENT;
00700 
00701     if(newent->name == NULL)
00702         return -ENOENT;
00703 
00704     if(AV_ISDIR(ent->node->st.mode) && vol_is_subdir(newent, ent))
00705         return -EINVAL;
00706 
00707     if(newent->node != NULL) {
00708         if(AV_ISDIR(ent->node->st.mode)) {
00709             if(!AV_ISDIR(newent->node->st.mode))
00710                 return -ENOTDIR;
00711 
00712             if(newent->node->subdir != NULL)
00713                 return -ENOTEMPTY;
00714         }
00715         else {
00716             if(AV_ISDIR(newent->node->st.mode))
00717                return -EISDIR;
00718         }
00719         vol_unlink_node(newent);
00720     }
00721 
00722     return 0;
00723 }
00724 
00725 static int vol_rename(ventry *ve, ventry *newve)
00726 {
00727     int res;
00728     struct volentry *ent = vol_ventry_volentry(ve);
00729     struct volentry *newent = vol_ventry_volentry(newve);
00730 
00731     if(ent->node != NULL && ent == newent)
00732         return 0;
00733 
00734     res = vol_check_rename(ent, newent);
00735     if(res < 0)
00736         return res;
00737 
00738     vol_link_node(newent, ent->node);
00739     vol_unlink_node(ent);
00740 
00741     return 0;
00742 }
00743 
00744 /* called by vol_link */
00745 static int vol_check_link(struct volentry *ent, struct volentry *newent)
00746 {
00747     if(ent->node == NULL)
00748         return -ENOENT;
00749 
00750     if(newent->name == NULL)
00751         return -ENOENT;
00752 
00753     if(AV_ISDIR(ent->node->st.mode))
00754         return -EPERM;
00755     
00756     if(newent->node != NULL)
00757         return -EEXIST;
00758     
00759     return 0;
00760 }
00761 
00762 static int vol_link(ventry *ve, ventry *newve)
00763 {
00764     int res;
00765     struct volentry *ent = vol_ventry_volentry(ve);
00766     struct volentry *newent = vol_ventry_volentry(newve);
00767     
00768     res = vol_check_link(ent, newent);
00769     if(res < 0)
00770         return res;
00771 
00772     vol_link_node(newent, ent->node);
00773     
00774     return 0;
00775 }
00776 
00777 static int vol_symlink(const char *path, ventry *newve)
00778 {
00779     int res;
00780     struct volfs *fs = vol_ventry_volfs(newve);
00781     struct volentry *ent = vol_ventry_volentry(newve);
00782     
00783     if(ent->node != NULL)
00784         return -EEXIST;
00785 
00786     res = vol_make_node(fs, ent, 0777 | AV_IFLNK);
00787     if(res < 0)
00788         return res;
00789     
00790     ent->node->content = av_strdup(path);
00791     ent->node->st.size = strlen(path);
00792 
00793     return 0;
00794 }
00795 
00796 static void vol_destroy(struct avfs *avfs)
00797 {
00798     struct volfs *fs = (struct volfs *) avfs->data;
00799 
00800     vol_free_tree(fs->root);
00801     av_unref_obj(fs->root);
00802     av_free(fs);
00803 }
00804 
00805 /* end of avfs ops                                              */
00806 /****************************************************************/
00807 
00808 extern int av_init_module_volatile(struct vmodule *module);
00809 
00810 int av_init_module_volatile(struct vmodule *module)
00811 {
00812     int res;
00813     struct avfs *avfs;
00814     struct volfs *fs;
00815 
00816     res = av_new_avfs("volatile", NULL, AV_VER, AVF_ONLYROOT, module, &avfs);
00817     if(res < 0)
00818         return res;
00819 
00820     avfs->destroy = vol_destroy;
00821 
00822     AV_NEW(fs);
00823 
00824     avfs->data = (void *) fs;
00825 
00826     fs->root = vol_new_entry("/");
00827     fs->avfs = avfs;
00828 
00829     vol_make_node(fs, fs->root, 0755 | AV_IFDIR);
00830 
00831     avfs->lookup    = vol_lookup;
00832     avfs->putent    = vol_putent;
00833     avfs->copyent   = vol_copyent;
00834     avfs->getpath   = vol_getpath;
00835     
00836     avfs->open      = vol_open;
00837     avfs->close     = vol_close;
00838     avfs->read      = vol_read;
00839     avfs->write     = vol_write;
00840     avfs->readdir   = vol_readdir;
00841     avfs->getattr   = vol_getattr;
00842     avfs->setattr   = vol_setattr;
00843     avfs->truncate  = vol_truncate;
00844 
00845     avfs->access    = vol_access;
00846     avfs->readlink  = vol_readlink;
00847     avfs->unlink    = vol_unlink;
00848     avfs->rmdir     = vol_rmdir;
00849     avfs->mkdir     = vol_mkdir;
00850     avfs->mknod     = vol_mknod;
00851     avfs->rename    = vol_rename;
00852     avfs->link      = vol_link;
00853     avfs->symlink   = vol_symlink;
00854 
00855     av_add_avfs(avfs);
00856     
00857     return 0;
00858 }