Back to index

avfs  1.0.1
state.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 "state.h"
00010 #include "version.h"
00011 
00012 struct stentry {
00013     char *param;
00014     struct entry *ent; /* namespace.h */
00015 };
00016 
00017 struct stfile {
00018     struct stentry *stent;
00019     char *contents;
00020     int modif;
00021 };
00022 
00023 static struct stentry *state_ventry_stentry(ventry *ve)
00024 {
00025     return (struct stentry *) ve->data;
00026 }
00027 
00028 static struct namespace *state_ventry_namespace(ventry *ve)
00029 {
00030     return (struct namespace *) ve->mnt->avfs->data;
00031 }
00032 
00033 static struct stfile *state_vfile_stfile(vfile *vf)
00034 {
00035     return (struct stfile *) vf->data;
00036 }
00037 
00038 static struct namespace *state_vfile_namespace(vfile *vf)
00039 {
00040     return (struct namespace *) vf->mnt->avfs->data;
00041 }
00042 
00043 static void state_free_stentry(struct stentry *stent)
00044 {
00045     av_free(stent->param);
00046     av_unref_obj(stent->ent);
00047 }
00048 
00049 static int state_lookup(ventry *ve, const char *name, void **newp)
00050 {
00051     struct stentry *stent = state_ventry_stentry(ve);
00052     struct namespace *ns = state_ventry_namespace(ve);
00053     struct stentry *newent;
00054  
00055     if(stent != NULL) {
00056         if(stent->ent == NULL && (name == NULL || strcmp(name, "..") == 0))
00057             newent = NULL;
00058         else {
00059             AV_NEW_OBJ(newent, state_free_stentry);
00060             newent->ent = av_namespace_lookup_all(ns, stent->ent, name);
00061             newent->param = av_strdup(stent->param);
00062         }
00063     }
00064     else {
00065         AV_NEW_OBJ(newent, state_free_stentry);
00066         newent->ent = NULL;
00067         newent->param = av_strdup(name);
00068     }
00069     av_unref_obj(stent);
00070     
00071     *newp = newent;
00072 
00073     return 0;
00074 }
00075 
00076 static int state_getpath(ventry *ve, char **resp)
00077 {
00078     char *path;
00079     char *nspath;
00080     struct stentry *stent = state_ventry_stentry(ve);
00081 
00082     path = av_strdup(stent->param);
00083     if(stent->ent != NULL) {
00084         nspath = av_namespace_getpath(stent->ent);
00085         path = av_stradd(path, "/", nspath, NULL);
00086         av_free(nspath);
00087     }
00088 
00089     *resp = path;
00090 
00091     return 0;
00092 }
00093 
00094 static void state_putent(ventry *ve)
00095 {
00096     struct stentry *stent = state_ventry_stentry(ve);
00097 
00098     av_unref_obj(stent);
00099 }
00100 
00101 static int state_copyent(ventry *ve, void **resp)
00102 {
00103     struct stentry *stent = state_ventry_stentry(ve);
00104 
00105     av_ref_obj(stent);
00106     *resp = stent;
00107 
00108     return 0;
00109 }
00110 
00111 static int state_open(ventry *ve, int flags, avmode_t mode, void **resp)
00112 {
00113     int res;
00114     struct stentry *stent = state_ventry_stentry(ve);
00115     struct namespace *ns = state_ventry_namespace(ve);
00116     struct stfile *sf;
00117     struct entry *subdir;
00118     struct statefile *stf;
00119     char *contents;
00120 
00121     subdir = av_namespace_subdir(ns, stent->ent);
00122     if(stent->ent != NULL)
00123         stf = (struct statefile *) av_namespace_get(stent->ent);
00124     else
00125         stf = NULL;
00126     
00127     if(subdir == NULL && (stf == NULL || (flags & AVO_DIRECTORY) != 0))
00128         return -ENOENT;
00129 
00130     av_unref_obj(subdir);
00131 
00132     contents = NULL;
00133     if(!(flags & AVO_DIRECTORY) && stf != NULL) {
00134         if(AV_ISWRITE(flags) && stf->set == NULL)
00135             return -EACCES;
00136             
00137         if((flags & AVO_TRUNC) != 0 || stf->get == NULL)
00138             contents = av_strdup("");
00139         else {
00140             res = stf->get(stent->ent, stent->param, &contents);
00141             if(res < 0)
00142                 return res;
00143         }
00144     }
00145 
00146     AV_NEW(sf);
00147     sf->stent = stent;
00148     sf->contents = contents;
00149     sf->modif = 0;
00150     av_ref_obj(stent);
00151 
00152     if((flags & AVO_TRUNC) != 0)
00153         sf->modif = 1;
00154 
00155     *resp = sf;
00156     
00157     return 0;
00158 }
00159 
00160 
00161 static int state_close(vfile *vf)
00162 {
00163     struct stfile *sf = state_vfile_stfile(vf);
00164     int res = 0;
00165 
00166     if(sf->modif && sf->stent->ent != NULL) {
00167         struct statefile *stf;
00168 
00169         stf = (struct statefile *) av_namespace_get(sf->stent->ent);
00170 
00171         res = stf->set(sf->stent->ent, sf->stent->param, sf->contents);
00172     }
00173 
00174     av_unref_obj(sf->stent);
00175     av_free(sf->contents);
00176     av_free(sf);
00177 
00178     return res;
00179 }
00180 
00181 static avssize_t state_read(vfile *vf, char *buf, avsize_t nbyte)
00182 {
00183     avoff_t nact;
00184     avoff_t size;
00185     struct stfile *sf = state_vfile_stfile(vf);
00186 
00187     if(sf->contents == NULL)
00188         return -EISDIR;
00189 
00190     size = strlen(sf->contents);
00191     if(vf->ptr >= size)
00192        return 0;
00193     
00194     nact = AV_MIN(nbyte, (avsize_t) (size - vf->ptr));
00195     
00196     memcpy(buf, sf->contents + vf->ptr, nact);
00197     
00198     vf->ptr += nact;
00199     
00200     return nact;
00201 }
00202 
00203 static avssize_t state_write(vfile *vf, const char *buf, avsize_t nbyte)
00204 {
00205     avoff_t end;
00206     struct stfile *sf = state_vfile_stfile(vf);
00207     avoff_t size;
00208 
00209     size = strlen(sf->contents);
00210     if((vf->flags & AVO_APPEND) != 0)
00211         vf->ptr = size;
00212 
00213     end = vf->ptr + nbyte;
00214     if(end > size) {
00215         sf->contents = av_realloc(sf->contents, end + 1);
00216         sf->contents[end] = '\0';
00217     }
00218 
00219     memcpy(sf->contents + vf->ptr, buf, nbyte);
00220 
00221     vf->ptr = end;
00222     sf->modif = 1;
00223 
00224     return nbyte;
00225 }
00226 
00227 static int state_truncate(vfile *vf, avoff_t length)
00228 {
00229     struct stfile *sf = state_vfile_stfile(vf);
00230     avoff_t size;
00231 
00232     size = strlen(sf->contents);
00233 
00234     if(length < size)
00235         sf->contents[length] = '\0';
00236 
00237     sf->modif = 1;
00238 
00239     return 0;
00240 }
00241 
00242 static unsigned int state_paramhash(const char *param)
00243 {
00244     unsigned long hash = 0;
00245 
00246     for(; *param; param++) {
00247         unsigned long c = *(const unsigned char *) param;
00248         hash = (hash + (c << 4) + (c >> 4)) * 11;
00249     }
00250     return hash;
00251 }
00252 
00253 static int state_readdir(vfile *vf, struct avdirent *buf)
00254 {
00255     struct stfile *sf = state_vfile_stfile(vf);
00256     struct namespace *ns = state_vfile_namespace(vf);
00257     struct statefile *stf;
00258     struct entry *ent;
00259     int n;
00260 
00261     ent = av_namespace_subdir(ns, sf->stent->ent);
00262     for(n = vf->ptr; n > 0 && ent != NULL; n--) {
00263         struct entry *next;
00264         next = av_namespace_next(ent);
00265         av_unref_obj(ent);
00266         ent = next;
00267     }
00268     if(ent == NULL)
00269         return 0;
00270     
00271     buf->name = av_namespace_name(ent);
00272     stf = av_namespace_get(ent);
00273 
00274     /* FIXME: Make ino be some hash function of param and entry */
00275     buf->ino = (long) stf + state_paramhash(sf->stent->param);
00276     /* add hash of entry name to hash */
00277     buf->ino += state_paramhash( buf->name );
00278     /* make sure ino is not 0 or 1 */
00279     buf->ino = (avino_t)((((unsigned int)buf->ino) % (~0U - 1)) + 2);
00280     
00281     buf->type = 0;
00282     av_unref_obj(ent);
00283     
00284     vf->ptr ++;
00285     
00286     return 1;
00287 }
00288 
00289 static int state_getattr(vfile *vf, struct avstat *buf, int attrmask)
00290 {
00291     struct stfile *sf = state_vfile_stfile(vf);
00292     struct statefile *stf;
00293     char *ent_name;
00294 
00295     if(sf->stent->ent != NULL)
00296         stf = (struct statefile *) av_namespace_get(sf->stent->ent);
00297     else
00298         stf = NULL;
00299 
00300     av_default_stat(buf);
00301     /* This isn't perfect, but... */
00302     buf->ino = (long) stf + state_paramhash(sf->stent->param);
00303 
00304     /* add hash of entry name to hash */
00305     if( sf->stent->ent != NULL ) {
00306       ent_name = av_namespace_name( sf->stent->ent );
00307       buf->ino += state_paramhash( ent_name );
00308       av_free( ent_name );
00309     }
00310     /* make sure ino is not 0 or 1 */
00311     buf->ino = (avino_t)((((unsigned int)buf->ino) % (~0U - 1)) + 2);
00312     
00313     buf->dev = vf->mnt->avfs->dev;
00314     if(stf != NULL) {
00315         if(stf->set != NULL)
00316             buf->mode = AV_IFREG | 0644;
00317         else
00318             buf->mode = AV_IFREG | 0444;
00319     }
00320     else
00321         buf->mode = AV_IFDIR | 0755;
00322 
00323     if(sf->contents != NULL) {
00324         buf->size = strlen(sf->contents);
00325         buf->blocks = AV_DIV(buf->size, 512);
00326     }
00327     buf->nlink = 1;
00328 
00329     return 0;
00330 }
00331 
00332 static int state_access(ventry *ve, int amode)
00333 {
00334     struct stentry *stent = state_ventry_stentry(ve);
00335     struct namespace *ns = state_ventry_namespace(ve);
00336     struct entry *subdir;
00337     struct statefile *stf;
00338 
00339     subdir = av_namespace_subdir(ns, stent->ent);
00340     if(stent->ent != NULL)
00341         stf = (struct statefile *) av_namespace_get(stent->ent);
00342     else
00343         stf = NULL;
00344     
00345     if(subdir == NULL && stf == NULL)
00346         return -ENOENT;
00347 
00348     if((amode & AVW_OK) != 0 && stf != NULL && stf->set == NULL)
00349         return -EACCES;
00350 
00351     av_unref_obj(subdir);
00352 
00353     return 0;
00354 }
00355 
00356 static void state_free_tree(struct namespace *ns, struct entry *ent)
00357 {
00358     struct entry *next;
00359     void *data;
00360 
00361     ent = av_namespace_subdir(ns, ent);
00362     while(ent != NULL) {
00363         state_free_tree(ns, ent);
00364         data = av_namespace_get(ent);
00365         if(data != NULL) {
00366             av_free(data);
00367             av_unref_obj(ent);
00368         }
00369         next = av_namespace_next(ent);
00370         av_unref_obj(ent);
00371         ent = next;
00372     }
00373 }
00374 
00375 
00376 static void state_destroy(struct avfs *avfs)
00377 {
00378     struct namespace *ns = (struct namespace *) avfs->data;
00379 
00380     state_free_tree(ns, NULL);
00381 
00382     av_unref_obj(ns);
00383 }
00384 
00385 int av_state_new(struct vmodule *module, const char *name,
00386                    struct namespace **resp, struct avfs **avfsp)
00387 {
00388     int res;
00389     struct avfs *avfs;
00390     struct namespace *ns;
00391 
00392     res = av_new_avfs(name, NULL, AV_VER, AVF_ONLYROOT, module, &avfs);
00393     if(res < 0)
00394         return res;
00395 
00396     ns = av_namespace_new();
00397 
00398     av_ref_obj(ns);
00399     avfs->data = ns;
00400     avfs->destroy = state_destroy;
00401 
00402     avfs->lookup    = state_lookup;
00403     avfs->putent    = state_putent;
00404     avfs->copyent   = state_copyent;
00405     avfs->getpath   = state_getpath;
00406 
00407     avfs->open      = state_open;
00408     avfs->close     = state_close;
00409     avfs->read      = state_read;
00410     avfs->write     = state_write;
00411     avfs->truncate  = state_truncate;
00412     avfs->readdir   = state_readdir;
00413     avfs->getattr   = state_getattr;
00414     avfs->access    = state_access;
00415 
00416     av_add_avfs(avfs);
00417 
00418     *resp = ns;
00419     *avfsp = avfs;
00420     
00421     return 0;
00422 }