#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) {
#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);
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) {
report_at (program_name, 0, REPORT_ERROR, "cannot access '%s'", dirname);
- *p2 = '/';
+ *p2 = saved_ch;
return 0;
}
- *p2 = '/';
+ *p2 = saved_ch;
}
}
-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);
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);
+ }
}
struct superblock sup = { 0 };
- unsigned long parent_ino = EXT2_ROOT_INO;
+ unsigned long parent_nod = EXT2_ROOT_INO;
struct filesystem *fs;
FILE *fp = NULL;
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;
}
}
- 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;
}
if (root) {
- if (!(parent_ino = walk_path (fs, root))) {
+ if (!(parent_nod = walk_path (fs, root))) {
return EXIT_FAILURE;
}
}
- copy_file (fs, fp, parent_ino, files[i]);
+ copy_file (fs, fp, parent_nod, files[i]);
fclose (fp);
}