Back to index

avfs  1.0.1
parse.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 1998  Miklos Szeredi <miklos@szeredi.hu>
00004     Copyright (C) 2006  Ralf Hoffmann (ralf@boomerangsworld.de)
00005 
00006     This program can be distributed under the terms of the GNU GPL.
00007     See the file COPYING.
00008 
00009     Path parser module
00010 */
00011 
00012 #include "internal.h"
00013 #include "version.h"
00014 #include "local.h"
00015 #include "mod_static.h"
00016 #include "operutil.h"
00017 #include "oper.h"
00018 
00019 #include <stdio.h>
00020 #include <ctype.h>
00021 #include <string.h>
00022 #include <stdlib.h>
00023 #include <sys/stat.h>
00024 
00025 static AV_LOCK_DECL(initlock);
00026 static int inited;
00027 
00028 struct avfs_list {
00029     struct avfs *avfs;
00030     struct avfs_list *next;
00031     struct avfs_list *prev;
00032 };
00033 
00034 static AV_LOCK_DECL(avfs_lock);
00035 static struct avfs_list avfs_list;
00036 static int symlink_rewrite = 0;
00037 
00038 struct parse_state {
00039     ventry *ve;
00040     char *path;
00041     char *prevseg;
00042     int islink;
00043     int resolvelast;
00044     int nextseg;
00045     int linkctr;
00046     int first_seg;  /* true if no segment was analysed, see segment_len() comment */
00047 };
00048 
00049 static int copyrightstat_get(struct entry *ent, const char *param, char **retp)
00050 {
00051     char buf[256];
00052 
00053     sprintf(buf, 
00054             "AVFS Virtual File System (C) Miklos Szeredi 1998-2001, Version %i.%i.%i,\n"
00055             "AVFS comes with ABSOLUTELY NO WARRANTY.\n", 
00056             AV_VER / 100,
00057             (AV_VER / 10) % 10,
00058             AV_VER % 10);
00059     
00060     *retp = av_strdup(buf);
00061     
00062     return 0;
00063 }
00064 
00065 static int modstat_get(struct entry *ent, const char *param, char **retp)
00066 {
00067     char *ret = av_strdup("");
00068     char buf[128];
00069 
00070     struct avfs_list *li;
00071 
00072     AV_LOCK(avfs_lock);
00073     for(li = avfs_list.next; li != &avfs_list; li = li->next) {
00074         struct avfs *avfs = li->avfs;
00075         struct ext_info *exts;
00076         int ei;
00077         int ver = avfs->version;
00078 
00079        sprintf(buf, "%2d.%d.%d\t", (ver / 100) % 100, (ver / 10) % 10,
00080                 ver % 10);
00081 
00082         ret = av_stradd(ret, buf, avfs->name, ":\t", NULL);
00083 
00084        exts = avfs->exts;
00085        if(exts != NULL) 
00086            for(ei = 0; exts[ei].from != NULL; ei++) {
00087                 ret = av_stradd(ret, exts[ei].from, NULL);
00088               if(exts[ei].to != NULL)
00089                     ret = av_stradd(ret, "(", exts[ei].to, ")", NULL);
00090                 
00091                 ret = av_stradd(ret, " ", NULL);
00092            }
00093 
00094         ret = av_stradd(ret, "\n", NULL);
00095     }
00096     AV_UNLOCK(avfs_lock);
00097 
00098     *retp = ret;
00099 
00100     return 0;
00101 }
00102 
00103 static int versionstat_get(struct entry *ent, const char *param, char **retp)
00104 {
00105     char buf[128];
00106     char *compiledate;
00107     char *compilesys;
00108     char *moduledir;
00109 
00110     sprintf(buf, "%i.%i.%i", AV_VER / 100, (AV_VER / 10) % 10, AV_VER % 10);
00111 
00112     compiledate = av_get_config("compiledate");
00113     compilesys = av_get_config("compilesystem");
00114     moduledir = av_get_config("moduledir");
00115 
00116     *retp = av_stradd(NULL, "Interface version: ", buf, 
00117                         "\nCompile date: ", compiledate,
00118                         "\nCompile system: ", compilesys,
00119                         "\nModule directory: ", moduledir, "\n", NULL);
00120 
00121     av_free(compiledate);
00122     av_free(compilesys);
00123     av_free(moduledir);
00124 
00125     return 0;
00126 }
00127 
00128 static int symlinkrewrite_get(struct entry *ent, const char *param, char **retp)
00129 {
00130     char buf[32];
00131     
00132     AV_LOCK(avfs_lock);
00133     sprintf(buf, "%d\n", symlink_rewrite);
00134     AV_UNLOCK(avfs_lock);
00135 
00136     *retp = av_strdup(buf);
00137     return 0;
00138 }
00139 
00140 static int symlinkrewrite_set(struct entry *ent, const char *param, const char *val)
00141 {
00142     int mode;
00143 
00144     if(strlen(val) < 2)
00145         return -EINVAL;
00146 
00147     if(val[1] != '\n' && val[1] != ' ') 
00148         return -EINVAL;
00149 
00150     if(val[0] == '0')
00151         mode = 0;
00152     else if(val[0] == '1')
00153         mode = 1;
00154     else
00155         return -EINVAL;
00156     
00157     AV_LOCK(avfs_lock);
00158     symlink_rewrite = mode;
00159     AV_UNLOCK(avfs_lock);
00160 
00161     return 0;
00162 }
00163 
00164 static void init_stats()
00165 {
00166     struct statefile statf;
00167     
00168     statf.data = NULL;
00169     statf.set = NULL;
00170 
00171     statf.get = copyrightstat_get;
00172     av_avfsstat_register("copyright", &statf);
00173     
00174     statf.get = modstat_get;
00175     av_avfsstat_register("modules", &statf);
00176 
00177     statf.get = versionstat_get;
00178     av_avfsstat_register("version", &statf);
00179 
00180     statf.get = symlinkrewrite_get;
00181     statf.set = symlinkrewrite_set;
00182     av_avfsstat_register("symlink_rewrite", &statf);
00183 }
00184 
00185 static void destroy()
00186 {
00187     av_log(AVLOG_DEBUG, "DESTROY");
00188 
00189     AV_LOCK(initlock);
00190     if(inited) {
00191         av_close_all_files();
00192 
00193         AV_LOCK(avfs_lock);
00194         while(avfs_list.next != &avfs_list) {
00195             struct avfs_list *li = avfs_list.next;
00196 
00197             li->next->prev = li->prev;
00198             li->prev->next = li->next;
00199             av_unref_obj(li->avfs);
00200             av_free(li);
00201         }
00202         AV_UNLOCK(avfs_lock);
00203 
00204         av_do_exit();
00205        av_delete_tmpdir();
00206 
00207         inited = 0;
00208     }
00209     AV_UNLOCK(initlock);
00210 
00211     av_check_malloc();
00212     av_log(AVLOG_DEBUG, "DESTROY successful");
00213 }
00214 
00215 static int init()
00216 {
00217     int res = 0;
00218 
00219     AV_LOCK(initlock);    
00220     if(!inited) {
00221         av_log(AVLOG_DEBUG, "INIT");
00222 
00223         avfs_list.next = &avfs_list;
00224         avfs_list.prev = &avfs_list;
00225 
00226         res = av_init_module_local();
00227         if(res == 0) {
00228             av_init_avfsstat();
00229             av_init_static_modules();
00230             av_init_dynamic_modules();
00231             av_init_logstat();
00232             init_stats();
00233             av_init_cache();
00234             av_init_filecache();
00235             atexit(destroy);
00236             inited = 1;
00237             av_log(AVLOG_DEBUG, "INIT successful");
00238         }
00239         else
00240             av_log(AVLOG_DEBUG, "INIT failed");
00241     }
00242     AV_UNLOCK(initlock);
00243 
00244     return res;
00245 }
00246 
00247 void av_add_avfs(struct avfs *newavfs)
00248 {
00249     struct avfs_list *li;
00250 
00251     AV_NEW(li);
00252     AV_LOCK(avfs_lock);
00253     li->avfs = newavfs;
00254     li->next = &avfs_list;
00255     li->prev = avfs_list.prev;
00256     avfs_list.prev = li;
00257     li->prev->next = li;
00258     AV_UNLOCK(avfs_lock);
00259 }
00260 
00261 static int av_copy_parsestate(struct parse_state *ps, struct parse_state *destps)
00262 {
00263     destps->linkctr = ps->linkctr;
00264     destps->nextseg = ps->nextseg;
00265     destps->resolvelast = ps->resolvelast;
00266     destps->islink = ps->islink;
00267 
00268     if(ps->path)
00269       destps->path = av_strdup(ps->path);
00270     else
00271       destps->path = NULL;
00272 
00273     destps->first_seg = ps->first_seg;
00274 
00275     if(ps->prevseg)
00276       destps->prevseg = av_strdup(ps->prevseg);
00277     else
00278       destps->prevseg = NULL;
00279 
00280     av_copy_ventry(ps->ve, &(destps->ve));
00281     return 0;
00282 }
00283 
00284 static void set_prevseg(struct parse_state *ps, const char *name)
00285 {
00286     av_free(ps->prevseg);
00287     ps->prevseg = av_strdup(name);
00288 }
00289 
00290 static int lookup_virtual(struct parse_state *ps, const char *name)
00291 {
00292     int res;
00293     ventry *ve = ps->ve;
00294     struct avfs *avfs = ve->mnt->avfs;
00295     void *newdata;
00296 
00297     AVFS_LOCK(avfs);
00298     res = avfs->lookup(ve, name, &newdata);
00299     AVFS_UNLOCK(avfs);
00300     if(res < 0)
00301         return res;
00302     
00303     ve->data = newdata;
00304     if(ve->data != NULL) {
00305         if(res == (AV_IFLNK >> 12))
00306             ps->islink = 1;
00307 
00308         res = 0;
00309     }
00310     else {
00311         ps->ve = ve->mnt->base;
00312         ve->mnt->base = NULL;
00313         av_free_ventry(ve);
00314 
00315         res = lookup_virtual(ps, NULL);
00316     }
00317 
00318     return res;
00319 }
00320 
00321 static struct avmount *new_mount(ventry *base, struct avfs *avfs,
00322                              const char *opts)
00323 {
00324     struct avmount *mnt;
00325 
00326     AV_NEW(mnt);
00327 
00328     mnt->base = base;
00329     mnt->avfs = avfs;
00330     mnt->opts = av_strdup(opts);
00331     mnt->flags = 0;
00332 
00333     return mnt;
00334 }
00335 
00336 static int is_root(ventry *ve)
00337 {
00338     char *path;
00339     struct stat pathstat;
00340     struct stat rootstat;
00341     int res;
00342 
00343     if(ve->mnt->base != NULL)
00344        return 0;
00345 
00346     for(path = (char *) ve->data; *path == AV_DIR_SEP_CHAR; path++);
00347     if(!*path)
00348        return 1;
00349 
00350     res = stat((char *) ve->data, &pathstat);
00351     if(res == -1)
00352        return 0;
00353 
00354     res = stat("/", &rootstat);
00355     if(res == -1)
00356        return 0;
00357     
00358     if(rootstat.st_dev == pathstat.st_dev &&
00359        rootstat.st_ino == pathstat.st_ino)
00360        return 1;
00361 
00362     return 0;
00363 }
00364 
00365 static int enter_mount(struct parse_state *ps, struct avfs *avfs,
00366                        const char *opts, const char *param)
00367 {
00368     int res;
00369     ventry *newve;
00370     
00371     AV_NEW(newve);
00372 
00373     newve->mnt = new_mount(ps->ve, avfs, opts);
00374     newve->data = NULL;
00375 
00376     ps->ve = newve;
00377 
00378     if((avfs->flags & AVF_ONLYROOT) != 0 && !is_root(ps->ve->mnt->base))
00379         return -ENOENT;
00380 
00381     res = lookup_virtual(ps, param);
00382 
00383     return res;
00384 }
00385 
00386 static struct ext_info *find_ext(struct ext_info *exts, const char *prevseg)
00387 {
00388     int ei;
00389     unsigned int prevseglen = strlen(prevseg);
00390 
00391     for(ei = 0; exts[ei].from != NULL; ei++) {
00392         unsigned int extlen = strlen(exts[ei].from);
00393         if(prevseglen >= extlen) {
00394             const char *prevsegext = prevseg + prevseglen - extlen;
00395             if(strncasecmp(prevsegext, exts[ei].from, extlen) == 0)
00396                 return &exts[ei];
00397         }
00398     }
00399     return NULL;
00400 }
00401 
00402 static struct avfs *find_auto_avfs(const char *prevseg, struct ext_info **extp)
00403 {
00404     struct ext_info *exts;
00405     struct avfs_list *li;
00406 
00407     for(li = avfs_list.next; li != &avfs_list; li = li->next) {
00408         exts = li->avfs->exts;
00409         if(exts != NULL) {
00410             struct ext_info *e;
00411             e = find_ext(exts, prevseg);
00412             if(e != NULL) {
00413                 *extp = e;
00414                 return li->avfs;
00415             }
00416         }
00417     }
00418 
00419     return NULL;
00420 }
00421 
00422 static void get_new_name(struct parse_state *ps, struct ext_info *ext)
00423 {
00424     unsigned int extlen = strlen(ext->from);
00425     unsigned int prevseglen = strlen(ps->prevseg);
00426         
00427     ps->prevseg[prevseglen - extlen] = '\0';
00428     if(ext->to != NULL) 
00429         ps->prevseg = av_stradd(ps->prevseg, ext->to, NULL);
00430 }
00431 
00432 
00433 static int lookup_auto_avfs(struct parse_state *ps, const char *opts,
00434                             const char *param)
00435 {
00436     int res;
00437     struct avfs *avfs;
00438     struct ext_info *ext = NULL;
00439 
00440     AV_LOCK(avfs_lock);
00441     avfs = find_auto_avfs(ps->prevseg, &ext);
00442     if(avfs == NULL)
00443         res = -ENOENT;
00444     else {
00445         av_ref_obj(avfs);
00446 
00447         get_new_name(ps, ext);
00448         if(find_auto_avfs(ps->prevseg, &ext) == NULL)
00449             set_prevseg(ps, "");
00450         else {
00451             param = "";
00452             ps->nextseg = 0;
00453         }
00454         res = 0;
00455     }
00456     AV_UNLOCK(avfs_lock);
00457 
00458     if(res == 0) {
00459         res = enter_mount(ps, avfs, opts, param);
00460         if(res == 0)
00461             ps->ve->mnt->flags = 1;
00462     }
00463 
00464     return res;
00465 }
00466 
00467 static int is_handler_char(int ch)
00468 {
00469     return isalpha(ch) || isdigit(ch) || ch == '_';
00470 }
00471 
00472 static struct avfs *find_avfs_name(char *name)
00473 {
00474     struct avfs_list *li;
00475 
00476     if(!*name)
00477        return NULL;
00478 
00479     AV_LOCK(avfs_lock);
00480     for(li = avfs_list.next; li != &avfs_list; li = li->next)
00481        if(li->avfs->name != NULL && 
00482           strcmp(li->avfs->name, name) == 0) {
00483             av_ref_obj(li->avfs);
00484             break;
00485         }
00486     AV_UNLOCK(avfs_lock);
00487     
00488     return li->avfs;
00489 }
00490 
00491 static int is_special(const char *name)
00492 {
00493     if(name[0] == '.' &&
00494        (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
00495        return 1;
00496 
00497     return 0;
00498 }
00499 
00500 static int lookup_avfs(struct parse_state *ps, char *name)
00501 {
00502     int res;
00503     char c;
00504     char *s;
00505     char *opts;
00506     const char *param;
00507     struct avfs *avfs;
00508 
00509     if(is_special(ps->prevseg))
00510         return -ENOENT;
00511 
00512     for(s = name; *s && is_handler_char(*s); s++);
00513     opts = s;
00514     for(; *s && *s != ':'; s++);
00515     c = *s;
00516     if(*s == ':') {
00517         *s = '\0';
00518         param = s + 1;
00519         if(*param == '\0' || *param == AV_DIR_SEP_CHAR)
00520             return -ENOENT;
00521     }
00522     else
00523         param = "";
00524 
00525     if(name == opts) {
00526         res = lookup_auto_avfs(ps, opts, param);
00527         *s = c;
00528         return res;
00529     }
00530 
00531     c = *opts;
00532     *s = '\0';
00533     avfs = find_avfs_name(name);
00534     *opts = c;
00535 
00536     if(avfs == NULL)
00537         return -ENOENT;
00538     
00539     res = enter_mount(ps, avfs, opts, param);
00540     set_prevseg(ps, "");
00541 
00542     return res;
00543 }
00544 
00545 static int lookup_segment(struct parse_state *ps, int noavfs)
00546 {
00547     int res;
00548     char *name = ps->path;
00549     ventry *ve = ps->ve;
00550 
00551     /* only enter next avfs hierarchie if the magic char is not the
00552        very first char (first_seg) and we really want this action
00553        (noavfs needed by segment_islocal() test */
00554 
00555     if((name[0] == AVFS_SEP_CHAR) && (noavfs == 0) && (ps->first_seg == 0))
00556       res = lookup_avfs(ps, name+1);
00557     else {
00558         /* reset first_seg as we now process a path segment and from now on 
00559           the next magic char is always the magic char and not from a local
00560           filename */
00561         ps->first_seg = 0;
00562 
00563         for(;*name && *name == AV_DIR_SEP_CHAR; name++);
00564         set_prevseg(ps, name);
00565 
00566        if((ve->mnt->avfs->flags & AVF_NEEDSLASH) != 0)
00567           name = ps->path;
00568         
00569         if(name[0] != '\0')
00570             res = lookup_virtual(ps, name);
00571         else
00572             res = 0;
00573     }
00574         
00575     return res;
00576 }
00577 
00578 static int segment_islocal(struct parse_state *ps, unsigned int seglen )
00579 {
00580     int islocal = 0;
00581     char c;
00582     struct parse_state tempps;
00583     int f;
00584 
00585     /* we will copy the whole parse_state and try to find a local entry
00586        if open succeed there is a local file and we can return true */
00587 
00588     av_copy_parsestate( ps, &tempps );
00589     
00590     tempps.nextseg = seglen;
00591     c = tempps.path[seglen];
00592     tempps.path[seglen] = '\0';
00593     
00594     /* we force lookup_segment() to not enter any avfs hierarchie */
00595     lookup_segment(&tempps, 1);
00596     f = av_fd_open_entry(tempps.ve, AVO_RDONLY, 0);
00597     av_free_ventry(tempps.ve);
00598     av_free(tempps.path);
00599     av_free(tempps.prevseg);
00600     if ( f >= 0 ) {
00601       islocal = 1;
00602       av_fd_close(f);
00603     }
00604     return islocal;
00605 }
00606 
00607 static unsigned int segment_len(struct parse_state *ps, int ignoreMagic)
00608 {
00609     const char *s = ps->path,
00610                *first_s = ps->path;
00611     unsigned int seglen, orig_seglen;
00612     int found_magic = 0, search_avfs_key = 0;
00613 
00614     /* this function will find the next segment len by also checking for local files
00615        with magic chars inside the filename
00616        two cases:
00617        1.magic at the beginning:
00618          in this case we are searching for an avfs key (#utar, #ugz...)
00619         so we will stop at the next magic char or dir separator
00620         except when this magic char is the very first character
00621         where it makes no sense to accept this as an avfs key
00622         (imagine open("#utar"))
00623         For this case there is a new flag first_seg which takes
00624         care of this
00625        2.Otherwise we are searching for the longest path segment
00626          starting at the next dir separator skipping any magic char
00627         we stop after first local hit
00628         If no local file was found we return whole segment len to be able
00629         to open new files with magic chars
00630        If no magic char was found or we are forced to ignore it
00631        we immediately return the whole path segment without any checking
00632     */
00633 
00634     if(s[0] == AVFS_SEP_CHAR) {
00635         s++;
00636        if(ps->first_seg == 0)
00637             search_avfs_key = 1;
00638     } else while(*s == AV_DIR_SEP_CHAR)
00639         s++;
00640     
00641     while(*s && *s != AV_DIR_SEP_CHAR) {
00642         if(*s == AVFS_SEP_CHAR) {
00643             if(found_magic == 0) {
00644                first_s = s;
00645            }
00646            found_magic++;
00647         }
00648         s++;
00649     }
00650     seglen = s - ps->path;
00651 
00652     if((ignoreMagic == 1) || (found_magic == 0)) return seglen;
00653 
00654     /* a magic char was already found so first_s is correct */
00655     if(search_avfs_key == 1)
00656         return (first_s - ps->path);
00657 
00658     orig_seglen = seglen;
00659     /* found magic char so check for existing local file */
00660     while(seglen > 0) {
00661         if(segment_islocal(ps, seglen) == 1)
00662            break;
00663         for(seglen = seglen - 1;
00664             (seglen > 0) && ( ps->path[seglen] != AVFS_SEP_CHAR );
00665             seglen--);
00666     }
00667 
00668     if(seglen > 0) return seglen;
00669     else return orig_seglen;
00670 }
00671 
00672 static int is_last(struct parse_state *ps, unsigned int seglen)
00673 {
00674     const char *s;
00675 
00676     for(s = ps->path + seglen; *s && *s == AV_DIR_SEP_CHAR; s++);
00677     if(!*s)
00678         return 1;
00679     else
00680         return 0;
00681 }
00682 
00683 static struct avfs *get_local_avfs()
00684 {
00685     struct avfs *localavfs;
00686 
00687     AV_LOCK(avfs_lock);
00688     localavfs = avfs_list.next->avfs;
00689     av_ref_obj(localavfs);
00690     AV_UNLOCK(avfs_lock);
00691 
00692     return localavfs;
00693 }
00694 
00695 static int parse_path(struct parse_state *ps, int force_localfile);
00696 
00697 static int follow_link(struct parse_state *ps)
00698 {
00699     int res;
00700     struct parse_state linkps;
00701     char *buf;
00702 
00703     if(!ps->linkctr)
00704         return -ELOOP;
00705 
00706     res = av_readlink(ps->ve, &buf);
00707     if(res < 0)
00708         return res;
00709 
00710     linkps.path = buf;
00711     linkps.resolvelast = 1;
00712     linkps.linkctr = ps->linkctr - 1;
00713 
00714     if(buf[0] != AV_DIR_SEP_CHAR) {
00715         linkps.ve = ps->ve;
00716         
00717         res = lookup_virtual(&linkps, NULL);
00718         if(res == 0)
00719             res = parse_path(&linkps, 0);
00720     }
00721     else {
00722         av_free_ventry(ps->ve);
00723 
00724         AV_NEW(linkps.ve);
00725         linkps.ve->mnt = new_mount(NULL, get_local_avfs(), NULL);
00726         linkps.ve->data = av_strdup("");
00727 
00728         res = parse_path(&linkps, 0);
00729     }
00730 
00731     
00732     av_free(buf);
00733     ps->ve = linkps.ve;
00734     
00735     return res;
00736 }
00737 
00738 static int parse_path(struct parse_state *ps, int force_localfile)
00739 {
00740     int res = 0;
00741     int numseg = 0;
00742 
00743     ps->prevseg = av_strdup("");
00744     ps->first_seg = 1;
00745     while(ps->path[0]) {
00746         unsigned int seglen;
00747         int lastseg;
00748         char c;
00749 
00750        seglen = segment_len(ps, force_localfile);
00751        
00752         lastseg = is_last(ps, seglen);
00753         ps->nextseg = seglen;
00754         c = ps->path[seglen];
00755         ps->path[seglen] = '\0';
00756         ps->islink = 0;
00757         
00758         res = lookup_segment(ps,0);
00759         if(res < 0)
00760             break;
00761         
00762         if(ps->islink && (ps->resolvelast || !lastseg)) {
00763             res = follow_link(ps);
00764             if(res < 0) 
00765                 break;
00766         }
00767         ps->path[seglen] = c;
00768         ps->path += ps->nextseg;
00769         numseg ++;
00770         
00771         if(numseg > 1000) {
00772             av_log(AVLOG_ERROR, "Infinate loop in parse_path");
00773             res = -EFAULT;
00774             break;
00775         }
00776     }
00777 
00778     av_free(ps->prevseg);
00779 
00780     return res;
00781 }
00782 
00783 int av_get_ventry(const char *path, int resolvelast, ventry **resp)
00784 {
00785     int res;
00786     struct parse_state ps;
00787     char *copypath;
00788 
00789     res = init();
00790     if(res < 0)
00791         return res;
00792 
00793     if(path == NULL)
00794         return -ENOENT;
00795 
00796     copypath = av_strdup(path);
00797     ps.path = copypath;
00798     ps.resolvelast = resolvelast;
00799     ps.linkctr = 10;
00800 
00801     AV_NEW(ps.ve);
00802     ps.ve->mnt = new_mount(NULL, get_local_avfs(), NULL);
00803     ps.ve->data = av_strdup("");
00804 
00805     res = parse_path(&ps, 0);
00806 
00807     /* no ventry so force localfile to be able to create files with
00808        the magic character inside filename */
00809     if(res < 0) {
00810         av_free(copypath);
00811         copypath = av_strdup(path);
00812         av_free_ventry(ps.ve);
00813         ps.path = copypath;
00814         ps.resolvelast = resolvelast;
00815         ps.linkctr = 10;
00816         AV_NEW(ps.ve);
00817         ps.ve->mnt = new_mount(NULL, get_local_avfs(), NULL);
00818         ps.ve->data = av_strdup("");
00819         res = parse_path(&ps, 1);
00820     }
00821 
00822     if(res < 0) {
00823         av_free_ventry(ps.ve);
00824         *resp = NULL;
00825     }
00826     else
00827         *resp = ps.ve;
00828 
00829     av_free(copypath);
00830 
00831     return res;
00832 }
00833 
00834 int av_copy_vmount(struct avmount *mnt, struct avmount **resp)
00835 {
00836     int res;
00837     ventry *newbase;
00838     
00839     if(mnt->base != NULL) {
00840         res = av_copy_ventry(mnt->base, &newbase);
00841         if(res < 0)
00842             return res;
00843     }
00844     else
00845         newbase = NULL;
00846 
00847     av_ref_obj(mnt->avfs);
00848 
00849     *resp = new_mount(newbase, mnt->avfs, mnt->opts);
00850     
00851     return 0;
00852 }
00853 
00854 int av_copy_ventry(ventry *ve, ventry **resp)
00855 {
00856     int res;
00857     ventry *newve;
00858     struct avmount *newmnt;
00859     void *newdata;
00860     struct avfs *avfs = ve->mnt->avfs;
00861 
00862     res = av_copy_vmount(ve->mnt, &newmnt);
00863     if(res < 0)
00864        return res;
00865 
00866     if(ve->data != NULL) {
00867         AVFS_LOCK(avfs);
00868         res = avfs->copyent(ve, &newdata);
00869         AVFS_UNLOCK(avfs);
00870         if(res < 0)
00871             return res;
00872     }
00873     else
00874        newdata = NULL;
00875     
00876     AV_NEW(newve);
00877     
00878     newve->data = newdata;
00879     newve->mnt = newmnt;
00880 
00881     *resp = newve;
00882 
00883     return 0;
00884 }
00885 
00886 void av_free_vmount(struct avmount *mnt)
00887 {
00888     av_unref_obj(mnt->avfs);
00889 
00890     av_free(mnt->opts);
00891     av_free_ventry(mnt->base);
00892     av_free(mnt);
00893 }
00894 
00895 void av_free_ventry(ventry *ve)
00896 {
00897     if(ve != NULL) {
00898        struct avfs *avfs = ve->mnt->avfs;
00899 
00900         if(ve->data != NULL) {
00901             AVFS_LOCK(avfs);
00902             avfs->putent(ve);
00903             AVFS_UNLOCK(avfs);
00904         }
00905 
00906         av_free_vmount(ve->mnt);
00907         av_free(ve);
00908     }
00909 }
00910 
00911 
00912 static int ipath_len(const char *s)
00913 {
00914     int cnt;
00915 
00916     for(cnt = 0; *s; s++, cnt++);
00917 
00918     return cnt;
00919 }
00920 
00921 static void ipath_copy(char *dst, const char *src)
00922 {
00923     for(; *src; dst++, src++) {
00924         *dst = *src;
00925     }
00926     *dst = '\0';
00927 }
00928 
00929 static char *expand_segment(char *segment)
00930 {
00931     char *tmp;
00932 
00933     tmp = (char *) av_malloc(ipath_len(segment) + 1);
00934     ipath_copy(tmp, segment);
00935     av_free(segment);
00936 
00937     return tmp;
00938 }
00939 
00940 static int add_segment(ventry *ve, char **pathp)
00941 {
00942     int res;
00943     char *segment;
00944     struct avfs *avfs = ve->mnt->avfs;
00945 
00946     if(ve->data != NULL) {
00947         AVFS_LOCK(avfs);
00948         res = avfs->getpath(ve, &segment);
00949         AVFS_UNLOCK(avfs);
00950         if(res < 0)
00951             return res;
00952     }
00953     else 
00954         segment = av_strdup("");
00955 
00956     if(ve->mnt->base == NULL)
00957        *pathp = av_stradd(*pathp, segment, NULL);
00958     else {
00959        char *avfsname = avfs->name;
00960        char *opts = ve->mnt->opts;
00961        char avfssep[] = { AVFS_SEP_CHAR, '\0' };
00962         const char *paramsep;
00963         
00964         if(segment[0] && segment[0] != AV_DIR_SEP_CHAR)
00965             paramsep = ":";
00966         else
00967             paramsep = "";
00968        
00969         segment = expand_segment(segment);
00970        
00971        *pathp = av_stradd(*pathp, avfssep, avfsname, opts, paramsep,
00972                              segment, NULL);
00973     }
00974     av_free(segment);
00975 
00976     return 0;
00977 }
00978 
00979 int av_generate_path(ventry *ve, char **pathp)
00980 {
00981     int res;
00982 
00983     if(ve == NULL) 
00984         *pathp = NULL;
00985     else {
00986         res = av_generate_path(ve->mnt->base, pathp);
00987         if(res < 0)
00988             return res;
00989 
00990         res = add_segment(ve, pathp);
00991         if(res < 0) {
00992             av_free(*pathp);
00993             return res;
00994         }
00995     }
00996 
00997     return 0;
00998 }
00999 
01000 int av_get_symlink_rewrite()
01001 {
01002     return symlink_rewrite;
01003 }