Allow overriding files
authorRobert Pengelly <robertapengelly@hotmail.com>
Sun, 31 Aug 2025 06:13:16 +0000 (07:13 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Sun, 31 Aug 2025 06:13:16 +0000 (07:13 +0100)
e2cp.c

diff --git a/e2cp.c b/e2cp.c
index 283ec2d32bc4e1cd57763274f98e3061dae05fb8..bdea24fe74720961a149d0038360eb63da0e3d69 100644 (file)
--- a/e2cp.c
+++ b/e2cp.c
@@ -338,23 +338,12 @@ signed long read_cb (struct filesystem *fs, struct inode_pos *ipos, signed long
 
 #define     EXT2_FEATURE_RO_COMPAT_LARGE_FILE               0x0002
 
-unsigned long mkfile_fs (struct filesystem *fs, unsigned long parent_nod, const char *name, void *data, unsigned long size, unsigned short uid, unsigned short gid, unsigned long ctime, unsigned long mtime) {
+static void write_file (struct filesystem *fs, struct inode *node, struct inode_pos *ipos, unsigned long size, void *data) {
 
-    unsigned long nod;
-    
-    struct inode_pos ipos;
-    struct nod_info *ni;
-    struct inode *node;
-    
     signed long actual_size;
     
-    nod = mknod_fs (fs, parent_nod, name, mode_con (mode), uid, gid, ctime, mtime);
-    node = get_nod (fs, nod, &ni);
-    
-    inode_pos_init (fs, &ipos, nod, INODE_POS_TRUNCATE, 0);
-    
-    if ((actual_size = read_cb (fs, &ipos, size, data)) > 0x7FFFFFFF) {
-    
+    if ((actual_size = read_cb (fs, ipos, size, data)) > 0x7FFFFFFF) {
+        
         unsigned long feature_ro_compat = byte_array_to_integer (fs->sb->s_feature_ro_compat, 4);
         
         if (byte_array_to_integer (fs->sb->s_rev_level, 4) < 1) {
@@ -370,6 +359,22 @@ unsigned long mkfile_fs (struct filesystem *fs, unsigned long parent_nod, const
 #endif
     
     write_to_byte_array (node->i_size, actual_size, 4);
+
+}
+
+unsigned long mkfile_fs (struct filesystem *fs, unsigned long parent_nod, const char *name, void *data, unsigned long size, unsigned short uid, unsigned short gid, unsigned long ctime, unsigned long mtime) {
+
+    unsigned long nod;
+    
+    struct inode_pos ipos;
+    struct nod_info *ni;
+    struct inode *node;
+    
+    nod = mknod_fs (fs, parent_nod, name, mode_con (mode), uid, gid, ctime, mtime);
+    node = get_nod (fs, nod, &ni);
+    
+    inode_pos_init (fs, &ipos, nod, INODE_POS_TRUNCATE, 0);
+    write_file (fs, node, &ipos, size, data);
     
     inode_pos_finish (&ipos);
     put_nod (ni);
@@ -381,16 +386,17 @@ unsigned long mkfile_fs (struct filesystem *fs, unsigned long parent_nod, const
 static int walk_path (struct filesystem *fs, char *dirname) {
 
     unsigned long nod = EXT2_ROOT_INO;
-    char *p1 = dirname, *p2;
+    char *p1 = dirname, *p2, saved_ch;
     
-    while (*p1 && *p1 == '/') {
+    while (*p1 && (*p1 == '/' || *p1 == '\\')) {
         p1++;
     }
     
     if (*p1) {
     
-        for (; (p2 = strchr (p1, '/')); p1 = p2 + 1) {
+        for (; (p2 = strchr (p1, '/')) || (p2 = strchr (p1, '\\')); p1 = p2 + 1) {
         
+            saved_ch = *p2;
             *p2 = '\0';
             
             if (strlen (p1) >= 14) {
@@ -401,12 +407,12 @@ static int walk_path (struct filesystem *fs, char *dirname) {
             
                 report_at (program_name, 0, REPORT_ERROR, "cannot access '%s'", dirname);
                 
-                *p2 = '/';
+                *p2 = saved_ch;
                 return 0;
             
             }
             
-            *p2 = '/';
+            *p2 = saved_ch;
         
         }
         
@@ -423,20 +429,284 @@ static int walk_path (struct filesystem *fs, char *dirname) {
 
 }
 
-static void copy_file (struct filesystem *fs, FILE *fp, unsigned long parent_nod, char *fn) {
+#ifndef     __PDOS__
+# if    defined (_WIN32)
+#  include  <windows.h>
+#  include  <winioctl.h>
+# elif defined (__GNUC__)
+#  include  <sys/ioctl.h>
+#  include  <termios.h>
+#  include  <unistd.h>
+#  if   defined (__CYGWIN__)
+#   include  <sys/socket.h>
+#  endif
+# endif
+
+/** Get a single character from the terminal. */
+static char getch (void) {
+
+#if     defined(_WIN32) && !defined (__PDOS__)
+
+    KEY_EVENT_RECORD keyevent;
+    INPUT_RECORD irec;
+    DWORD events;
+    
+    for (;;) {
+    
+        ReadConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &irec, 1, &events);
+        
+        if (irec.EventType == KEY_EVENT && ((KEY_EVENT_RECORD) irec.Event.KeyEvent).bKeyDown) {
+        
+            const int ca = (int) keyevent.uChar.AsciiChar;
+            const int cv = (int) keyevent.wVirtualKeyCode;
+            const int key = ca == 0 ? -cv : ca + (ca > 0 ? 0 : 256);
+            
+            keyevent = (KEY_EVENT_RECORD) irec.Event.KeyEvent;
+            
+            switch (key) {
+            
+                case  -16: continue;    /* disable Shift */
+                case  -17: continue;    /* disable Ctrl / AltGr */
+                case  -18: continue;    /* disable Alt / AltGr */
+                case -220: continue;    /* disable first detection of "^" key (not "^" symbol) */
+                case -221: continue;    /* disable first detection of "'" key (not "'" symbol) */
+                case -191: continue;    /* disable AltGr + "#" */
+                case  -52: continue;    /* disable AltGr + "4" */
+                case  -53: continue;    /* disable AltGr + "5" */
+                case  -54: continue;    /* disable AltGr + "6" */
+                case  -12: continue;    /* disable num block 5 with num lock deactivated */
+                case   13: return  10;  /* enter */
+                case  -46: return 127;  /* delete */
+                case  -49: return 251;  /* Â¹ */
+                case    0: continue;
+                case    1: continue;    /* disable Ctrl + a (selects all text) */
+                case    2: continue;    /* disable Ctrl + b */
+                case    3: continue;    /* disable Ctrl + c (terminates program) */
+                case    4: continue;    /* disable Ctrl + d */
+                case    5: continue;    /* disable Ctrl + e */
+                case    6: continue;    /* disable Ctrl + f (opens search) */
+                case    7: continue;    /* disable Ctrl + g */
+                case   10: continue;    /* disable Ctrl + j */
+                case   11: continue;    /* disable Ctrl + k */
+                case   12: continue;    /* disable Ctrl + l */
+                case   14: continue;    /* disable Ctrl + n */
+                case   15: continue;    /* disable Ctrl + o */
+                case   16: continue;    /* disable Ctrl + p */
+                case   17: continue;    /* disable Ctrl + q */
+                case   18: continue;    /* disable Ctrl + r */
+                case   19: continue;    /* disable Ctrl + s */
+                case   20: continue;    /* disable Ctrl + t */
+                case   21: continue;    /* disable Ctrl + u */
+                case   22: continue;    /* disable Ctrl + v (inserts clipboard) */
+                case   23: continue;    /* disable Ctrl + w */
+                case   24: continue;    /* disable Ctrl + x */
+                case   25: continue;    /* disable Ctrl + y */
+                case   26: continue;    /* disable Ctrl + z */
+                default: return key;    /* any other ASCII/virtual character */
+            
+            }
+        
+        }
+    
+    }
 
-    unsigned long bytes = 0, timestamp = time (0);
-    char *basename = fn, *p;
+#else
+
+    int key;
     
-    if ((p = strrchr (fn, '/'))) {
-        basename = (p + 1);
+#if     defined (__PDOS__)
+
+    setvbuf (stdin, NULL, _IONBF, 0);
+    
+    for (;;) {
+
+#else
+
+    struct termios term;
+    int nbbytes;
+    
+    tcgetattr (0, &term);
+    
+    for (;;) {
+    
+        term.c_lflag &= ~(ICANON | ECHO);                   /* turn off line buffering and echoing */
+        tcsetattr (0, TCSANOW, &term);
+        
+        ioctl (0, FIONREAD, &nbbytes);                      /* 0 is STDIN */
+        
+        while (!nbbytes) {
+        
+            sleep (1);
+            fflush (stdout);
+            
+            ioctl (0, FIONREAD, &nbbytes);                  /* 0 is STDIN */
+        
+        }
+
+#endif
+        
+        key = (int) getchar ();
+        
+        if (key == 27 || key == 194 || key == 195) {        /* escape, 194/195 is escape for Â°ÃŸÂ´Ã¤Ã¶Ã¼Ã„ÖÜ */
+        
+            key = (int) getchar ();
+            
+            if (key == 91) {                                /* [ following escape */
+            
+                key = (int) getchar ();                     /* get code of next char after \e[ */
+                
+                if (key == 49) {                            /* F5-F8 */
+                
+                    key = 62 + (int) getchar ();            /* 53, 55-57 */
+                    
+                    if (key == 115) {
+                        key++;                              /* F5 code is too low by 1 */
+                    }
+                    
+                    getchar ();                             /* take in following ~ (126), but discard code */
+                
+                } else if (key == 50) {                     /* insert or F9-F12 */
+                
+                    key = (int) getchar ();
+                    
+                    if (key == 126) {                       /* insert */
+                        key = 45;
+                    } else {                                /* F9-F12 */
+                    
+                        key += 71;                          /* 48, 49, 51, 52 */
+                        
+                        if (key < 121) {
+                            key++;                          /* F11 and F12 are too low by 1 */
+                        }
+                        
+                        getchar ();                         /* take in following ~ (126), but discard code */
+                    
+                    }
+                
+                } else if (key == 51 || key == 53 || key == 54) {               /* delete, page up/down */
+                    getchar ();                             /* take in following ~ (126), but discard code */
+                }
+            
+            } else if (key == 79) {                         /* F1-F4 */
+                key = 32 + (int) getchar ();                /* 80-83 */
+            }
+            
+            key = -key;                                     /* use negative numbers for escaped keys */
+        
+        }
+        
+#if     defined (__PDOS__)
+        setvbuf (stdin, NULL, _IOLBF, 0);
+#else
+
+        term.c_lflag |= (ICANON | ECHO);                    /* turn on line buffering and echoing */
+        tcsetattr (0, TCSANOW, &term);
+
+#endif
+        
+        switch (key) {
+        
+            case  127: return (char)   8;   /* backspace */
+            case  -27: return (char)  27;   /* escape */
+            case  -51: return (char) 127;   /* delete */
+            case -164: return (char) 132;   /* Ã¤ */
+            case -182: return (char) 148;   /* Ã¶ */
+            case -188: return (char) 129;   /* Ã¼ */
+            case -132: return (char) 142;   /* Ã„ */
+            case -150: return (char) 153;   /* Ã– */
+            case -156: return (char) 154;   /* Ãœ */
+            case -159: return (char) 225;   /* ÃŸ */
+            case -181: return (char) 230;   /* Âµ */
+            case -167: return (char) 245;   /* Â§ */
+            case -176: return (char) 248;   /* Â° */
+            case -178: return (char) 253;   /* Â² */
+            case -179: return (char) 252;   /* Â³ */
+            case -180: return (char) 239;   /* Â´ */
+            case  -65: return (char) -38;   /* up arrow */
+            case  -66: return (char) -40;   /* down arrow */
+            case  -68: return (char) -37;   /* left arrow */
+            case  -67: return (char) -39;   /* right arrow */
+            case  -53: return (char) -33;   /* page up */
+            case  -54: return (char) -34;   /* page down */
+            case  -72: return (char) -36;   /* pos1 */
+            case  -70: return (char) -35;   /* end */
+            case    0: continue;
+            case    1: continue;            /* disable Ctrl + a */
+            case    2: continue;            /* disable Ctrl + b */
+            case    3: continue;            /* disable Ctrl + c (terminates program) */
+            case    4: continue;            /* disable Ctrl + d */
+            case    5: continue;            /* disable Ctrl + e */
+            case    6: continue;            /* disable Ctrl + f */
+            case    7: continue;            /* disable Ctrl + g */
+            case    8: continue;            /* disable Ctrl + h */
+            case   11: continue;            /* disable Ctrl + k */
+            case   12: continue;            /* disable Ctrl + l */
+            case   13: continue;            /* disable Ctrl + m */
+            case   14: continue;            /* disable Ctrl + n */
+            case   15: continue;            /* disable Ctrl + o */
+            case   16: continue;            /* disable Ctrl + p */
+            case   17: continue;            /* disable Ctrl + q */
+            case   18: continue;            /* disable Ctrl + r */
+            case   19: continue;            /* disable Ctrl + s */
+            case   20: continue;            /* disable Ctrl + t */
+            case   21: continue;            /* disable Ctrl + u */
+            case   22: continue;            /* disable Ctrl + v */
+            case   23: continue;            /* disable Ctrl + w */
+            case   24: continue;            /* disable Ctrl + x */
+            case   25: continue;            /* disable Ctrl + y */
+            case   26: continue;            /* disable Ctrl + z (terminates program) */
+            default: return key;            /* any other ASCII character */
+        
+        }
+    
+    }
+
+#endif
+
+}
+#endif
+
+static int check_overwrite (const char *fn) {
+
+#if     defined (__PDOS__)
+
+    report_at (NULL, 0, REPORT_WARNING, "overwriting %s", fn);
+    return 1;
+
+#else
+
+    int ch;
+    
+    printf ("File %s already exists.\n", fn);
+    printf ("o)verwrite s)skip (os): ");
+    
+    while ((ch = tolower (getch ())) < 0) {}
+    
+    if (isspace (ch)) {
+        printf ("\n");
+    } else {
+        printf ("%c\n", ch);
     }
     
-    if (find_entry (fs, parent_nod, basename)) {
+    if (ch == 'o') {
+        return 1;
+    } else if (ch == 's') {
+        return 0;
+    }
     
-        report_at (program_name, 0, REPORT_ERROR, "'%s' already exists.  Currently replacing files isn't supported.", basename);
-        return;
+    return check_overwrite (fn);
+
+#endif
+
+}
+
+static void copy_file (struct filesystem *fs, FILE *fp, unsigned long parent_nod, char *fn) {
+
+    unsigned long bytes = 0, timestamp = time (0), nod;
+    char *basename = fn, *p;
     
+    if ((p = strrchr (fn, '/')) || (p = strrchr (fn, '\\'))) {
+        basename = (p + 1);
     }
     
     fseek (fp, 0, SEEK_END);
@@ -444,7 +714,28 @@ static void copy_file (struct filesystem *fs, FILE *fp, unsigned long parent_nod
     bytes = ftell (fp);
     fseek (fp, 0, SEEK_SET);
     
-    mkfile_fs (fs, parent_nod, basename, fp, bytes, 0, 0, timestamp, timestamp);
+    if ((nod = find_entry (fs, parent_nod, basename))) {
+    
+        struct inode *node;
+        struct nod_info *ni;
+        struct inode_pos ipos;
+        
+        if (!check_overwrite ((char *) basename)) {
+            return;
+        }
+        
+        node = get_nod (fs, nod, &ni);
+        inode_pos_init (fs, &ipos, nod, INODE_POS_TRUNCATE, 0);
+        
+        memset (node->i_block, 0, sizeof (node->i_block));
+        write_file (fs, node, &ipos, bytes, fp);
+        
+        inode_pos_finish (&ipos);
+        put_nod (ni);
+    
+    } else {
+        mkfile_fs (fs, parent_nod, basename, fp, bytes, 0, 0, timestamp, timestamp);
+    }
 
 }
 
@@ -452,7 +743,7 @@ int main (int argc, char **argv) {
 
     struct superblock sup = { 0 };
     
-    unsigned long parent_ino = EXT2_ROOT_INO;
+    unsigned long parent_nod = EXT2_ROOT_INO;
     struct filesystem *fs;
     
     FILE *fp = NULL;
@@ -528,17 +819,17 @@ int main (int argc, char **argv) {
             if (root) {
             
                 report_at (program_name, 0, REPORT_WARNING, "root '%s' is ignored, using output path instead", root);
-                free (root);
                 
+                free (root);
                 root = 0;
             
             }
             
-            if ((p = strrchr (path, '/'))) {
+            if ((p = strrchr (path, '/')) || (p = strrchr (path, '\\'))) {
             
                 *p = '\0';
                 
-                if (!(parent_ino = walk_path (fs, path))) {
+                if (!(parent_nod = walk_path (fs, path))) {
                     return EXIT_FAILURE;
                 }
                 
@@ -553,9 +844,11 @@ int main (int argc, char **argv) {
             
             }
             
-            copy_file (fs, fp, parent_ino, path);
+            copy_file (fs, fp, parent_nod, path);
             
             fclose (fp);
+            finish_fs (fs);
+            
             return (get_error_count () > 0) ? EXIT_FAILURE : EXIT_SUCCESS;
         
         }
@@ -564,7 +857,7 @@ int main (int argc, char **argv) {
     
     if (root) {
     
-        if (!(parent_ino = walk_path (fs, root))) {
+        if (!(parent_nod = walk_path (fs, root))) {
             return EXIT_FAILURE;
         }
     
@@ -579,7 +872,7 @@ int main (int argc, char **argv) {
         
         }
         
-        copy_file (fs, fp, parent_ino, files[i]);
+        copy_file (fs, fp, parent_nod, files[i]);
         fclose (fp);
     
     }