From: Robert Pengelly Date: Sun, 31 Aug 2025 06:13:16 +0000 (+0100) Subject: Allow overriding files X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=bcbcc853ac3f37bc783ea9166056d62dc962774f;p=e2fsprogs.git Allow overriding files --- diff --git a/e2cp.c b/e2cp.c index 283ec2d..bdea24f 100644 --- 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 +# include +# elif defined (__GNUC__) +# include +# include +# include +# if defined (__CYGWIN__) +# include +# 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); }