/* Usage transparent des r‚pertoires virtuels En utilisant les fonctions vdir_xxxx() plutot que les fonctions dir_xxxxx et file_xxxx du projet tool, on rend l'usage des makefile.dat pratiquement invisible. Ce module essai de retenir les 10 derniers FILEDIR pour activer le traitement. */ #include #include #include #include #include #include "ostool.h" #include "commun.h" #define NB_VDIR 10 typedef struct { FILEDIR fdir; /* Contenu du fichier makefile.dat */ char abspath[MAXSIZ_PATH]; unsigned usage; /* Permet d'‚liminer celui qui ne sert plus */ } VDIRS; static VDIRS tbdir[NB_VDIR]; static int nbdir=0; static volatile char *vdir_refpath=NULL; /* Enregistre le r‚pertoire pour complŠter les paths relatif du makefile.dat. */ export void vdir_setrelatif (const char *path) { free ((void*)vdir_refpath); vdir_refpath = strdup_err (path); } static void spawnvp (int, const char *, const char *argv[]) { char cmd[MAXSIZ_PATH]; cmd[0] = '\0'; for (int i=0; argv[i] != NULL; i++){ strcat (cmd," "); strcat (cmd,argv[i]); } system (cmd); } static void near vdir_getreel ( VFILE_SPEC *vf, char *pathreel) { if (pathreel != NULL){ strcpy (pathreel,vf->relpath); if (pathreel[0] == '$' && pathreel[1] == '('){ /* Il y a une macro au d‚but, on remplace. */ macrodir_repl (pathreel,pathreel); }else if (!path_isabs(pathreel) && vdir_refpath != NULL){ path_make ((const char *)vdir_refpath,pathreel,pathreel); } /* #Sp‚cification: vdir / localise / unzip AprŠs avoir localis‚ un fichier dans le makefile.dat on v‚rifie toujours si le fichier est pr‚sent sur disque. Si ce n'est le cas, on assume que le fichier est dans un fichier pack.zip du r‚pertoire ancˆtre. On commande silencieusement le unzip. Le stdout du unzip est redirige sur stderr pour eviter de confondre avec le stdout de la commande courante. */ if (!file_exist(pathreel)){ char zippath[MAXSIZ_PATH]; char fname[MAXSIZ_NAME]; path_splitlex (pathreel,zippath,fname); char sdir[MAXSIZ_NAME+MAXSIZ_NAME+1]; path_splitlex (zippath,zippath,sdir); SAVEPATH save; if (path_pushdir (zippath,&save)!=-1){ path_make(sdir,fname,sdir); const char *argv[4]; argv[0] = "unzip"; argv[1] = "pack"; argv[2] = sdir; argv[3] = NULL; // Redirige le canal stdout int protege = dup(1); if (protege != -1) dup2(2,1); spawnvp (0,argv[0],argv); if (protege != -1){ dup2(protege,1); close (protege); } path_popdir (&save); } } } } /* Initialise le FILEDIR pour un r‚pertoire. Consulte la table tbdir pour v‚rifier si le r‚pertoire n'y est pas d‚j…. Si ce n'est pas le cas, fait de la place dans la table et ajoute ce r‚pertoire. Retourne toujours une valeur ok. Attention, l'appelant ne doit pas conserver le r‚sultat trop longtemps puisque les FILEDIR font partie d'une table et que le moins utilis‚ cŠdera la place pour une nouvelle demande. */ FILEDIR *vdir_setup ( const char *path, int decomp, /* Doit d‚composer le path */ /* car il repr‚sente un ‚l‚ment du r‚pertoire */ /* … consulter plutot que le r‚pertoire lui-mˆme */ char *name) /* Recueillera le nom extrait du path */ /* Contiendra '\0' si decomp = 0 */ /* Peut etre NULL */ { VDIRS *selvdir=NULL; /* Contiendra l'entr‚e s‚lectionn‚ */ VDIRS *ptdir = tbdir; static unsigned alloc_usage = 0; int i; char abspath[MAXSIZ_PATH]; path_setabs (path,abspath); if (name != NULL) name[0] = '\0'; if (decomp) path_splitlex (abspath,abspath,name); for (i=0; iabspath,abspath)==0){ selvdir = ptdir; break; } } if (selvdir == NULL){ if (nbdir < NB_VDIR){ /* Il y a de la place … la fin de la table */ selvdir = tbdir + nbdir++; }else{ /* On doit libŠrer une entr‚e */ unsigned minusage = 65000u; ptdir = tbdir; /* On trouve l'entr‚e qui sert la moins souvent. */ for (i=0; iusage < minusage){ minusage = ptdir->usage; selvdir = ptdir; } } filedir_end (&selvdir->fdir); } { char datpath[MAXSIZ_PATH]; char delpath[MAXSIZ_PATH]; path_make (abspath,"makefile.del",delpath); path_make (abspath,"makefile.dat",datpath); strcpy (selvdir->abspath,abspath); if (file_type(abspath)!=1 && *path_skipabs(abspath) != '\0'){ /* Le r‚pertoire n'existe pas, il faut utiliser une combinaison de makefile.dat pour retrouver la v‚ritable location du makefile.dat s'il existe. */ FILEDIR *fdir; VFILE_SPEC *spec; char relpath[MAXSIZ_PATH]; selvdir->usage = alloc_usage; /* Usage r‚cursif, protŠge */ fdir = vdir_setup (abspath,1,relpath); strcat (relpath,"/makefile.dat"); spec = filedir_locate (fdir,relpath); if (spec != NULL){ vdir_getreel(spec,datpath); }else{ path_make (abspath,"makefile.dat",datpath); } } filedir_init (&selvdir->fdir,datpath,delpath); } } if (alloc_usage > 65000){ /* On remet tous les usage … 0. C'est pas trŠs juste, mais trŠs simple. Une fois … tous les 65000 accŠs, la performance va diminuer. La vrai solution serait de r‚allouer les usages tout en conservant l'ordre. C'est plus compliqu‚ et ‡a donne pas grand chose. */ ptdir = tbdir; for (i=0; iusage = 0; alloc_usage = 0; } selvdir->usage = ++alloc_usage; return &selvdir->fdir; } /* LibŠre m‚moire associ‚ au r‚pertoires virtuels. Appel‚ cette fonction ne changera pas le r‚sultat d'un programme mais pourra le ralentir. */ export void vdir_free (void) { int i; VDIRS *ptdir = tbdir; for (i=0; ifdir); } nbdir = 0; macrodir_free(); } /* D‚termine si un fichier existe et son path r‚el. Retourne != 0 si oui. ( Retourne 1 si fichier pr‚sent localement, 2 si fichier pr‚sent dans KITOMBRE ). */ export int vdir_exist ( const char *fname, char *pathreel) /* Peut ˆtre NULL */ { int ret = file_exist (fname); if (ret){ ret = 1; if (pathreel != NULL) strcpy (pathreel,fname); }else{ char name[MAXSIZ_NAME]; FILEDIR *fdir = vdir_setup (fname,1,name); VFILE_SPEC *vf = filedir_locate (fdir,name); if (vf != NULL){ ret = 2; vdir_getreel (vf,pathreel); } } return ret; } /* D‚termine le type d'un fichier */ export int vdir_ftype ( const char *fname, char *pathreel) /* Peut ˆtre NULL ou mˆme que fname */ { int ret = file_type (fname); if (ret != -1){ if (pathreel != NULL) strcpy (pathreel,fname); }else{ /* D‚termine si c'est un fichier dans le makefile.dat Les sous-r‚pertoires ne sont jamais virtualiser. Il sont toujours localement pr‚sent. */ char name[MAXSIZ_NAME]; FILEDIR *fdir = vdir_setup (fname,1,name); VFILE_SPEC *vf = filedir_locate (fdir,name); if (vf != NULL){ ret = 0; vdir_getreel (vf,pathreel); } } return ret; } /* Retrouve information de base sur un fichier. Retourne -1 si le fichier existe pas. */ export int vdir_infodos ( const char *fname, char *pathreel, /* Peut ˆtre NULL ou meme que fname */ unsigned long *date, /* Date format natif */ long *size) { int ret = file_infodos (fname,date,size); char reel[MAXSIZ_PATH]; if (pathreel == NULL) pathreel = reel; if (ret != -1){ if (pathreel != fname) strcpy (pathreel,fname); }else{ /* D‚termine si c'est un fichier dans le makefile.dat */ char name[MAXSIZ_NAME]; FILEDIR *fdir = vdir_setup (fname,1,name); VFILE_SPEC *vf = filedir_locate (fdir,name); if (vf != NULL){ vdir_getreel (vf,pathreel); ret = file_infodos (pathreel,date,size); *date = vf->date; } } return ret; } /* Retourne la date d'un fichier (r‚pertoire virtuel). Retourne 0 si le fichier existe pas. C'est sensiblement mˆme traitement que vdir_info sauf que c'est la date en format DOS qui est requise. Pour optimiser le code a ‚t‚ un peu duplicat‚. */ export unsigned long vdir_dosdate ( const char *fname, char *pathreel) /* Peut ˆtre NULL ou mˆme que fname */ { unsigned long date = file_dosdate (fname); char reel[MAXSIZ_PATH]; if (pathreel == NULL) pathreel = reel; if (date != 0){ if (pathreel != fname) strcpy (pathreel,fname); }else{ /* D‚termine si c'est un fichier dans le makefile.dat */ char name[MAXSIZ_NAME]; FILEDIR *fdir = vdir_setup (fname,1,name); VFILE_SPEC *vf = filedir_locate (fdir,name); if (vf != NULL){ vdir_getreel (vf,pathreel); date = vf->date; } } return date; } /* Retourne la dimension d'un fichier (r‚pertoire virtuel). Retourne -1 si le fichier existe pas. */ export long vdir_size( const char *fname, char *pathreel) /* Peut ˆtre NULL ou mˆme que fname */ { long size = -1; unsigned long date; if (vdir_infodos (fname,pathreel,&date,&size) == -1){ date = (unsigned long)-1; } return size; } #ifdef TEST int main (int argc, char *argv[]) { int i; for (i=1; i %s\n",arg,path); }else{ printf ("%s existe pas\n",arg); } printf ("ftype(%s) -> %d\n",arg,vdir_ftype(arg,NULL)); } return 0; } #endif