From 87e81f17081bdf9d69895fcbe1dc6bb51b90b668 Mon Sep 17 00:00:00 2001 From: !flatcap Date: Thu, 22 Aug 2002 18:09:47 +0000 Subject: [PATCH] AT_NONAME -> AT_UNNAMED 2002/07/11 16:20:34-00:00 !flatcap whitespace and include guards 2002/07/08 23:27:17-00:00 !flatcap added AT_NONAME so we can search for a (un)named attribute or just iterate through all attributes 2002/07/07 19:44:57-00:00 !antona Change ntfs_read_file_record() not to abort if the inode is not in use. Adapt callers which care to check this themselves. 2002/07/03 21:56:01-00:00 !antona Updates 2002/07/03 14:38:40-00:00 !antona Cleanup the build process a bit. 2002/07/03 11:30:07-00:00 !flatcap moved undelete,logprogs to EXTRA_PROGRAMS 2002/07/02 23:47:11-00:00 !antona Global replacement of __[su]{8,16,32,64} with [su]{8,16,32,64} and layout.h define it. 2002/04/29 01:53:55-00:00 !antona Loads of stuff. Improvements, start on attr pread and attr mst_pread. Write to follow. ntfslabel cleanup and extensions. libntfs cleanups, fixes, etc. 2002/04/21 01:26:39-00:00 !antona Cleanup/streamline include file dependencies. 2002/04/20 23:09:43-00:00 !antona Port attribute lookup functions with attribute list support from ntfs tng driver. Port/reimplement extent mft record handling code as well. Rename out all dollar signs from type names and constants. Adapt all callers to new API. Note mkntfs is currently broken due to some needed work. 2002/04/20 01:53:03-00:00 !antona Rename mft code adding ntfs_ prefix. Change all return values to zero on success. Thanks to mattjf for pointing out the inconsistencies. 2002/04/19 21:09:55-00:00 !antona Finished provisional inode.c::ntfs_{open,close}_inode() functions. Also, started defining API provided by attrib.[ch], so far only done search context related stuff. 2002/04/18 18:15:46-00:00 !antona Define API for bootsect.[ch]: is_boot_sector_ntfs(). 2002/04/16 12:13:53-00:00 !antona New API function mft.[ch]::read_file_record(). Also some cleanups. 2002/04/14 15:26:24-00:00 !antona Remove find_first_attr and make all users use get_attr_search_ctx + find_attr instead. 2001/12/06 01:14:52-00:00 !antona Added mount flags to ntfs_mount and adapted utilities to new mount syntax. 2001/06/16 19:59:51-00:00 !antona Update ntfsdump_logfile and dumplog and the relevant textfiles. 2001/06/16 00:06:17-00:00 !antona dumplog now decodes the first 0x5000 bytes of the logfile given on the command line as fully as possible with the current knowledge of the logfile structures. 2001/06/10 18:30:17-00:00 !antona Preparations for the 0.1.0 release. Updating documentation and information. Updating rpm generation and added mkntfs man page which currently is not accurate as it shows all the mke2fs options in it while mkntfs doesn't actually accept any options except for device at all but it is a good starting point. 2001/06/10 15:54:20-00:00 !antona Linux-NTFS 0.1.0-pre1 ===================== -fixed up ntfsfix and ntfsdump_logfile -corrected stuff -several bug fixes -fixed (hopefully) final bug with mkntfs (sd generator was wrong due to brain'o) -mkntfs now completed, only need to add a few command line options before first public release. -rpm generation file updated and autostrip modified to make use of install-stip make target instead of stripping manually -made bootsector check verbosity during mount dependent on --enable-debug configure option. 2001/06/01 02:07:26-00:00 !antona It has been a long time since last commit. At moment have done a lot of work on mkntfs but also at the moment ntfsfix and ntfsdump_logfile and libntfs are broken. Basically only mkntfs works and that is not complete either. 2001/04/11 15:36:54-00:00 !flatcap fixed typo 2001/04/08 03:02:55-00:00 !antona Added cvs Id header. 2001/04/02 02:04:37-00:00 !antona Everything compiles again! Yey! (Don't know about working though, haven't tried it... So be careful...) The definitely final find_{first_}attr() functions are in place. Currently still no support for attribute lists. The two new _RE files contain the C-fied and more or less (more less than more actually) cleaned up functions from the ntfs driver. Once they are cleaned up (find_attr() is already completed but I left it in the _RE files for future reference/educational value) and modified to suit my ideas of how they should work, which are not quite the same as the driver way, they will make it into attrib.[ch]. If anyone gives the new code a try, I would be interested in whether it worked or not... (-; 2001/03/02 15:06:37-00:00 !antona Full commit of my current dircetory. New files not yet added. 2001/02/02 00:16:18-00:00 !antona Changed make process to using autoconf/automake/libtool. Added necessary files for this and for the gnu standard. Inititial checkin. Probably still stuff missing. Will know soon... 2001/01/27 14:22:02-00:00 !antona Added a logfile dumper as a new utility. Almost finished the first ntfsfix release. (Still missingin CVS are attrib.c for ntfslib and the makefiles to build everything.) Fixes for nested packed structure/union typedefs as gcc doesn't automatically nest the __attribute__ ((__packed__)), even though according to the gcc info page it does. (Thanks to Yuri Per for pointing this out.) (Logical change 1.5) --- ntfstools/ntfsdump_logfile.c | 371 +++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) diff --git a/ntfstools/ntfsdump_logfile.c b/ntfstools/ntfsdump_logfile.c index e69de29b..e785ea96 100644 --- a/ntfstools/ntfsdump_logfile.c +++ b/ntfstools/ntfsdump_logfile.c @@ -0,0 +1,371 @@ +const char *EXEC_NAME = "NtfsDump_LogFile"; +const char *EXEC_VERSION = "1.0"; +/* + * $Id$ + * + * NtfsDump_LogFile - Part of the Linux-NTFS project. + * + * Copyright (c) 2000,2001 Anton Altaparmakov. + * + * This utility will interpret the contents of the journal ($LogFile) of an + * NTFS partition and display the results on stdout. Errors will be output to + * stderr. + * + * Anton Altaparmakov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS source + * in the file COPYING); if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * WARNING: This program might not work on architectures which do not allow + * unaligned access. For those, the program would need to start using + * get/put_unaligned macros (#include ), but not doing it yet, + * since NTFS really mostly applies to ia32 only, which does allow unaligned + * accesses. We might not actually have a problem though, since the structs are + * defined as being packed so that might be enough for gcc to insert the + * correct code. + * + * If anyone using a non-little endian and/or an aligned access only CPU tries + * this program please let me know whether it works or not! + * + * Anton Altaparmakov + */ + +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "attrib.h" +#include "mft.h" +#include "disk_io.h" +#include "logfile.h" +#include "mst.h" + +int main(int argc, char **argv) +{ + MFT_RECORD *m = NULL; + ATTR_RECORD *a; + s64 l; + unsigned char *lfd = NULL; + ntfs_volume *vol = NULL; + ntfs_attr_search_ctx *ctx = NULL; + RESTART_PAGE_HEADER *rph; + RESTART_AREA *rr; + RESTART_CLIENT *cr; + RECORD_PAGE_HEADER *rcrd_ph; + LOG_RECORD *lr; + int pass = 1; + int i, lps, client; + char zero[4096]; + + memset(zero, 0, sizeof(zero)); + printf("\n"); + if (argc != 2) { + printf("%s v%s - Interpret and display information about the " + "journal\n($LogFile) of an NTFS volume.\n\n" + /* Generic copyright / disclaimer. */ + "Copyright (c) 2000, 2001 Anton Altaparmakov.\n\n" + "%s is free software, released under the GNU " + "General Public License\nand you are welcome to " + "redistribute it under certain conditions.\n" + "%s comes with ABSOLUTELY NO WARRANTY; for details " + "read the GNU\nGeneral Public License to be found " + "in the file COPYING in the main Linux-NTFS\n" + "distribution directory.\n\n" + /* Generic part ends here. */ + "Syntax: ntfsdump_logfile partition_or_file_name\n" + " e.g. ntfsdump_logfile /dev/hda6\n\n", + EXEC_NAME, EXEC_VERSION, EXEC_NAME, EXEC_NAME); + fprintf(stderr, "Error: incorrect syntax\n"); + exit(1); + } + vol = ntfs_mount(argv[1], MS_RDONLY); + if (!vol) { + perror("ntfs_mount(MS_RDONLY) failed"); + exit(1); + } + /* Check NTFS version is ok for us. */ + printf("\nNTFS volume version is %i.%i.\n", vol->major_ver, + vol->minor_ver); + switch (vol->major_ver) { + case 1: + if (vol->minor_ver == 1 || vol->minor_ver == 2) + break; + else + goto version_error; + case 2: case 3: + if (vol->minor_ver == 0) + break; + /* Fall through on error. */ + default: +version_error: + fprintf(stderr, "Error: Unknown NTFS version.\n"); + goto error_exit; + } + /* Read in $LogFile. */ + if (ntfs_read_file_record(vol, FILE_LogFile, &m, NULL)) { + fprintf(stderr, "Error reading mft record for $LogFile.\n"); + goto error_exit; + } + if (!(m->flags & MFT_RECORD_IN_USE)) { + fprintf(stderr, "Error: $LogFile has been deleted. Run chkdsk " + "to fix this.\n"); + goto error_exit; + } + ctx = ntfs_get_attr_search_ctx(NULL, m); + if (!ctx) { + perror("Failed to allocate attribute search context"); + goto error_exit; + } + /* Find the $DATA attribute of the $LogFile. */ + if (ntfs_lookup_attr(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + fprintf(stderr, "Error: Attribute $DATA was not found in" \ + "$LogFile!\n"); + goto log_file_error; + } + a = ctx->attr; + /* Get length of $LogFile contents. */ + l = get_attribute_value_length(a); + if (!l) { + puts("$LogFile has zero length, no need to write to disk."); + goto log_file_error; + } + /* Allocate a buffer to hold all of the $LogFile contents. */ + lfd = (unsigned char*)malloc(l); + if (!lfd) { + puts("Not enough memory to load $LogFile."); + goto log_file_error; + } + /* Read in the $LogFile into the buffer. */ + if (l != get_attribute_value(vol, m, a, lfd)) { + puts("Amount of data read does not correspond to expected " + "length!"); + free(lfd); + goto log_file_error; + } + /* Check restart area. */ + if (!is_rstr_recordp(lfd)) { + s64 _l; + + for (_l = 0LL; _l < l; _l++) + if (lfd[_l] != (unsigned char)-1) + break; + if (_l < l) + puts("$LogFile contents are corrupt (magic RSTR " + "missing)!"); + else + puts("$LogFile is empty."); + goto log_file_error; + } + /* Do the interpretation and display now. */ + rph = (RESTART_PAGE_HEADER*)lfd; + lps = le32_to_cpu(rph->log_page_size); +pass_loc: + if (ntfs_post_read_mst_fixup((NTFS_RECORD*)rph, lps) || + is_baad_record(rph->magic)) { + puts("$LogFile incomplete multi sector transfer detected! " + "Cannot handle this yet!"); + goto log_file_error; + } + if ((pass == 2) && !memcmp(lfd, rph, lps)) { + printf("2nd restart area fully matches the 1st one. Skipping " + "display.\n"); + goto skip_rstr_pass; + } + if (le16_to_cpu(rph->major_ver != 1) || + le16_to_cpu(rph->minor_ver != 1)) { + fprintf(stderr, "$LogFile version %i.%i! Error: Unknown " + "$LogFile version!\n", + le16_to_cpu(rph->major_ver), + le16_to_cpu(rph->minor_ver)); + goto log_file_error; + } + rr = (RESTART_AREA*)((char*)rph + le16_to_cpu(rph->restart_offset)); + cr = (RESTART_CLIENT*)((char*)rr + + le16_to_cpu(rr->client_array_offset)); + /* Dump of the interpreted $LogFile restart area. */ + if (pass == 1) + printf("\n$LogFile version %i.%i.\n", + le16_to_cpu(rph->major_ver), + le16_to_cpu(rph->minor_ver)); + printf("\n%s restart area:\n", pass == 1? "1st": "2nd"); + printf("magic = RSTR\n"); + printf("ChkDskLsn = 0x%Lx\n", sle64_to_cpu(rph->chkdsk_lsn)); + printf("SystemPageSize = %u\n", le32_to_cpu(rph->system_page_size)); + printf("LogPageSize = %u\n", le32_to_cpu(rph->log_page_size)); + printf("RestartOffset = 0x%x\n", le16_to_cpu(rph->restart_offset)); + printf("\n(1st) restart record:\n"); + printf("CurrentLsn = %Lx\n", sle64_to_cpu(rr->current_lsn)); + printf("LogClients = %u\n", le16_to_cpu(rr->log_clients)); + printf("ClientFreeList = %i\n", sle16_to_cpu(rr->client_free_list)); + printf("ClientInUseList = %i\n", sle16_to_cpu(rr->client_in_use_list)); + printf("Flags = 0x%x\n", le16_to_cpu(rr->flags)); + printf("SeqNumberBits = %u (0x%x)\n", le32_to_cpu(rr->seq_number_bits), + le32_to_cpu(rr->seq_number_bits)); + printf("RestartAreaLength = 0x%x\n", + le16_to_cpu(rr->restart_area_length)); + printf("ClientArrayOffset = 0x%x\n", + le16_to_cpu(rr->client_array_offset)); + printf("FileSize = %Lu (0x%Lx)\n", le64_to_cpu(rr->file_size), + le64_to_cpu(rr->file_size)); + if (le64_to_cpu(rr->file_size) != l) + puts("$LogFile restart area indicates a log file size" + "different from the actual size!"); + printf("LastLsnDataLength = 0x%x\n", + le32_to_cpu(rr->last_lsn_data_length)); + printf("RecordLength = 0x%x\n", le16_to_cpu(rr->record_length)); + printf("LogPageDataOffset = 0x%x\n", + le16_to_cpu(rr->log_page_data_offset)); + for (client = 0; client < le16_to_cpu(rr->log_clients); client++) { + printf("\nRestart client record number %i:\n", client); + printf("OldestLsn = 0x%Lx\n", sle64_to_cpu(cr->oldest_lsn)); + printf("ClientRestartLsn = 0x%Lx\n", + sle64_to_cpu(cr->client_restart_lsn)); + printf("PrevClient = %i\n", sle16_to_cpu(cr->prev_client)); + printf("NextClient = %i\n", sle16_to_cpu(cr->next_client)); + printf("SeqNumber = 0x%Lx\n", le64_to_cpu(cr->seq_number)); + printf("ClientNameLength = 0x%x\n", + le32_to_cpu(cr->client_name_length)); + if (le32_to_cpu(cr->client_name_length)) { + // convert to ascii and print out. + // printf("ClientName = %u\n", le16_to_cpu(cr->client_name)); + } + /* Size of a restart client record is fixed at 0xa0 bytes. */ + cr = (RESTART_CLIENT*)((char*)cr + 0xa0); + } +skip_rstr_pass: + if (pass == 1) { + rph = (RESTART_PAGE_HEADER*)((char*)rph + lps); + ++pass; + goto pass_loc; + } + rcrd_ph = (RECORD_PAGE_HEADER*)rph; + /* Reuse pass for log record clienter. */ + pass = 0; + printf("\nFinished with restart area. Beginning with log area.\n"); +rcrd_pass_loc: + rcrd_ph = (RECORD_PAGE_HEADER*)((char*)rcrd_ph + lps); + if ((char*)rcrd_ph + lps > (char*)lfd + l) + goto end_of_rcrd_passes; + printf("\nLog record page number %i", pass); + if (!is_rcrd_record(rcrd_ph->magic)) { + for (i = 0; i < lps; i++) + if (((char*)rcrd_ph)[i] != (char)-1) + break; + if (i < lps) + puts(" is corrupt (magic RCRD is missing)."); + else + puts(" is empty."); + pass++; + goto rcrd_pass_loc; + } else + printf(":"); + /* Dump log record page */ + printf("\nmagic = RCRD\n"); + printf("copy.last_lsn/file_offset = 0x%Lx\n", + le64_to_cpu(rcrd_ph->copy.last_lsn)); + printf("flags = 0x%x\n", le32_to_cpu(rcrd_ph->flags)); + printf("page count = %i\n", le16_to_cpu(rcrd_ph->page_count)); + printf("page position = %i\n", le16_to_cpu(rcrd_ph->page_position)); + printf("header.next_record_offset = 0x%Lx\n", + le64_to_cpu(rcrd_ph->header.packed.next_record_offset)); + printf("header.last_end_lsn = 0x%Lx\n", + le64_to_cpu(rcrd_ph->header.packed.last_end_lsn)); + /* + * Where does the 0x40 come from? Is it just usa_offset + + * usa_client * 2 + 7 & ~7 or is it derived from somewhere? + */ + lr = (LOG_RECORD*)((char*)rcrd_ph + 0x40); + client = 0; +log_record_pass: + printf("\nLog record %i:\n", client); + printf("this lsn = 0x%Lx\n", le64_to_cpu(lr->this_lsn)); + printf("client previous lsn = 0x%Lx\n", + le64_to_cpu(lr->client_previous_lsn)); + printf("client undo next lsn = 0x%Lx\n", + le64_to_cpu(lr->client_undo_next_lsn)); + printf("client data length = 0x%x\n", + le32_to_cpu(lr->client_data_length)); + printf("client_id.seq_number = 0x%x\n", + le16_to_cpu(lr->client_id.seq_number)); + printf("client_id.client_index = 0x%x\n", + le16_to_cpu(lr->client_id.client_index)); + printf("record type = 0x%x\n", le32_to_cpu(lr->record_type)); + printf("transaction_id = 0x%x\n", le32_to_cpu(lr->transaction_id)); + printf("flags = 0x%x:", lr->flags); + if (!lr->flags) + printf(" NONE\n"); + else { + int _b = 0; + + if (lr->flags & LOG_RECORD_MULTI_PAGE) { + printf(" LOG_RECORD_MULTI_PAGE"); + _b = 1; + } + if (lr->flags & ~LOG_RECORD_MULTI_PAGE) { + if (_b) + printf(" |"); + printf(" Unknown flags"); + } + printf("\n"); + } + printf("redo_operation = 0x%x\n", le16_to_cpu(lr->redo_operation)); + printf("undo_operation = 0x%x\n", le16_to_cpu(lr->undo_operation)); + printf("redo_offset = 0x%x\n", le16_to_cpu(lr->redo_offset)); + printf("redo_length = 0x%x\n", le16_to_cpu(lr->redo_length)); + printf("undo_offset = 0x%x\n", le16_to_cpu(lr->undo_offset)); + printf("undo_length = 0x%x\n", le16_to_cpu(lr->undo_length)); + printf("target_attribute = 0x%x\n", le16_to_cpu(lr->target_attribute)); + printf("lcns_to_follow = 0x%x\n", le16_to_cpu(lr->lcns_to_follow)); + printf("record_offset = 0x%x\n", le16_to_cpu(lr->record_offset)); + printf("attribute_offset = 0x%x\n", le16_to_cpu(lr->attribute_offset)); + printf("target_vcn = 0x%Lx\n", sle64_to_cpu(lr->target_vcn)); + if (le16_to_cpu(lr->lcns_to_follow) > 0) + printf("Array of lcns:\n"); + for (i = 0; i < le16_to_cpu(lr->lcns_to_follow); i++) + printf("lcn_list[%i].lcn = 0x%Lx\n", i, + sle64_to_cpu(lr->lcn_list[i].lcn)); + client++; + lr = (LOG_RECORD*)((char*)lr + 0x70); + if (((char*)lr + 0x70 <= (char*)rcrd_ph + + le64_to_cpu(rcrd_ph->header.packed.next_record_offset))) + goto log_record_pass; + pass++; + goto rcrd_pass_loc; +end_of_rcrd_passes: +log_file_error: + printf("\n"); + /* Set return code to 0. */ + i = 0; +final_exit: + if (lfd) + free(lfd); + if (ctx) + ntfs_put_attr_search_ctx(ctx); + if (m) + free(m); + if (vol && ntfs_umount(vol, 0)) + ntfs_umount(vol, 1); + return i; +error_exit: + i = 1; + goto final_exit; +} +