Imported Upstream version 4.0.43
[platform/upstream/mtools.git] / mainloop.c
index 4218edd..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"
@@ -54,7 +52,7 @@ static const char *fix_mcwd(char *ans)
                                        /* drive letter present? */
        s = buf;
        if (buf[0] && buf[1] == ':') {
-               strncpy(ans, buf, 2);
+               memcpy(ans, buf, 2);
                ans[2] = '\0';
                s = &buf[2];
        } else {
@@ -71,7 +69,7 @@ static const char *fix_mcwd(char *ans)
 #if 0
                                        /* translate to upper case */
        for (s = ans; *s; ++s) {
-               *s = toupper(*s);
+               *s = ch_toupper(*s);
                if (*s == '\\')
                        *s = '/';
        }
@@ -85,20 +83,18 @@ 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, MainParam_t *mp, char *arg,
-             int follow_dir_link);
-
-static int _unix_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
+static int _unix_loop(Stream_t *Dir, MainParam_t *mp,
+                     const char *filename UNUSEDP)
 {
        return unix_dir_loop(Dir, mp);
 }
 
-int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link)
+int unix_loop(Stream_t *Stream UNUSEDP, MainParam_t *mp,
+             char *arg, int follow_dir_link)
 {
        int ret;
-       int isdir;
-       int unixNameLength;
+       int isdir=0;
+       size_t unixNameLength;
 
        mp->File = NULL;
        mp->direntry = NULL;
@@ -140,12 +136,12 @@ int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link)
                                fprintf(stderr,
                                        "skipping directory symlink %s\n",
                                        arg);
-                               return 0;                               
+                               return 0;
                        }
 #endif
                        if(! (mp->lookupflags & ACCEPT_DIR))
                                return 0;
-                       mp->File = OpenDir(Stream, arg);
+                       mp->File = OpenDir(arg);
                }
        }
 
@@ -157,31 +153,6 @@ int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link)
        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);
@@ -202,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;
@@ -221,7 +193,7 @@ static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
                                return 0;
                        case 1: /* we have already a directory */
                                FREE(&lookupState->Dir);
-                               fprintf(stderr,"Ambigous\n");
+                               fprintf(stderr,"Ambiguous\n");
                                return STOP_NOW | ERROR_ONE;
                        default:
                                return STOP_NOW | ERROR_ONE;
@@ -234,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;
@@ -255,9 +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,
-                            mp->longname)) == 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;
@@ -289,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;
@@ -329,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){
@@ -388,7 +374,8 @@ static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
              !got_signal &&
              (r=vfat_lookup(&entry, filename0, length,
                             lookupflags | NO_MSG,
-                            mp->shortname, mp->longname)) == 0 ){
+                            mp->shortname.data, mp->shortname.len,
+                            mp->longname.data, mp->longname.len)) == 0 ){
                if(checkForDot(lookupflags, entry.name))
                        /* while following the path, ignore the
                         * special entries if they were not
@@ -398,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;
@@ -424,14 +411,16 @@ 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] == ':') {
-               drive = toupper(*pathname);
+               drive = ch_toupper(*pathname);
                pathname += 2;
                if(mp->mcwd[0] == drive)
                        cwd = mp->mcwd+2;
@@ -449,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;
@@ -466,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;
@@ -502,48 +501,23 @@ static int dos_target_lookup(MainParam_t *mp, const char *arg)
                        return ret;
                default:
                        /* too much */
-                       fprintf(stderr, "Ambigous %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;
+                       fprintf(stderr, "Ambiguous %s\n", arg);
+                       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++) {
@@ -561,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",
@@ -595,21 +569,23 @@ 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 = mp->longname = 0;
+       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)
 {
        if(mp->direntry) {
                wchar_to_native(mp->direntry->name, mp->targetBuffer,
-                               MAX_VNAMELEN+1);
+                               MAX_VNAMELEN+1, sizeof(mp->targetBuffer));
                return mp->targetBuffer;
        } else
                return _basename(mp->unixSourceName);
@@ -632,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;
-}