mainloop.c

Go to the documentation of this file.
00001 /*
00002  * mainloop.c
00003  * Iterating over all the command line parameters, and matching patterns
00004  * where needed
00005  */
00006 
00007 #include "sysincludes.h"
00008 #include "msdos.h"
00009 #include "mtools.h"
00010 #include "vfat.h"
00011 #include "fs.h"
00012 #include "mainloop.h"
00013 #include "plain_io.h"
00014 #include "file.h"
00015 
00016 
00017 int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); 
00018 int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, 
00019               int follow_dir_link);
00020 
00021 static int _unix_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
00022 {
00023         unix_dir_loop(Dir, mp);
00024         return GOT_ONE;
00025 }
00026 
00027 int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link)
00028 {
00029         int ret;
00030         int isdir;
00031 
00032         mp->File = NULL;
00033         mp->direntry = NULL;
00034         mp->unixSourceName = arg;
00035         /*      mp->dir.attr = ATTR_ARCHIVE;*/
00036         mp->loop = _unix_loop;
00037         if((mp->lookupflags & DO_OPEN)){
00038                 mp->File = SimpleFileOpen(0, 0, arg, O_RDONLY, 0, 0, 0, 0);
00039                 if(!mp->File){
00040                         perror(arg);
00041 #if 0
00042                         tmp = _basename(arg);
00043                         strncpy(mp->filename, tmp, VBUFSIZE);
00044                         mp->filename[VBUFSIZE-1] = '\0';
00045 #endif
00046                         return ERROR_ONE;
00047                 }
00048                 GET_DATA(mp->File, 0, 0, &isdir, 0);
00049                 if(isdir) {
00050                         struct stat buf;
00051 
00052                         FREE(&mp->File);
00053 #ifdef S_ISLNK
00054                         if(!follow_dir_link &&
00055                            lstat(arg, &buf) == 0 &&
00056                            S_ISLNK(buf.st_mode)) {
00057                                 /* skip links to directories in order to avoid
00058                                  * infinite loops */
00059                                 fprintf(stderr, 
00060                                         "skipping directory symlink %s\n", 
00061                                         arg);
00062                                 return 0;                               
00063                         }
00064 #endif
00065                         if(! (mp->lookupflags & ACCEPT_DIR))
00066                                 return 0;
00067                         mp->File = OpenDir(Stream, arg);
00068                 }
00069         }
00070 
00071         if(isdir)
00072                 ret = mp->dirCallback(0, mp);
00073         else
00074                 ret = mp->unixcallback(mp);
00075         FREE(&mp->File);
00076         return ret;
00077 }
00078 
00079 
00080 int isSpecial(const char *name)
00081 {
00082         if(name[0] == '\0')
00083                 return 1;
00084         if(!strcmp(name,"."))
00085                 return 1;
00086         if(!strcmp(name,".."))
00087                 return 1;
00088         return 0;                       
00089 }
00090 
00091 
00092 static int checkForDot(int lookupflags, const char *name)
00093 {
00094         return (lookupflags & NO_DOTS) && isSpecial(name);
00095 }
00096 
00097 
00098 typedef struct lookupState_t {
00099         Stream_t *container;
00100         int nbContainers;
00101         Stream_t *Dir;
00102         int nbDirs;
00103         const char *filename;
00104 } lookupState_t;
00105 
00106 static int isUniqueTarget(const char *name)
00107 {
00108         return name && strcmp(name, "-");
00109 }
00110 
00111 static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
00112                        lookupState_t *lookupState)
00113 {
00114         Stream_t *MyFile=0;
00115         int ret;
00116 
00117         if(got_signal)
00118                 return ERROR_ONE;
00119         if(lookupState) {
00120                 /* we are looking for a "target" file */
00121                 switch(lookupState->nbDirs) {
00122                         case 0: /* no directory yet, open it */
00123                                 lookupState->Dir = OpenFileByDirentry(direntry);
00124                                 lookupState->nbDirs++;
00125                                 /* dump the container, we have
00126                                  * better now */
00127                                 FREE(&lookupState->container);
00128                                 return 0;
00129                         case 1: /* we have already a directory */
00130                                 FREE(&lookupState->Dir);
00131                                 fprintf(stderr,"Ambigous\n");
00132                                 return STOP_NOW | ERROR_ONE;
00133                         default:
00134                                 return STOP_NOW | ERROR_ONE;
00135                 }
00136         }
00137 
00138         mp->direntry = direntry;
00139         if(IS_DIR(direntry)) {
00140                 if(mp->lookupflags & (DO_OPEN | DO_OPEN_DIRS))
00141                         MyFile = mp->File = OpenFileByDirentry(direntry);
00142                 ret = mp->dirCallback(direntry, mp);
00143         } else {
00144                 if(mp->lookupflags & DO_OPEN)
00145                         MyFile = mp->File = OpenFileByDirentry(direntry);
00146                 ret = mp->callback(direntry, mp);
00147         }
00148         FREE(&MyFile);
00149         if(isUniqueTarget(mp->targetName))
00150                 ret |= STOP_NOW;
00151         return ret;
00152 }
00153 
00154 static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
00155 {       
00156         Stream_t *MyFile=0;
00157         direntry_t entry;
00158         int ret;
00159         int r;
00160         
00161         ret = 0;
00162         r=0;
00163         initializeDirentry(&entry, Dir);
00164         while(!got_signal &&
00165               (r=vfat_lookup(&entry, filename, -1,
00166                              mp->lookupflags, mp->shortname, 
00167                              mp->longname)) == 0 ){
00168                 mp->File = NULL;
00169                 if(!checkForDot(mp->lookupflags,entry.name)) {
00170                         MyFile = 0;
00171                         if((mp->lookupflags & DO_OPEN) ||
00172                            (IS_DIR(&entry) && 
00173                             (mp->lookupflags & DO_OPEN_DIRS))) {
00174                                 MyFile = mp->File = OpenFileByDirentry(&entry);
00175                         }
00176                         if(got_signal)
00177                                 break;
00178                         mp->direntry = &entry;
00179                         if(IS_DIR(&entry))
00180                                 ret |= mp->dirCallback(&entry,mp);
00181                         else
00182                                 ret |= mp->callback(&entry, mp);
00183                         FREE(&MyFile);
00184                 }
00185                 if (fat_error(Dir))
00186                         ret |= ERROR_ONE;
00187                 if(mp->fast_quit && (ret & ERROR_ONE))
00188                         break;
00189         }
00190         if (r == -2)
00191             return ERROR_ONE;
00192         if(got_signal)
00193                 ret |= ERROR_ONE;
00194         return ret;
00195 }
00196 
00197 static int recurs_dos_loop(MainParam_t *mp, const char *filename0, 
00198                            const char *filename1,
00199                            lookupState_t *lookupState)
00200 {
00201         /* Dir is de-allocated by the same entity which allocated it */
00202         const char *ptr;
00203         direntry_t entry;
00204         int length;
00205         int lookupflags;
00206         int ret;
00207         int have_one;
00208         int doing_mcwd;
00209         int r;
00210 
00211         while(1) {
00212                 /* strip dots and // */
00213                 if(!strncmp(filename0,"./", 2)) {
00214                         filename0 += 2;
00215                         continue;
00216                 }
00217                 if(!strcmp(filename0,".") && filename1) {
00218                         filename0 ++;
00219                         continue;
00220                 }
00221                 if(filename0[0] == '/') {
00222                         filename0++;
00223                         continue;
00224                 }
00225                 if(!filename0[0]) {
00226                         if(!filename1)
00227                                 break;
00228                         filename0 = filename1;
00229                         filename1 = 0;
00230                         continue;
00231                 }
00232                 break;
00233         }
00234 
00235         if(!strncmp(filename0,"../", 3) || 
00236            (!strcmp(filename0, "..") && filename1)) {
00237                 /* up one level */
00238                 mp->File = getDirentry(mp->File)->Dir;
00239                 return recurs_dos_loop(mp, filename0+2, filename1, lookupState);
00240         }
00241 
00242         doing_mcwd = !!filename1;
00243 
00244         ptr = strchr(filename0, '/');
00245         if(!ptr) {                      
00246                 length = strlen(filename0);             
00247                 ptr = filename1;
00248                 filename1 = 0;
00249         } else {
00250                 length = ptr - filename0;
00251                 ptr++;
00252         }
00253         if(!ptr) {
00254                 if(mp->lookupflags & OPEN_PARENT) {
00255                         mp->targetName = filename0;
00256                         ret = handle_leaf(getDirentry(mp->File), mp, 
00257                                           lookupState);
00258                         mp->targetName = 0;
00259                         return ret;
00260                 }
00261                 
00262                 if(!strcmp(filename0, ".") || !filename0[0]) {
00263                         return handle_leaf(getDirentry(mp->File), 
00264                                            mp, lookupState);
00265                 }
00266 
00267                 if(!strcmp(filename0, "..")) {
00268                         return handle_leaf(getParent(getDirentry(mp->File)), mp,
00269                                            lookupState);
00270                 }
00271 
00272                 lookupflags = mp->lookupflags;
00273                 
00274                 if(lookupState) {
00275                         lookupState->filename = filename0;
00276                         if(lookupState->nbContainers + lookupState->nbDirs > 0){
00277                                 /* we have already one target, don't bother 
00278                                  * with this one. */
00279                                 FREE(&lookupState->container);
00280                         } else {
00281                                 /* no match yet.  Remember this container for 
00282                                  * later use */
00283                                 lookupState->container = COPY(mp->File);
00284                         }
00285                         lookupState->nbContainers++;
00286                 }
00287         } else
00288                 lookupflags = ACCEPT_DIR | DO_OPEN | NO_DOTS;
00289 
00290         ret = 0;
00291         r = 0;
00292         have_one = 0;
00293         initializeDirentry(&entry, mp->File);
00294         while(!(ret & STOP_NOW) &&
00295               !got_signal &&
00296               (r=vfat_lookup(&entry, filename0, length,
00297                              lookupflags | NO_MSG, 
00298                              mp->shortname, mp->longname)) == 0 ){
00299                 if(checkForDot(lookupflags, entry.name))
00300                         /* while following the path, ignore the
00301                          * special entries if they were not
00302                          * explicitly given */
00303                         continue;
00304                 have_one = 1;
00305                 if(ptr) {
00306                         Stream_t *SubDir;
00307                         SubDir = mp->File = OpenFileByDirentry(&entry);
00308                         ret |= recurs_dos_loop(mp, ptr, filename1, lookupState);
00309                         FREE(&SubDir);
00310                 } else {
00311                         ret |= handle_leaf(&entry, mp, lookupState);
00312                         if(isUniqueTarget(mp->targetName))
00313                                 return ret | STOP_NOW;
00314                 }
00315                 if(doing_mcwd)
00316                         break;
00317         }
00318         if (r == -2)
00319                 return ERROR_ONE;
00320         if(got_signal)
00321                 return ret | ERROR_ONE;
00322         if(doing_mcwd & !have_one)
00323                 return NO_CWD;
00324         return ret;
00325 }
00326 
00327 static int common_dos_loop(MainParam_t *mp, const char *pathname,
00328                            lookupState_t *lookupState, int open_mode)
00329 
00330 {
00331         Stream_t *RootDir;
00332         char *cwd;
00333         char *drive;
00334         char *rest;
00335 
00336         int ret;
00337         mp->loop = _dos_loop;
00338         
00339         drive='\0';
00340         cwd = "";
00341         if((rest = skip_drive(pathname)) > pathname) {
00342                 drive = get_drive(pathname, NULL);
00343                 if (strncmp(pathname, mp->mcwd, rest - pathname) == 0)
00344                         cwd = skip_drive(mp->mcwd);
00345                 pathname = rest;
00346         } else {
00347                 drive = get_drive(mp->mcwd, NULL);
00348                 cwd = skip_drive(mp->mcwd);
00349         }
00350 
00351         if(*pathname=='/') /* absolute path name */
00352                 cwd = "";
00353 
00354         RootDir = mp->File = open_root_dir(drive, open_mode);
00355         if(!mp->File)
00356                 return ERROR_ONE;
00357 
00358         ret = recurs_dos_loop(mp, cwd, pathname, lookupState);
00359         if(ret & NO_CWD) {
00360                 /* no CWD */
00361                 *mp->mcwd = '\0';
00362                 unlink_mcwd();
00363                 ret = recurs_dos_loop(mp, "", pathname, lookupState);
00364         }
00365         FREE(&RootDir);
00366         return ret;
00367 }
00368 
00369 static int dos_loop(MainParam_t *mp, const char *arg)
00370 {
00371         return common_dos_loop(mp, arg, 0, mp->openflags);
00372 }
00373 
00374 
00375 static int dos_target_lookup(MainParam_t *mp, const char *arg)
00376 {
00377         lookupState_t lookupState;
00378         int ret;
00379         int lookupflags;
00380 
00381         lookupState.nbDirs = 0;
00382         lookupState.Dir = 0;
00383         lookupState.nbContainers = 0;
00384         lookupState.container = 0;
00385 
00386         lookupflags = mp->lookupflags;
00387         mp->lookupflags = DO_OPEN | ACCEPT_DIR;
00388         ret = common_dos_loop(mp, arg, &lookupState, O_RDWR);
00389         mp->lookupflags = lookupflags;
00390         if(ret & ERROR_ONE)
00391                 return ret;
00392 
00393         if(lookupState.nbDirs) {
00394                 mp->targetName = 0;
00395                 mp->targetDir = lookupState.Dir;
00396                 FREE(&lookupState.container); /* container no longer needed */
00397                 return ret;
00398         }
00399 
00400         switch(lookupState.nbContainers) {
00401                 case 0:
00402                         /* no match */
00403                         fprintf(stderr,"%s: no match for target\n", arg);
00404                         return MISSED_ONE;
00405                 case 1:
00406                         mp->targetName = strdup(lookupState.filename);
00407                         mp->targetDir = lookupState.container;
00408                         return ret;
00409                 default:
00410                         /* too much */
00411                         fprintf(stderr, "Ambigous %s\n", arg);
00412                         return ERROR_ONE;                       
00413         }
00414 }
00415 
00416 int unix_target_lookup(MainParam_t *mp, const char *arg)
00417 {
00418         char *ptr;
00419         mp->unixTarget = strdup(arg);
00420         /* try complete filename */
00421         if(access(mp->unixTarget, F_OK) == 0)
00422                 return GOT_ONE;
00423         ptr = strrchr(mp->unixTarget, '/');
00424         if(!ptr) {
00425                 mp->targetName = mp->unixTarget;
00426                 mp->unixTarget = strdup(".");
00427                 return GOT_ONE;
00428         } else {
00429                 *ptr = '\0';
00430                 mp->targetName = ptr+1;
00431                 return GOT_ONE;
00432         }
00433 }
00434 
00435 int target_lookup(MainParam_t *mp, const char *arg)
00436 {
00437         if((mp->lookupflags & NO_UNIX) || skip_drive(arg) > arg)
00438                 return dos_target_lookup(mp, arg);
00439         else
00440                 return unix_target_lookup(mp, arg);
00441 }
00442 
00443 int main_loop(MainParam_t *mp, char **argv, int argc)
00444 {
00445         int i;
00446         int ret, Bret;
00447         
00448         Bret = 0;
00449 
00450         if(argc != 1 && mp->targetName) {
00451                 fprintf(stderr,
00452                         "Several file names given, but last argument (%s) not a directory\n", mp->targetName);
00453         }
00454 
00455         for (i = 0; i < argc; i++) {
00456                 if ( got_signal )
00457                         break;
00458                 mp->originalArg = argv[i];
00459                 mp->basenameHasWildcard = strpbrk(_basename(mp->originalArg), 
00460                                                   "*[?") != 0;
00461                 if (mp->unixcallback && skip_drive(argv[i]) == argv[i])
00462                         ret = unix_loop(0, mp, argv[i], 1);
00463                 else
00464                         ret = dos_loop(mp, argv[i]);
00465                 
00466                 if (! (ret & (GOT_ONE | ERROR_ONE)) ) {
00467                         /* one argument was unmatched */
00468                         fprintf(stderr, "%s: File \"%s\" not found\n",
00469                                 progname, argv[i]);
00470                         ret |= ERROR_ONE;
00471                 }
00472                 Bret |= ret;
00473                 if(mp->fast_quit && (Bret & (MISSED_ONE | ERROR_ONE)))
00474                         break;
00475         }
00476         FREE(&mp->targetDir);
00477         if(Bret & ERROR_ONE)
00478                 return 1;
00479         if ((Bret & GOT_ONE) && ( Bret & MISSED_ONE))
00480                 return 2;
00481         if (Bret & MISSED_ONE)
00482                 return 1;
00483         return 0;
00484 }
00485 
00486 static int dispatchToFile(direntry_t *entry, MainParam_t *mp)
00487 {
00488         if(entry)
00489                 return mp->callback(entry, mp);
00490         else
00491                 return mp->unixcallback(mp);
00492 }
00493 
00494 
00495 void init_mp(MainParam_t *mp)
00496 {
00497         fix_mcwd(mp->mcwd);
00498         mp->openflags = 0;
00499         mp->targetName = 0;
00500         mp->targetDir = 0;
00501         mp->unixTarget = 0;
00502         mp->dirCallback = dispatchToFile;
00503         mp->unixcallback = NULL;
00504         mp->shortname = mp->longname = 0;
00505         mp->File = 0;
00506         mp->fast_quit = 0;
00507 }
00508 
00509 const char *mpGetBasename(MainParam_t *mp)
00510 {
00511         if(mp->direntry)
00512                 return mp->direntry->name;
00513         else
00514                 return _basename(mp->unixSourceName);
00515 }
00516 
00517 void mpPrintFilename(FILE *fp, MainParam_t *mp)
00518 {
00519         if(mp->direntry)
00520                 fprintPwd(fp, mp->direntry, 0);
00521         else
00522                 fprintf(fp,"%s",mp->originalArg);
00523 }
00524 
00525 const char *mpPickTargetName(MainParam_t *mp)
00526 {
00527         /* picks the target name: either the one explicitly given by the
00528          * user, or the same as the source */
00529         if(mp->targetName)
00530                 return mp->targetName;
00531         else
00532                 return mpGetBasename(mp);
00533 }
00534 
00535 char *mpBuildUnixFilename(MainParam_t *mp)
00536 {
00537         const char *target;
00538         char *ret;
00539 
00540         target = mpPickTargetName(mp);
00541         ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target));
00542         if(!ret)
00543                 return 0;
00544         strcpy(ret, mp->unixTarget);
00545         if(*target) {
00546 #if 1 /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */
00547                 if(!mp->targetName && !mp->targetDir) {
00548                         struct stat buf;
00549                         if (!stat(ret, &buf) && !S_ISDIR(buf.st_mode))
00550                                 return ret;
00551                 }
00552 #endif
00553                 strcat(ret, "/");
00554                 strcat(ret, target);
00555         }
00556         return ret;
00557 }

Generated on Fri Apr 14 22:56:55 2006 for minix by  doxygen 1.4.6