Imported Upstream version 4.0.43
[platform/upstream/mtools.git] / mainloop.c
index cfd91bf..7b9f8a0 100644 (file)
@@ -20,9 +20,7 @@
  */
 
 #include "sysincludes.h"
-#include "msdos.h"
 #include "mtools.h"
-#include "vfat.h"
 #include "fs.h"
 #include "mainloop.h"
 #include "plain_io.h"
@@ -85,10 +83,6 @@ static const char *fix_mcwd(char *ans)
        return ans;
 }
 
-int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); 
-int unix_loop(Stream_t *Stream UNUSEDP, MainParam_t *mp, char *arg,
-             int follow_dir_link);
-
 static int _unix_loop(Stream_t *Dir, MainParam_t *mp,
                      const char *filename UNUSEDP)
 {
@@ -100,7 +94,7 @@ int unix_loop(Stream_t *Stream UNUSEDP, MainParam_t *mp,
 {
        int ret;
        int isdir=0;
-       int unixNameLength;
+       size_t unixNameLength;
 
        mp->File = NULL;
        mp->direntry = NULL;
@@ -142,7 +136,7 @@ int unix_loop(Stream_t *Stream UNUSEDP, MainParam_t *mp,
                                fprintf(stderr,
                                        "skipping directory symlink %s\n",
                                        arg);
-                               return 0;                               
+                               return 0;
                        }
 #endif
                        if(! (mp->lookupflags & ACCEPT_DIR))
@@ -159,31 +153,6 @@ int unix_loop(Stream_t *Stream UNUSEDP, MainParam_t *mp,
        return ret;
 }
 
-
-int isSpecial(const char *name)
-{
-       if(name[0] == '\0')
-               return 1;
-       if(!strcmp(name,"."))
-               return 1;
-       if(!strcmp(name,".."))
-               return 1;
-       return 0;                       
-}
-
-#ifdef HAVE_WCHAR_H
-int isSpecialW(const wchar_t *name)
-{
-       if(name[0] == '\0')
-               return 1;
-       if(!wcscmp(name,L"."))
-               return 1;
-       if(!wcscmp(name,L".."))
-               return 1;
-       return 0;                       
-}
-#endif
-
 static int checkForDot(int lookupflags, const wchar_t *name)
 {
        return (lookupflags & NO_DOTS) && isSpecialW(name);
@@ -204,7 +173,8 @@ static int isUniqueTarget(const char *name)
 }
 
 static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
-                      lookupState_t *lookupState)
+                      lookupState_t *lookupState,
+                      Stream_t **DeferredFileP)
 {
        Stream_t *MyFile=0;
        int ret;
@@ -236,18 +206,29 @@ static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
                        MyFile = mp->File = OpenFileByDirentry(direntry);
                ret = mp->dirCallback(direntry, mp);
        } else {
-               if(mp->lookupflags & DO_OPEN)
+               if(mp->lookupflags & DO_OPEN) {
+                       if(DeferredFileP && *DeferredFileP) {
+                               /* Already a deferred file => close it and error */
+                               FREE(DeferredFileP);
+                               fprintf(stderr,
+                                       "Attempt to copy multiple files to non-directory\n");
+                               return STOP_NOW | ERROR_ONE;
+                       }
+
                        MyFile = mp->File = OpenFileByDirentry(direntry);
+                       if(DeferredFileP) {
+                               *DeferredFileP = MyFile;
+                               return 0;
+                       }
+               }
                ret = mp->callback(direntry, mp);
        }
        FREE(&MyFile);
-       if(isUniqueTarget(mp->targetName))
-               ret |= STOP_NOW;
        return ret;
 }
 
 static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
-{      
+{
        Stream_t *MyFile=0;
        direntry_t entry;
        int ret;
@@ -257,10 +238,10 @@ static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
        r=0;
        initializeDirentry(&entry, Dir);
        while(!got_signal &&
-             (r=vfat_lookup(&entry, filename, -1,
-                            mp->lookupflags,
-                            mp->shortname.data, mp->shortname.len,
-                            mp->longname.data, mp->longname.len)) == 0 ){
+             (r=vfat_lookup_zt(&entry, filename,
+                               mp->lookupflags,
+                               mp->shortname.data, mp->shortname.len,
+                               mp->longname.data, mp->longname.len)) == 0 ){
                mp->File = NULL;
                if(!checkForDot(mp->lookupflags,entry.name)) {
                        MyFile = 0;
@@ -292,12 +273,13 @@ static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
 
 static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
                           const char *filename1,
-                          lookupState_t *lookupState)
+                          lookupState_t *lookupState,
+                          Stream_t **DeferredFileP)
 {
        /* Dir is de-allocated by the same entity which allocated it */
        const char *ptr;
        direntry_t entry;
-       int length;
+       size_t length;
        int lookupflags;
        int ret;
        int have_one;
@@ -332,41 +314,42 @@ static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
           (!strcmp(filename0, "..") && filename1)) {
                /* up one level */
                mp->File = getDirentry(mp->File)->Dir;
-               return recurs_dos_loop(mp, filename0+2, filename1, lookupState);
+               return recurs_dos_loop(mp, filename0+2, filename1, lookupState,
+                                      DeferredFileP);
        }
 
        doing_mcwd = !!filename1;
 
        ptr = strchr(filename0, '/');
-       if(!ptr) {                      
-               length = strlen(filename0);             
+       if(!ptr) {
+               length = strlen(filename0);
                ptr = filename1;
                filename1 = 0;
        } else {
-               length = ptr - filename0;
+               length = ptrdiff(ptr, filename0);
                ptr++;
        }
        if(!ptr) {
                if(mp->lookupflags & OPEN_PARENT) {
                        mp->targetName = filename0;
                        ret = handle_leaf(getDirentry(mp->File), mp,
-                                         lookupState);
+                                         lookupState, NULL);
                        mp->targetName = 0;
                        return ret;
                }
-               
+
                if(!strcmp(filename0, ".") || !filename0[0]) {
                        return handle_leaf(getDirentry(mp->File),
-                                          mp, lookupState);
+                                          mp, lookupState, NULL);
                }
 
                if(!strcmp(filename0, "..")) {
                        return handle_leaf(getParent(getDirentry(mp->File)), mp,
-                                          lookupState);
+                                          lookupState, NULL);
                }
 
                lookupflags = mp->lookupflags;
-               
+
                if(lookupState) {
                        lookupState->filename = filename0;
                        if(lookupState->nbContainers + lookupState->nbDirs > 0){
@@ -402,12 +385,12 @@ static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
                if(ptr) {
                        Stream_t *SubDir;
                        SubDir = mp->File = OpenFileByDirentry(&entry);
-                       ret |= recurs_dos_loop(mp, ptr, filename1, lookupState);
+                       ret |= recurs_dos_loop(mp, ptr, filename1, lookupState,
+                                              DeferredFileP);
                        FREE(&SubDir);
                } else {
-                       ret |= handle_leaf(&entry, mp, lookupState);
-                       if(isUniqueTarget(mp->targetName))
-                               return ret | STOP_NOW;
+                       ret |= handle_leaf(&entry, mp, lookupState,
+                                          DeferredFileP);
                }
                if(doing_mcwd)
                        break;
@@ -428,10 +411,12 @@ static int common_dos_loop(MainParam_t *mp, const char *pathname,
        Stream_t *RootDir;
        const char *cwd;
        char drive;
+       Stream_t *DeferredFile=NULL;
+       Stream_t **DeferredFileP=NULL;
 
        int ret;
        mp->loop = _dos_loop;
-       
+
        drive='\0';
        cwd = "";
        if(*pathname && pathname[1] == ':') {
@@ -453,12 +438,22 @@ static int common_dos_loop(MainParam_t *mp, const char *pathname,
        if(!mp->File)
                return ERROR_ONE;
 
-       ret = recurs_dos_loop(mp, cwd, pathname, lookupState);
+       if(mp->originalArg && strpbrk(mp->originalArg, "*[?") != 0 &&
+          (mp->lookupflags & DEFERABLE) &&
+          isUniqueTarget(mp->targetName))
+               DeferredFileP = &DeferredFile;
+       
+       ret = recurs_dos_loop(mp, cwd, pathname, lookupState, DeferredFileP);
        if(ret & NO_CWD) {
                /* no CWD */
                *mp->mcwd = '\0';
                unlink_mcwd();
-               ret = recurs_dos_loop(mp, "", pathname, lookupState);
+               ret = recurs_dos_loop(mp, "", pathname, lookupState, DeferredFileP);
+       }
+       if(DeferredFile) {
+               mp->File = DeferredFile;
+               ret = mp->callback(NULL, mp);
+               FREE(&DeferredFile);
        }
        FREE(&RootDir);
        return ret;
@@ -470,7 +465,7 @@ static int dos_loop(MainParam_t *mp, const char *arg)
 }
 
 
-static int dos_target_lookup(MainParam_t *mp, const char *arg)
+int dos_target_lookup(MainParam_t *mp, const char *arg)
 {
        lookupState_t lookupState;
        int ret;
@@ -507,47 +502,22 @@ static int dos_target_lookup(MainParam_t *mp, const char *arg)
                default:
                        /* too much */
                        fprintf(stderr, "Ambiguous %s\n", arg);
-                       return ERROR_ONE;                       
-       }
-}
-
-static int unix_target_lookup(MainParam_t *mp, const char *arg)
-{
-       char *ptr;
-       mp->unixTarget = strdup(arg);
-       /* try complete filename */
-       if(access(mp->unixTarget, F_OK) == 0)
-               return GOT_ONE;
-       ptr = strrchr(mp->unixTarget, '/');
-       if(!ptr) {
-               mp->targetName = mp->unixTarget;
-               mp->unixTarget = strdup(".");
-               return GOT_ONE;
-       } else {
-               *ptr = '\0';
-               mp->targetName = ptr+1;
-               return GOT_ONE;
+                       return ERROR_ONE;
        }
 }
 
-int target_lookup(MainParam_t *mp, const char *arg)
-{
-       if((mp->lookupflags & NO_UNIX) || (arg[0] && arg[1] == ':' ))
-               return dos_target_lookup(mp, arg);
-       else
-               return unix_target_lookup(mp, arg);
-}
-
 int main_loop(MainParam_t *mp, char **argv, int argc)
 {
        int i;
        int ret, Bret;
-       
+
        Bret = 0;
 
        if(argc != 1 && mp->targetName) {
                fprintf(stderr,
                        "Several file names given, but last argument (%s) not a directory\n", mp->targetName);
+               FREE(&mp->targetDir);
+               return 1;
        }
 
        for (i = 0; i < argc; i++) {
@@ -565,7 +535,7 @@ int main_loop(MainParam_t *mp, char **argv, int argc)
                        ret = unix_loop(0, mp, argv[i], 1);
                else
                        ret = dos_loop(mp, argv[i]);
-               
+
                if (! (ret & (GOT_ONE | ERROR_ONE)) ) {
                        /* one argument was unmatched */
                        fprintf(stderr, "%s: File \"%s\" not found\n",
@@ -599,15 +569,16 @@ void init_mp(MainParam_t *mp)
 {
        fix_mcwd(mp->mcwd);
        mp->openflags = O_RDONLY;
+       mp->lookupflags = 0;
        mp->targetName = 0;
        mp->targetDir = 0;
-       mp->unixTarget = 0;
        mp->dirCallback = dispatchToFile;
        mp->unixcallback = NULL;
        mp->shortname.data = mp->longname.data = 0;
        mp->shortname.len = mp->longname.len = 0;
        mp->File = 0;
        mp->fast_quit = 0;
+       mp->originalArg = 0;
 }
 
 const char *mpGetBasename(MainParam_t *mp)
@@ -637,38 +608,3 @@ const char *mpPickTargetName(MainParam_t *mp)
        else
                return mpGetBasename(mp);
 }
-
-char *mpBuildUnixFilename(MainParam_t *mp)
-{
-       const char *target;
-       char *ret;
-       char *tmp;
-
-       target = mpPickTargetName(mp);
-       ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target));
-       if(!ret)
-               return 0;
-       strcpy(ret, mp->unixTarget);
-       if(*target) {
-#if 1 /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */
-               if(!mp->targetName && !mp->targetDir) {
-                       struct MT_STAT buf;
-                       if (!MT_STAT(ret, &buf) && !S_ISDIR(buf.st_mode))
-                               return ret;
-               }
-#endif
-               strcat(ret, "/");
-               if(!strcmp(target, ".")) {
-                 target="DOT";
-               } else if(!strcmp(target, "..")) {
-                 target="DOTDOT";
-               }
-               while( (tmp=strchr(target, '/')) ) {
-                 strncat(ret, target, tmp-target);
-                 strcat(ret, "\\");
-                 target=tmp+1;
-               }
-               strcat(ret, target);
-       }
-       return ret;
-}