dump.c revision efc6f628e15de95bcd13e4f0ee223cb42115d520
1f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/* 2f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * dump.c --- dump the contents of an inode out to a file 3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 4f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * Copyright (C) 1994 Theodore Ts'o. This file may be redistributed 5f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * under the terms of the GNU Public License. 6f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */ 7f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 8efac5a7f0d19b06276520b35bc986540eb22c34dTheodore Ts'o#define _GNU_SOURCE /* for O_LARGEFILE */ 9efac5a7f0d19b06276520b35bc986540eb22c34dTheodore Ts'o 10f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <stdio.h> 11f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <unistd.h> 12f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <stdlib.h> 13f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <ctype.h> 14f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <string.h> 15f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <time.h> 1650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#ifdef HAVE_ERRNO_H 1750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#include <errno.h> 1850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#endif 19f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h> 20f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/stat.h> 21f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <fcntl.h> 22fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o#include <utime.h> 23fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o#ifdef HAVE_GETOPT_H 24fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o#include <getopt.h> 25efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o#else 26fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'oextern int optind; 27fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'oextern char *optarg; 28fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o#endif 29f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 30f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include "debugfs.h" 31f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 32819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#ifndef O_LARGEFILE 33819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#define O_LARGEFILE 0 34819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#endif 35819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o 36fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o/* 37fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o * The mode_xlate function translates a linux mode into a native-OS mode_t. 38fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o */ 39fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'ostatic struct { 40fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o __u16 lmask; 41fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o mode_t mask; 42fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o} mode_table[] = { 43fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IRUSR, S_IRUSR }, 44fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IWUSR, S_IWUSR }, 45fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IXUSR, S_IXUSR }, 46fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IRGRP, S_IRGRP }, 47fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IWGRP, S_IWGRP }, 48fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IXGRP, S_IXGRP }, 49fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IROTH, S_IROTH }, 50fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IWOTH, S_IWOTH }, 51fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IXOTH, S_IXOTH }, 52fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { 0, 0 } 53fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o}; 54efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 55fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'ostatic mode_t mode_xlate(__u16 lmode) 56fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o{ 57fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o mode_t mode = 0; 58fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o int i; 59fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o 60fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o for (i=0; mode_table[i].lmask; i++) { 61fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o if (lmode & mode_table[i].lmask) 62fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o mode |= mode_table[i].mask; 63fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o } 64fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o return mode; 65fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o} 66fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o 672e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'ostatic void fix_perms(const char *cmd, const struct ext2_inode *inode, 682e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int fd, const char *name) 692e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 702e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o struct utimbuf ut; 712e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int i; 722e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 732e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (fd != -1) 742e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = fchmod(fd, mode_xlate(inode->i_mode)); 752e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else 762e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = chmod(name, mode_xlate(inode->i_mode)); 772e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (i == -1) 782e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err(cmd, errno, "while setting permissions of %s", name); 792e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 802e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o#ifndef HAVE_FCHOWN 81c5de1d4a0d1a45e3068247192d2297f94d70340fTheodore Ts'o i = chown(name, inode->i_uid, inode->i_gid); 822e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o#else 832e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (fd != -1) 842e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = fchown(fd, inode->i_uid, inode->i_gid); 852e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else 862e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = chown(name, inode->i_uid, inode->i_gid); 872e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o#endif 882e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (i == -1) 892e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err(cmd, errno, "while changing ownership of %s", name); 902e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 912e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (fd != -1) 922e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o close(fd); 932e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 942e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ut.actime = inode->i_atime; 952e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ut.modtime = inode->i_mtime; 962e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (utime(name, &ut) == -1) 972e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err(cmd, errno, "while setting times of %s", name); 982e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 992e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 100b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'ostatic void dump_file(const char *cmdname, ext2_ino_t ino, int fd, 101b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int preserve, char *outname) 102f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 103f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o errcode_t retval; 104fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o struct ext2_inode inode; 1055a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o char buf[8192]; 1065a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o ext2_file_t e2_file; 1074a31c48b827f378f386b28461fd14b41d709e4ebTheodore Ts'o int nbytes; 1084a31c48b827f378f386b28461fd14b41d709e4ebTheodore Ts'o unsigned int got; 109efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 110e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (debugfs_read_inode(ino, &inode, cmdname)) 111fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o return; 112f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 1135a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o retval = ext2fs_file_open(current_fs, ino, 0, &e2_file); 1145a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o if (retval) { 1155a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o com_err(cmdname, retval, "while opening ext2 file"); 116f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 117f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 1185a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o while (1) { 1195a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o retval = ext2fs_file_read(e2_file, buf, sizeof(buf), &got); 120efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o if (retval) 1215a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o com_err(cmdname, retval, "while reading ext2 file"); 1225a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o if (got == 0) 1235a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o break; 1245a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o nbytes = write(fd, buf, got); 125544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o if ((unsigned) nbytes != got) 1265a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o com_err(cmdname, errno, "while writing file"); 127f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 1285a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o retval = ext2fs_file_close(e2_file); 1295a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o if (retval) { 1305a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o com_err(cmdname, retval, "while closing ext2 file"); 1315a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o return; 132f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 133efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 1342e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (preserve) 1352e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o fix_perms("dump_file", &inode, fd, outname); 1362e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else if (fd != 1) 137fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o close(fd); 138efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 139f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 140f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 141f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 142f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ovoid do_dump(int argc, char **argv) 143f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 144b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t inode; 145b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int fd; 146b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int c; 147b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int preserve = 0; 148fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o const char *dump_usage = "Usage: dump_inode [-p] <file> <output_file>"; 149b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o char *in_fn, *out_fn; 150efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 15188494bb6d440f703db98b6cc4452f63d7aa392b9Theodore Ts'o reset_getopt(); 152fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o while ((c = getopt (argc, argv, "p")) != EOF) { 153fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o switch (c) { 154fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o case 'p': 155fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o preserve++; 156fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o break; 157fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o default: 158fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o com_err(argv[0], 0, dump_usage); 159fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o return; 160fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o } 161fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o } 162fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o if (optind != argc-2) { 163fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o com_err(argv[0], 0, dump_usage); 164f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 165f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 166f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 167f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (check_fs_open(argv[0])) 168f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 169f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 170fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o in_fn = argv[optind]; 171fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o out_fn = argv[optind+1]; 172fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o 173fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o inode = string_to_inode(in_fn); 174efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o if (!inode) 175f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 176f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 177819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o fd = open(out_fn, O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE, 0666); 178f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (fd < 0) { 179f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err(argv[0], errno, "while opening %s for dump_inode", 180fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o out_fn); 181f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 182f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 183f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 184fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o dump_file(argv[0], inode, fd, preserve, out_fn); 185f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 186f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 187f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 188f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 189b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'ostatic void rdump_symlink(ext2_ino_t ino, struct ext2_inode *inode, 1902e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o const char *fullname) 1912e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 1922e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ext2_file_t e2_file; 1932e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o char *buf; 1942e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o errcode_t retval; 1952e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 1962e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o buf = malloc(inode->i_size + 1); 1972e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (!buf) { 1982e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while allocating for symlink"); 1992e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2002e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2012e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2022e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* Apparently, this is the right way to detect and handle fast 2032e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o * symlinks; see do_stat() in debugfs.c. */ 2042e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (inode->i_blocks == 0) 2052e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o strcpy(buf, (char *) inode->i_block); 2062e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else { 2072e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o unsigned bytes = inode->i_size; 2082e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o char *p = buf; 2092e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o retval = ext2fs_file_open(current_fs, ino, 0, &e2_file); 2102e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (retval) { 2112e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", retval, "while opening symlink"); 2122e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2132e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2142e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o for (;;) { 2152e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o unsigned int got; 2162e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o retval = ext2fs_file_read(e2_file, p, bytes, &got); 2172e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (retval) { 2182e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", retval, "while reading symlink"); 2192e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2202e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2212e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o bytes -= got; 2222e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o p += got; 2232e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (got == 0 || bytes == 0) 2242e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o break; 2252e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2262e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o buf[inode->i_size] = 0; 2272e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o retval = ext2fs_file_close(e2_file); 2282e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (retval) 2292e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", retval, "while closing symlink"); 2302e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2312e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2322e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (symlink(buf, fullname) == -1) { 2332e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while creating symlink %s -> %s", buf, fullname); 2342e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2352e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2362e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2372e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'oerrout: 2382e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o free(buf); 2392e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 2402e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2412e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'ostatic int rdump_dirent(struct ext2_dir_entry *, int, int, char *, void *); 2422e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 243b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'ostatic void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode, 2442e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o const char *name, const char *dumproot) 2452e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 2462e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o char *fullname; 2472e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2482e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* There are more efficient ways to do this, but this method 2492e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o * requires only minimal debugging. */ 2502e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o fullname = malloc(strlen(dumproot) + strlen(name) + 2); 2512e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (!fullname) { 2522e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while allocating memory"); 2532e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 2542e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2552e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o sprintf(fullname, "%s/%s", dumproot, name); 2562e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2572e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (LINUX_S_ISLNK(inode->i_mode)) 2582e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o rdump_symlink(ino, inode, fullname); 2592e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else if (LINUX_S_ISREG(inode->i_mode)) { 2602e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int fd; 261efac5a7f0d19b06276520b35bc986540eb22c34dTheodore Ts'o fd = open(fullname, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRWXU); 2622e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (fd == -1) { 2632e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while dumping %s", fullname); 2642e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2652e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2662e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o dump_file("rdump", ino, fd, 1, fullname); 2672e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2682e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else if (LINUX_S_ISDIR(inode->i_mode) && strcmp(name, ".") && strcmp(name, "..")) { 2692e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o errcode_t retval; 2702e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2712e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* Create the directory with 0700 permissions, because we 2722e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o * expect to have to create entries it. Then fix its perms 2732e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o * once we've done the traversal. */ 2742e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (mkdir(fullname, S_IRWXU) == -1) { 2752e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while making directory %s", fullname); 2762e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2772e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2782e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2792e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o retval = ext2fs_dir_iterate(current_fs, ino, 0, 0, 2802e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o rdump_dirent, (void *) fullname); 2812e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (retval) 2822e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", retval, "while dumping %s", fullname); 2832e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2842e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o fix_perms("rdump", inode, -1, fullname); 2852e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2862e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* else do nothing (don't dump device files, sockets, fifos, etc.) */ 2872e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2882e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'oerrout: 2892e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o free(fullname); 2902e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 2912e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 292efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic int rdump_dirent(struct ext2_dir_entry *dirent, 293544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int offset EXT2FS_ATTR((unused)), 294544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int blocksize EXT2FS_ATTR((unused)), 295544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o char *buf EXT2FS_ATTR((unused)), void *private) 2962e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 297b772900b4bcff407c883b7bd8419af56be0a9823Brian Behlendorf char name[EXT2_NAME_LEN + 1]; 2982e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int thislen; 2992e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o const char *dumproot = private; 3002e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o struct ext2_inode inode; 3012e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3022e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN 3032e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ? (dirent->name_len & 0xFF) : EXT2_NAME_LEN); 3042e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o strncpy(name, dirent->name, thislen); 3052e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o name[thislen] = 0; 3062e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 307e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (debugfs_read_inode(dirent->inode, &inode, name)) 3082e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return 0; 3092e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3102e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o rdump_inode(dirent->inode, &inode, name, dumproot); 3112e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3122e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return 0; 3132e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 3142e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3152e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'ovoid do_rdump(int argc, char **argv) 3162e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 317b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t ino; 3182e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o struct ext2_inode inode; 3192e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o struct stat st; 3202e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int i; 3212e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o char *p; 3222e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 323e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (common_args_process(argc, argv, 3, 3, "rdump", 324e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o "<directory> <native directory>", 0)) 3252e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3262e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3272e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ino = string_to_inode(argv[1]); 3282e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (!ino) 3292e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3302e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3312e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* Ensure ARGV[2] is a directory. */ 3322e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = stat(argv[2], &st); 3332e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (i == -1) { 3342e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while statting %s", argv[2]); 3352e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3362e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 3372e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (!S_ISDIR(st.st_mode)) { 3382e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", 0, "%s is not a directory", argv[2]); 3392e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3402e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 3412e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 342e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (debugfs_read_inode(ino, &inode, argv[1])) 3432e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3442e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3452e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o p = strrchr(argv[1], '/'); 3462e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (p) 3472e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o p++; 3482e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else 3492e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o p = argv[1]; 3502e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3512e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o rdump_inode(ino, &inode, p, argv[2]); 3522e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 3532e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 354f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ovoid do_cat(int argc, char **argv) 355f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 356b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t inode; 357f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 358e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (common_inode_args_process(argc, argv, &inode, 0)) 359f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 360f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 361fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o fflush(stdout); 362fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o fflush(stderr); 363efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o dump_file(argv[0], inode, 1, 0, argv[2]); 364f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 365f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 366f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 367f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 368