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 8e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifndef _GNU_SOURCE 9efac5a7f0d19b06276520b35bc986540eb22c34dTheodore Ts'o#define _GNU_SOURCE /* for O_LARGEFILE */ 10e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif 11efac5a7f0d19b06276520b35bc986540eb22c34dTheodore Ts'o 12f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <stdio.h> 13f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <unistd.h> 14f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <stdlib.h> 15f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <ctype.h> 16f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <string.h> 17f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <time.h> 1850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#ifdef HAVE_ERRNO_H 1950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#include <errno.h> 2050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#endif 21f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h> 22f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/stat.h> 23f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <fcntl.h> 24fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o#include <utime.h> 25fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o#ifdef HAVE_GETOPT_H 26fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o#include <getopt.h> 27efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o#else 28fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'oextern int optind; 29fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'oextern char *optarg; 30fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o#endif 31f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 32f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include "debugfs.h" 33f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 34819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#ifndef O_LARGEFILE 35819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#define O_LARGEFILE 0 36819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#endif 37819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o 38fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o/* 39fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o * The mode_xlate function translates a linux mode into a native-OS mode_t. 40fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o */ 41fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'ostatic struct { 42fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o __u16 lmask; 43fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o mode_t mask; 44fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o} mode_table[] = { 45fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IRUSR, S_IRUSR }, 46fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IWUSR, S_IWUSR }, 47fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IXUSR, S_IXUSR }, 48fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IRGRP, S_IRGRP }, 49fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IWGRP, S_IWGRP }, 50fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IXGRP, S_IXGRP }, 51fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IROTH, S_IROTH }, 52fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IWOTH, S_IWOTH }, 53fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { LINUX_S_IXOTH, S_IXOTH }, 54fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o { 0, 0 } 55fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o}; 56efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 57fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'ostatic mode_t mode_xlate(__u16 lmode) 58fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o{ 59fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o mode_t mode = 0; 60fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o int i; 61fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o 62fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o for (i=0; mode_table[i].lmask; i++) { 63fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o if (lmode & mode_table[i].lmask) 64fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o mode |= mode_table[i].mask; 65fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o } 66fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o return mode; 67fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o} 68fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o 692e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'ostatic void fix_perms(const char *cmd, const struct ext2_inode *inode, 702e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int fd, const char *name) 712e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 722e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o struct utimbuf ut; 732e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int i; 742e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 752e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (fd != -1) 762e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = fchmod(fd, mode_xlate(inode->i_mode)); 772e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else 782e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = chmod(name, mode_xlate(inode->i_mode)); 792e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (i == -1) 802e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err(cmd, errno, "while setting permissions of %s", name); 812e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 822e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o#ifndef HAVE_FCHOWN 83c5de1d4a0d1a45e3068247192d2297f94d70340fTheodore Ts'o i = chown(name, inode->i_uid, inode->i_gid); 842e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o#else 852e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (fd != -1) 862e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = fchown(fd, inode->i_uid, inode->i_gid); 872e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else 882e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = chown(name, inode->i_uid, inode->i_gid); 892e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o#endif 902e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (i == -1) 912e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err(cmd, errno, "while changing ownership of %s", name); 922e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 932e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (fd != -1) 942e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o close(fd); 952e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 962e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ut.actime = inode->i_atime; 972e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ut.modtime = inode->i_mtime; 982e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (utime(name, &ut) == -1) 992e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err(cmd, errno, "while setting times of %s", name); 1002e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 1012e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 102b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'ostatic void dump_file(const char *cmdname, ext2_ino_t ino, int fd, 103b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int preserve, char *outname) 104f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 105f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o errcode_t retval; 106fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o struct ext2_inode inode; 107e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall char *buf = 0; 1085a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o ext2_file_t e2_file; 1094a31c48b827f378f386b28461fd14b41d709e4ebTheodore Ts'o int nbytes; 110e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall unsigned int got, blocksize = current_fs->blocksize; 111efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 112e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (debugfs_read_inode(ino, &inode, cmdname)) 113fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o return; 114f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 1155a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o retval = ext2fs_file_open(current_fs, ino, 0, &e2_file); 1165a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o if (retval) { 1175a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o com_err(cmdname, retval, "while opening ext2 file"); 118f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 119f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 120e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall retval = ext2fs_get_mem(blocksize, &buf); 121e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall if (retval) { 122e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall com_err(cmdname, retval, "while allocating memory"); 123e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall return; 124e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall } 1255a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o while (1) { 126e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall retval = ext2fs_file_read(e2_file, buf, blocksize, &got); 127efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o if (retval) 1285a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o com_err(cmdname, retval, "while reading ext2 file"); 1295a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o if (got == 0) 1305a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o break; 1315a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o nbytes = write(fd, buf, got); 132544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o if ((unsigned) nbytes != got) 1335a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o com_err(cmdname, errno, "while writing file"); 134f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 135e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall if (buf) 136e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall ext2fs_free_mem(&buf); 1375a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o retval = ext2fs_file_close(e2_file); 1385a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o if (retval) { 1395a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o com_err(cmdname, retval, "while closing ext2 file"); 1405a51384ef2cdcb2d49965c841ff558afc1f4ee01Theodore Ts'o return; 141f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 142efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 1432e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (preserve) 1442e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o fix_perms("dump_file", &inode, fd, outname); 145efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 146f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 147f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 148f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 149f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ovoid do_dump(int argc, char **argv) 150f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 151b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t inode; 152b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int fd; 153b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int c; 154b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int preserve = 0; 155b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o char *in_fn, *out_fn; 156efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 15788494bb6d440f703db98b6cc4452f63d7aa392b9Theodore Ts'o reset_getopt(); 158fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o while ((c = getopt (argc, argv, "p")) != EOF) { 159fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o switch (c) { 160fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o case 'p': 161fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o preserve++; 162fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o break; 163fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o default: 1645299580c1ced39e7a6d7ac2717a3d6a3cab299b0Theodore Ts'o print_usage: 1655299580c1ced39e7a6d7ac2717a3d6a3cab299b0Theodore Ts'o com_err(argv[0], 0, "Usage: dump_inode [-p] " 1665299580c1ced39e7a6d7ac2717a3d6a3cab299b0Theodore Ts'o "<file> <output_file>"); 167fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o return; 168fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o } 169fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o } 1705299580c1ced39e7a6d7ac2717a3d6a3cab299b0Theodore Ts'o if (optind != argc-2) 1715299580c1ced39e7a6d7ac2717a3d6a3cab299b0Theodore Ts'o goto print_usage; 172f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 173f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (check_fs_open(argv[0])) 174f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 175f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 176fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o in_fn = argv[optind]; 177fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o out_fn = argv[optind+1]; 178fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o 179fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o inode = string_to_inode(in_fn); 180efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o if (!inode) 181f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 182f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 183819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o fd = open(out_fn, O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE, 0666); 184f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (fd < 0) { 185f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err(argv[0], errno, "while opening %s for dump_inode", 186fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o out_fn); 187f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 188f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 189f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 190fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o dump_file(argv[0], inode, fd, preserve, out_fn); 191e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall if (close(fd) != 0) { 192e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall com_err(argv[0], errno, "while closing %s for dump_inode", 193e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall out_fn); 194e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall return; 195e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall } 196f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 197f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 198f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 199f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 200b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'ostatic void rdump_symlink(ext2_ino_t ino, struct ext2_inode *inode, 2012e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o const char *fullname) 2022e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 2032e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ext2_file_t e2_file; 2042e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o char *buf; 2052e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o errcode_t retval; 2062e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2072e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o buf = malloc(inode->i_size + 1); 2082e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (!buf) { 2092e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while allocating for symlink"); 2102e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2112e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2122e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2132e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* Apparently, this is the right way to detect and handle fast 2142e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o * symlinks; see do_stat() in debugfs.c. */ 2152e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (inode->i_blocks == 0) 2162e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o strcpy(buf, (char *) inode->i_block); 2172e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else { 2182e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o unsigned bytes = inode->i_size; 2192e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o char *p = buf; 2202e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o retval = ext2fs_file_open(current_fs, ino, 0, &e2_file); 2212e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (retval) { 2222e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", retval, "while opening symlink"); 2232e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2242e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2252e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o for (;;) { 2262e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o unsigned int got; 2272e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o retval = ext2fs_file_read(e2_file, p, bytes, &got); 2282e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (retval) { 2292e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", retval, "while reading symlink"); 2302e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2312e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2322e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o bytes -= got; 2332e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o p += got; 2342e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (got == 0 || bytes == 0) 2352e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o break; 2362e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2372e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o buf[inode->i_size] = 0; 2382e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o retval = ext2fs_file_close(e2_file); 2392e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (retval) 2402e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", retval, "while closing symlink"); 2412e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2422e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2432e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (symlink(buf, fullname) == -1) { 2442e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while creating symlink %s -> %s", buf, fullname); 2452e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2462e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2472e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2482e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'oerrout: 2492e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o free(buf); 2502e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 2512e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2522e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'ostatic int rdump_dirent(struct ext2_dir_entry *, int, int, char *, void *); 2532e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 254b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'ostatic void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode, 2552e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o const char *name, const char *dumproot) 2562e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 2572e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o char *fullname; 2582e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2592e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* There are more efficient ways to do this, but this method 2602e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o * requires only minimal debugging. */ 2612e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o fullname = malloc(strlen(dumproot) + strlen(name) + 2); 2622e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (!fullname) { 2632e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while allocating memory"); 2642e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 2652e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2662e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o sprintf(fullname, "%s/%s", dumproot, name); 2672e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2682e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (LINUX_S_ISLNK(inode->i_mode)) 2692e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o rdump_symlink(ino, inode, fullname); 2702e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else if (LINUX_S_ISREG(inode->i_mode)) { 2712e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int fd; 272efac5a7f0d19b06276520b35bc986540eb22c34dTheodore Ts'o fd = open(fullname, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRWXU); 2732e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (fd == -1) { 2742e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while dumping %s", fullname); 2752e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2762e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2772e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o dump_file("rdump", ino, fd, 1, fullname); 278e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall if (close(fd) != 0) { 279e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall com_err("rdump", errno, "while dumping %s", fullname); 280e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall goto errout; 281e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall } 2822e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2832e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else if (LINUX_S_ISDIR(inode->i_mode) && strcmp(name, ".") && strcmp(name, "..")) { 2842e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o errcode_t retval; 2852e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2862e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* Create the directory with 0700 permissions, because we 2872e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o * expect to have to create entries it. Then fix its perms 2882e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o * once we've done the traversal. */ 2892e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (mkdir(fullname, S_IRWXU) == -1) { 2902e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while making directory %s", fullname); 2912e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o goto errout; 2922e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 2932e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2942e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o retval = ext2fs_dir_iterate(current_fs, ino, 0, 0, 2952e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o rdump_dirent, (void *) fullname); 2962e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (retval) 2972e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", retval, "while dumping %s", fullname); 2982e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 2992e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o fix_perms("rdump", inode, -1, fullname); 3002e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 3012e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* else do nothing (don't dump device files, sockets, fifos, etc.) */ 3022e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3032e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'oerrout: 3042e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o free(fullname); 3052e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 3062e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 307efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic int rdump_dirent(struct ext2_dir_entry *dirent, 308544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int offset EXT2FS_ATTR((unused)), 309544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int blocksize EXT2FS_ATTR((unused)), 310544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o char *buf EXT2FS_ATTR((unused)), void *private) 3112e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 312b772900b4bcff407c883b7bd8419af56be0a9823Brian Behlendorf char name[EXT2_NAME_LEN + 1]; 3132e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int thislen; 3142e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o const char *dumproot = private; 3152e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o struct ext2_inode inode; 3162e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 317e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall thislen = dirent->name_len & 0xFF; 3182e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o strncpy(name, dirent->name, thislen); 3192e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o name[thislen] = 0; 3202e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 321e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (debugfs_read_inode(dirent->inode, &inode, name)) 3222e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return 0; 3232e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3242e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o rdump_inode(dirent->inode, &inode, name, dumproot); 3252e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3262e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return 0; 3272e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 3282e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3292e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'ovoid do_rdump(int argc, char **argv) 3302e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o{ 331b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t ino; 3322e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o struct ext2_inode inode; 3332e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o struct stat st; 3342e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o int i; 3352e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o char *p; 3362e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 337e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (common_args_process(argc, argv, 3, 3, "rdump", 338e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o "<directory> <native directory>", 0)) 3392e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3402e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3412e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o ino = string_to_inode(argv[1]); 3422e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (!ino) 3432e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3442e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3452e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o /* Ensure ARGV[2] is a directory. */ 3462e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o i = stat(argv[2], &st); 3472e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (i == -1) { 3482e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", errno, "while statting %s", argv[2]); 3492e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3502e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 3512e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (!S_ISDIR(st.st_mode)) { 3522e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o com_err("rdump", 0, "%s is not a directory", argv[2]); 3532e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3542e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o } 3552e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 356e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (debugfs_read_inode(ino, &inode, argv[1])) 3572e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o return; 3582e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3592e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o p = strrchr(argv[1], '/'); 3602e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o if (p) 3612e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o p++; 3622e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o else 3632e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o p = argv[1]; 3642e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 3652e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o rdump_inode(ino, &inode, p, argv[2]); 3662e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o} 3672e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o 368f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ovoid do_cat(int argc, char **argv) 369f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 370b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t inode; 371f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 372e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (common_inode_args_process(argc, argv, &inode, 0)) 373f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 374f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 375fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o fflush(stdout); 376fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o fflush(stderr); 377efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o dump_file(argv[0], inode, 1, 0, argv[2]); 378f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 379f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 380f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 381f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 382