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 <yuri@acronis.com> for pointing this out.)

(Logical change 1.5)
edge.strict_endians
!flatcap 2002-08-22 18:09:47 +00:00
parent 39a5dcc1e4
commit 87e81f1708
1 changed files with 371 additions and 0 deletions

View File

@ -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 <aia21@cantab.net>
*
* 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 <asm/unaligned.h>), 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 <aia21@cantab.net>
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#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;
}