00001
00002
00003
00004
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
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
00058
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
00121 switch(lookupState->nbDirs) {
00122 case 0:
00123 lookupState->Dir = OpenFileByDirentry(direntry);
00124 lookupState->nbDirs++;
00125
00126
00127 FREE(&lookupState->container);
00128 return 0;
00129 case 1:
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
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
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
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
00278
00279 FREE(&lookupState->container);
00280 } else {
00281
00282
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
00301
00302
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=='/')
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
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);
00397 return ret;
00398 }
00399
00400 switch(lookupState.nbContainers) {
00401 case 0:
00402
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
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
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
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
00528
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
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 }