1987da915Sopenharmony_ci/**
2987da915Sopenharmony_ci * ntfsdump_logfile - Part of the Linux-NTFS project.
3987da915Sopenharmony_ci *
4987da915Sopenharmony_ci * Copyright (c) 2000-2005 Anton Altaparmakov
5987da915Sopenharmony_ci *
6987da915Sopenharmony_ci * This utility will interpret the contents of the journal ($LogFile) of an
7987da915Sopenharmony_ci * NTFS partition and display the results on stdout.  Errors will be output to
8987da915Sopenharmony_ci * stderr.
9987da915Sopenharmony_ci *
10987da915Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
11987da915Sopenharmony_ci * it under the terms of the GNU General Public License as published by
12987da915Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
13987da915Sopenharmony_ci * (at your option) any later version.
14987da915Sopenharmony_ci *
15987da915Sopenharmony_ci * This program is distributed in the hope that it will be useful,
16987da915Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
17987da915Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18987da915Sopenharmony_ci * GNU General Public License for more details.
19987da915Sopenharmony_ci *
20987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License
21987da915Sopenharmony_ci * along with this program (in the main directory of the Linux-NTFS source
22987da915Sopenharmony_ci * in the file COPYING); if not, write to the Free Software Foundation,
23987da915Sopenharmony_ci * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24987da915Sopenharmony_ci */
25987da915Sopenharmony_ci/* TODO:
26987da915Sopenharmony_ci *	- Remove the need for clipping at 64MiB.
27987da915Sopenharmony_ci *	- Add normal command line switchs (use getopt_long()).
28987da915Sopenharmony_ci *	- For a volume: allow dumping only uncommitted records.
29987da915Sopenharmony_ci *	- For a file:   get an optional command line parameter for the last SN.
30987da915Sopenharmony_ci *	- Sanity checks.
31987da915Sopenharmony_ci */
32987da915Sopenharmony_ci
33987da915Sopenharmony_ci#include "config.h"
34987da915Sopenharmony_ci
35987da915Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H
36987da915Sopenharmony_ci#include <sys/types.h>
37987da915Sopenharmony_ci#endif
38987da915Sopenharmony_ci#ifdef HAVE_SYS_STAT_H
39987da915Sopenharmony_ci#include <sys/stat.h>
40987da915Sopenharmony_ci#endif
41987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H
42987da915Sopenharmony_ci#include <unistd.h>
43987da915Sopenharmony_ci#endif
44987da915Sopenharmony_ci#ifdef HAVE_STDARG_H
45987da915Sopenharmony_ci#include <stdarg.h>
46987da915Sopenharmony_ci#endif
47987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H
48987da915Sopenharmony_ci#include <stdlib.h>
49987da915Sopenharmony_ci#endif
50987da915Sopenharmony_ci#ifdef HAVE_STDIO_H
51987da915Sopenharmony_ci#include <stdio.h>
52987da915Sopenharmony_ci#endif
53987da915Sopenharmony_ci#ifdef HAVE_STRING_H
54987da915Sopenharmony_ci#include <string.h>
55987da915Sopenharmony_ci#endif
56987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H
57987da915Sopenharmony_ci#include <errno.h>
58987da915Sopenharmony_ci#endif
59987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H
60987da915Sopenharmony_ci#include <fcntl.h>
61987da915Sopenharmony_ci#endif
62987da915Sopenharmony_ci
63987da915Sopenharmony_ci#include "types.h"
64987da915Sopenharmony_ci#include "endians.h"
65987da915Sopenharmony_ci#include "volume.h"
66987da915Sopenharmony_ci#include "inode.h"
67987da915Sopenharmony_ci#include "attrib.h"
68987da915Sopenharmony_ci#include "layout.h"
69987da915Sopenharmony_ci#include "logfile.h"
70987da915Sopenharmony_ci#include "mst.h"
71987da915Sopenharmony_ci#include "utils.h"
72987da915Sopenharmony_ci/* #include "version.h" */
73987da915Sopenharmony_ci#include "logging.h"
74987da915Sopenharmony_ci
75987da915Sopenharmony_citypedef struct {
76987da915Sopenharmony_ci	BOOL is_volume;
77987da915Sopenharmony_ci	const char *filename;
78987da915Sopenharmony_ci	s64 data_size;
79987da915Sopenharmony_ci	union {
80987da915Sopenharmony_ci		struct {
81987da915Sopenharmony_ci			ntfs_volume *vol;
82987da915Sopenharmony_ci			ntfs_inode *ni;
83987da915Sopenharmony_ci			ntfs_attr *na;
84987da915Sopenharmony_ci		};
85987da915Sopenharmony_ci		struct {
86987da915Sopenharmony_ci			int fd;
87987da915Sopenharmony_ci		};
88987da915Sopenharmony_ci	};
89987da915Sopenharmony_ci} logfile_file;
90987da915Sopenharmony_ci
91987da915Sopenharmony_ci/**
92987da915Sopenharmony_ci * logfile_close
93987da915Sopenharmony_ci */
94987da915Sopenharmony_cistatic int logfile_close(logfile_file *logfile)
95987da915Sopenharmony_ci{
96987da915Sopenharmony_ci	if (logfile->is_volume) {
97987da915Sopenharmony_ci		if (logfile->na)
98987da915Sopenharmony_ci			ntfs_attr_close(logfile->na);
99987da915Sopenharmony_ci		if (logfile->ni && ntfs_inode_close(logfile->ni))
100987da915Sopenharmony_ci			ntfs_log_perror("Warning: Failed to close $LogFile "
101987da915Sopenharmony_ci					"(inode %i)", FILE_LogFile);
102987da915Sopenharmony_ci		if (ntfs_umount(logfile->vol, 0))
103987da915Sopenharmony_ci			ntfs_log_perror("Warning: Failed to umount %s",
104987da915Sopenharmony_ci				logfile->filename);
105987da915Sopenharmony_ci	} else {
106987da915Sopenharmony_ci		if (close(logfile->fd))
107987da915Sopenharmony_ci			ntfs_log_perror("Warning: Failed to close file %s",
108987da915Sopenharmony_ci				logfile->filename);
109987da915Sopenharmony_ci	}
110987da915Sopenharmony_ci	return 0;
111987da915Sopenharmony_ci}
112987da915Sopenharmony_ci
113987da915Sopenharmony_ci/**
114987da915Sopenharmony_ci * device_err_exit - put an error message, cleanup and exit.
115987da915Sopenharmony_ci * @vol: volume to unmount.
116987da915Sopenharmony_ci * @ni:  Inode to free.
117987da915Sopenharmony_ci * @na:  Attribute to close.
118987da915Sopenharmony_ci *
119987da915Sopenharmony_ci * Use when you wish to exit and collate all the cleanups together.
120987da915Sopenharmony_ci * if you don't have some parameter to pass, just pass NULL.
121987da915Sopenharmony_ci */
122987da915Sopenharmony_ci__attribute__((noreturn))
123987da915Sopenharmony_ci__attribute__((format(printf, 4, 5)))
124987da915Sopenharmony_cistatic void device_err_exit(ntfs_volume *vol, ntfs_inode *ni,
125987da915Sopenharmony_ci		ntfs_attr *na, const char *fmt, ...)
126987da915Sopenharmony_ci{
127987da915Sopenharmony_ci	va_list ap;
128987da915Sopenharmony_ci
129987da915Sopenharmony_ci	if (na)
130987da915Sopenharmony_ci		ntfs_attr_close(na);
131987da915Sopenharmony_ci	if (ni && ntfs_inode_close(ni))
132987da915Sopenharmony_ci		ntfs_log_perror("Warning: Failed to close $LogFile (inode %i)",
133987da915Sopenharmony_ci			FILE_LogFile);
134987da915Sopenharmony_ci	if (ntfs_umount(vol, 0))
135987da915Sopenharmony_ci		ntfs_log_perror("Warning: Failed to umount");
136987da915Sopenharmony_ci
137987da915Sopenharmony_ci	fprintf(stderr, "ERROR: ");
138987da915Sopenharmony_ci	va_start(ap, fmt);
139987da915Sopenharmony_ci	vfprintf(stderr, fmt, ap);
140987da915Sopenharmony_ci	va_end(ap);
141987da915Sopenharmony_ci
142987da915Sopenharmony_ci	ntfs_log_error("Aborting...\n");
143987da915Sopenharmony_ci	exit(1);
144987da915Sopenharmony_ci}
145987da915Sopenharmony_ci
146987da915Sopenharmony_ci/**
147987da915Sopenharmony_ci * log_err_exit -
148987da915Sopenharmony_ci */
149987da915Sopenharmony_ci__attribute__((noreturn))
150987da915Sopenharmony_ci__attribute__((format(printf, 2, 3)))
151987da915Sopenharmony_cistatic void log_err_exit(u8 *buf, const char *fmt, ...)
152987da915Sopenharmony_ci{
153987da915Sopenharmony_ci	va_list ap;
154987da915Sopenharmony_ci
155987da915Sopenharmony_ci	free(buf);
156987da915Sopenharmony_ci
157987da915Sopenharmony_ci	fprintf(stderr, "ERROR: ");
158987da915Sopenharmony_ci	va_start(ap, fmt);
159987da915Sopenharmony_ci	vfprintf(stderr, fmt, ap);
160987da915Sopenharmony_ci	va_end(ap);
161987da915Sopenharmony_ci
162987da915Sopenharmony_ci	ntfs_log_error("Aborting...\n");
163987da915Sopenharmony_ci	exit(1);
164987da915Sopenharmony_ci}
165987da915Sopenharmony_ci
166987da915Sopenharmony_ci/**
167987da915Sopenharmony_ci * usage -
168987da915Sopenharmony_ci */
169987da915Sopenharmony_ci__attribute__((noreturn))
170987da915Sopenharmony_cistatic void usage(const char *exec_name)
171987da915Sopenharmony_ci{
172987da915Sopenharmony_ci	ntfs_log_error("%s v%s (libntfs-3g) - Interpret and display information "
173987da915Sopenharmony_ci			"about the journal\n($LogFile) of an NTFS volume.\n"
174987da915Sopenharmony_ci			"Copyright (c) 2000-2005 Anton Altaparmakov.\n"
175987da915Sopenharmony_ci			"%s is free software, released under the GNU General "
176987da915Sopenharmony_ci			"Public License\nand you are welcome to redistribute "
177987da915Sopenharmony_ci			"it under certain conditions.\n%s comes with "
178987da915Sopenharmony_ci			"ABSOLUTELY NO WARRANTY; for details read the GNU\n"
179987da915Sopenharmony_ci			"General Public License to be found in the file "
180987da915Sopenharmony_ci			"COPYING in the main Linux-NTFS\ndistribution "
181987da915Sopenharmony_ci			"directory.\nUsage: %s device\n    e.g. %s /dev/hda6\n"
182987da915Sopenharmony_ci			"Alternative usage: %s -f file\n    e.g. %s -f "
183987da915Sopenharmony_ci			"MyCopyOfTheLogFile\n", exec_name, VERSION,
184987da915Sopenharmony_ci			exec_name, exec_name,
185987da915Sopenharmony_ci			exec_name, exec_name, exec_name, exec_name);
186987da915Sopenharmony_ci	exit(1);
187987da915Sopenharmony_ci}
188987da915Sopenharmony_ci
189987da915Sopenharmony_ci/**
190987da915Sopenharmony_ci * logfile_open
191987da915Sopenharmony_ci */
192987da915Sopenharmony_cistatic int logfile_open(BOOL is_volume, const char *filename,
193987da915Sopenharmony_ci		logfile_file *logfile)
194987da915Sopenharmony_ci{
195987da915Sopenharmony_ci	if (is_volume) {
196987da915Sopenharmony_ci		ntfs_volume *vol;
197987da915Sopenharmony_ci		ntfs_inode *ni;
198987da915Sopenharmony_ci		ntfs_attr *na;
199987da915Sopenharmony_ci
200987da915Sopenharmony_ci		/* Porting note: NTFS_MNT_FORENSIC is not needed when we mount
201987da915Sopenharmony_ci		 * the volume in read-only mode. No changes will be made to the
202987da915Sopenharmony_ci		 * logfile or anything else when we are in read only-mode. */
203987da915Sopenharmony_ci		vol = ntfs_mount(filename, NTFS_MNT_RDONLY);
204987da915Sopenharmony_ci		if (!vol)
205987da915Sopenharmony_ci			log_err_exit(NULL, "Failed to mount %s: %s\n",
206987da915Sopenharmony_ci					filename, strerror(errno));
207987da915Sopenharmony_ci		ntfs_log_info("Mounted NTFS volume %s (NTFS v%i.%i) on device %s.\n",
208987da915Sopenharmony_ci				vol->vol_name ? vol->vol_name : "<NO_NAME>",
209987da915Sopenharmony_ci				vol->major_ver, vol->minor_ver, filename);
210987da915Sopenharmony_ci		if (ntfs_version_is_supported(vol))
211987da915Sopenharmony_ci			device_err_exit(vol, NULL, NULL,
212987da915Sopenharmony_ci					"Unsupported NTFS version.\n");
213987da915Sopenharmony_ci		ni = ntfs_inode_open(vol, FILE_LogFile);
214987da915Sopenharmony_ci		if (!ni)
215987da915Sopenharmony_ci			device_err_exit(vol, NULL, NULL, "Failed to "
216987da915Sopenharmony_ci					"open $LogFile (inode %i): %s\n",
217987da915Sopenharmony_ci					FILE_LogFile, strerror(errno));
218987da915Sopenharmony_ci		na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
219987da915Sopenharmony_ci		if (!na)
220987da915Sopenharmony_ci			device_err_exit(vol, ni, NULL, "Failed to open "
221987da915Sopenharmony_ci					"$LogFile/$DATA (attribute 0x%x):"
222987da915Sopenharmony_ci					" %s\n", (unsigned int)
223987da915Sopenharmony_ci					le32_to_cpu(AT_DATA), strerror(errno));
224987da915Sopenharmony_ci		if (!na->data_size)
225987da915Sopenharmony_ci			device_err_exit(vol, ni, na, "$LogFile has zero "
226987da915Sopenharmony_ci					"length.  Run chkdsk /f to correct "
227987da915Sopenharmony_ci					"this.\n");
228987da915Sopenharmony_ci		logfile->data_size = na->data_size;
229987da915Sopenharmony_ci		logfile->vol = vol;
230987da915Sopenharmony_ci		logfile->ni = ni;
231987da915Sopenharmony_ci		logfile->na = na;
232987da915Sopenharmony_ci	} else {
233987da915Sopenharmony_ci		struct stat sbuf;
234987da915Sopenharmony_ci		int fd;
235987da915Sopenharmony_ci
236987da915Sopenharmony_ci		if (stat(filename, &sbuf) == -1) {
237987da915Sopenharmony_ci			if (errno == ENOENT)
238987da915Sopenharmony_ci				log_err_exit(NULL, "The file %s does not "
239987da915Sopenharmony_ci						"exist.  Did you specify it "
240987da915Sopenharmony_ci						"correctly?\n", filename);
241987da915Sopenharmony_ci			log_err_exit(NULL, "Error getting information about "
242987da915Sopenharmony_ci					"%s: %s\n", filename, strerror(errno));
243987da915Sopenharmony_ci		}
244987da915Sopenharmony_ci
245987da915Sopenharmony_ci		fd = open(filename, O_RDONLY);
246987da915Sopenharmony_ci		if (fd == -1)
247987da915Sopenharmony_ci			log_err_exit(NULL, "Failed to open file %s: %s\n",
248987da915Sopenharmony_ci					filename, strerror(errno));
249987da915Sopenharmony_ci		logfile->data_size = sbuf.st_size;
250987da915Sopenharmony_ci		logfile->fd = fd;
251987da915Sopenharmony_ci	}
252987da915Sopenharmony_ci
253987da915Sopenharmony_ci	logfile->is_volume = is_volume;
254987da915Sopenharmony_ci	logfile->filename = filename;
255987da915Sopenharmony_ci
256987da915Sopenharmony_ci	return 0;
257987da915Sopenharmony_ci}
258987da915Sopenharmony_ci
259987da915Sopenharmony_ci/**
260987da915Sopenharmony_ci * logfile_read
261987da915Sopenharmony_ci */
262987da915Sopenharmony_cistatic int logfile_pread(logfile_file *logfile, int ofs, int count, u8 *buf)
263987da915Sopenharmony_ci{
264987da915Sopenharmony_ci	int br;
265987da915Sopenharmony_ci
266987da915Sopenharmony_ci	if (logfile->is_volume) {
267987da915Sopenharmony_ci		br = (int)ntfs_attr_pread(logfile->na, ofs, count, buf);
268987da915Sopenharmony_ci	} else {
269987da915Sopenharmony_ci		if (lseek(logfile->fd, ofs, SEEK_SET)==-1) {
270987da915Sopenharmony_ci			ntfs_log_error("Could not seek to offset %u\n", ofs);
271987da915Sopenharmony_ci			return 0;
272987da915Sopenharmony_ci		}
273987da915Sopenharmony_ci		br = read(logfile->fd, buf, count);
274987da915Sopenharmony_ci	}
275987da915Sopenharmony_ci	if (br != count) {
276987da915Sopenharmony_ci		ntfs_log_error("Only %d out of %d bytes read starting at %d\n",
277987da915Sopenharmony_ci			br, count, ofs);
278987da915Sopenharmony_ci	}
279987da915Sopenharmony_ci	return br;
280987da915Sopenharmony_ci}
281987da915Sopenharmony_ci
282987da915Sopenharmony_ci/**
283987da915Sopenharmony_ci * restart_header_sanity()
284987da915Sopenharmony_ci */
285987da915Sopenharmony_cistatic void restart_header_sanity(RESTART_PAGE_HEADER *rstr, u8 *buf)
286987da915Sopenharmony_ci{
287987da915Sopenharmony_ci	unsigned int usa_end_ofs, page_size;
288987da915Sopenharmony_ci
289987da915Sopenharmony_ci	/* Only CHKD records are allowed to have chkdsk_lsn set. */
290987da915Sopenharmony_ci	if (!ntfs_is_chkd_record(rstr->magic) &&
291987da915Sopenharmony_ci			sle64_to_cpu(rstr->chkdsk_lsn))
292987da915Sopenharmony_ci		log_err_exit(buf, "$LogFile is corrupt:  Restart page header "
293987da915Sopenharmony_ci				"magic is not CHKD but a chkdsk LSN is "
294987da915Sopenharmony_ci				"specified.  Cannot handle this yet.\n");
295987da915Sopenharmony_ci	/* Both system and log page size must be >= 512 and a power of 2. */
296987da915Sopenharmony_ci	page_size = le32_to_cpu(rstr->log_page_size);
297987da915Sopenharmony_ci	if (page_size < 512 || page_size & (page_size - 1))
298987da915Sopenharmony_ci		log_err_exit(buf, "$LogFile is corrupt:  Restart page header "
299987da915Sopenharmony_ci				"specifies invalid log page size.  Cannot "
300987da915Sopenharmony_ci				"handle this yet.\n");
301987da915Sopenharmony_ci	if (page_size != le32_to_cpu(rstr->system_page_size)) {
302987da915Sopenharmony_ci		page_size = le32_to_cpu(rstr->system_page_size);
303987da915Sopenharmony_ci		if (page_size < 512 || page_size & (page_size - 1))
304987da915Sopenharmony_ci			log_err_exit(buf, "$LogFile is corrupt:  Restart page "
305987da915Sopenharmony_ci					"header specifies invalid system page "
306987da915Sopenharmony_ci					"size.  Cannot handle this yet.\n");
307987da915Sopenharmony_ci	}
308987da915Sopenharmony_ci	/* Abort if the version number is not 1.1. */
309987da915Sopenharmony_ci	if (sle16_to_cpu(rstr->major_ver) != 1 ||
310987da915Sopenharmony_ci			sle16_to_cpu(rstr->minor_ver) != 1)
311987da915Sopenharmony_ci		log_err_exit(buf, "Unknown $LogFile version %i.%i.  Only know "
312987da915Sopenharmony_ci				"how to handle version 1.1.\n",
313987da915Sopenharmony_ci				sle16_to_cpu(rstr->major_ver),
314987da915Sopenharmony_ci				sle16_to_cpu(rstr->minor_ver));
315987da915Sopenharmony_ci	/* Verify the location and size of the update sequence array. */
316987da915Sopenharmony_ci	usa_end_ofs = le16_to_cpu(rstr->usa_ofs) +
317987da915Sopenharmony_ci			le16_to_cpu(rstr->usa_count) * sizeof(u16);
318987da915Sopenharmony_ci	if (page_size / NTFS_BLOCK_SIZE + 1 != le16_to_cpu(rstr->usa_count))
319987da915Sopenharmony_ci		log_err_exit(buf, "Restart page header in $LogFile is "
320987da915Sopenharmony_ci				"corrupt:  Update sequence array size is "
321987da915Sopenharmony_ci				"wrong.  Cannot handle this yet.\n");
322987da915Sopenharmony_ci	if (le16_to_cpu(rstr->usa_ofs) < offsetof(RESTART_PAGE_HEADER, usn))
323987da915Sopenharmony_ci		log_err_exit(buf, "Restart page header in $LogFile is "
324987da915Sopenharmony_ci				"corrupt:  Update sequence array overlaps "
325987da915Sopenharmony_ci				"restart page header.  Cannot handle this "
326987da915Sopenharmony_ci				"yet.\n");
327987da915Sopenharmony_ci	if (usa_end_ofs > NTFS_BLOCK_SIZE - sizeof(u16))
328987da915Sopenharmony_ci		log_err_exit(buf, "Restart page header in $LogFile is "
329987da915Sopenharmony_ci				"corrupt:  Update sequence array overlaps or "
330987da915Sopenharmony_ci				"is behind first protected sequence number.  "
331987da915Sopenharmony_ci				"Cannot handle this yet.\n");
332987da915Sopenharmony_ci	if (usa_end_ofs > le16_to_cpu(rstr->restart_area_offset))
333987da915Sopenharmony_ci		log_err_exit(buf, "Restart page header in $LogFile is "
334987da915Sopenharmony_ci				"corrupt:  Update sequence array overlaps or "
335987da915Sopenharmony_ci				"is behind restart area.  Cannot handle this "
336987da915Sopenharmony_ci				"yet.\n");
337987da915Sopenharmony_ci	/* Finally, verify the offset of the restart area. */
338987da915Sopenharmony_ci	if (le16_to_cpu(rstr->restart_area_offset) & 7)
339987da915Sopenharmony_ci		log_err_exit(buf, "Restart page header in $LogFile is "
340987da915Sopenharmony_ci				"corrupt:  Restart area offset is not aligned "
341987da915Sopenharmony_ci				"to 8-byte boundary.  Cannot handle this "
342987da915Sopenharmony_ci				"yet.\n");
343987da915Sopenharmony_ci}
344987da915Sopenharmony_ci
345987da915Sopenharmony_ci/**
346987da915Sopenharmony_ci * dump_restart_areas_header
347987da915Sopenharmony_ci */
348987da915Sopenharmony_cistatic void dump_restart_areas_header(RESTART_PAGE_HEADER *rstr)
349987da915Sopenharmony_ci{
350987da915Sopenharmony_ci	ntfs_log_info("\nRestart page header:\n");
351987da915Sopenharmony_ci	ntfs_log_info("magic = %s\n", ntfs_is_rstr_record(rstr->magic) ? "RSTR" :
352987da915Sopenharmony_ci			"CHKD");
353987da915Sopenharmony_ci	ntfs_log_info("usa_ofs = %u (0x%x)\n", le16_to_cpu(rstr->usa_ofs),
354987da915Sopenharmony_ci			le16_to_cpu(rstr->usa_ofs));
355987da915Sopenharmony_ci	ntfs_log_info("usa_count = %u (0x%x)\n", le16_to_cpu(rstr->usa_count),
356987da915Sopenharmony_ci			le16_to_cpu(rstr->usa_count));
357987da915Sopenharmony_ci	ntfs_log_info("chkdsk_lsn = %lli (0x%llx)\n",
358987da915Sopenharmony_ci			(long long)sle64_to_cpu(rstr->chkdsk_lsn),
359987da915Sopenharmony_ci			(unsigned long long)sle64_to_cpu(rstr->chkdsk_lsn));
360987da915Sopenharmony_ci	ntfs_log_info("system_page_size = %u (0x%x)\n",
361987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(rstr->system_page_size),
362987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(rstr->system_page_size));
363987da915Sopenharmony_ci	ntfs_log_info("log_page_size = %u (0x%x)\n",
364987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(rstr->log_page_size),
365987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(rstr->log_page_size));
366987da915Sopenharmony_ci	ntfs_log_info("restart_offset = %u (0x%x)\n",
367987da915Sopenharmony_ci			le16_to_cpu(rstr->restart_area_offset),
368987da915Sopenharmony_ci			le16_to_cpu(rstr->restart_area_offset));
369987da915Sopenharmony_ci}
370987da915Sopenharmony_ci
371987da915Sopenharmony_ci/**
372987da915Sopenharmony_ci * dump_restart_areas_area
373987da915Sopenharmony_ci */
374987da915Sopenharmony_cistatic void dump_restart_areas_area(RESTART_PAGE_HEADER *rstr)
375987da915Sopenharmony_ci{
376987da915Sopenharmony_ci	LOG_CLIENT_RECORD *lcr;
377987da915Sopenharmony_ci	RESTART_AREA *ra;
378987da915Sopenharmony_ci	int client;
379987da915Sopenharmony_ci
380987da915Sopenharmony_ci	ra = (RESTART_AREA*)((u8*)rstr +
381987da915Sopenharmony_ci			le16_to_cpu(rstr->restart_area_offset));
382987da915Sopenharmony_ci	ntfs_log_info("current_lsn = %lli (0x%llx)\n",
383987da915Sopenharmony_ci			(long long)sle64_to_cpu(ra->current_lsn),
384987da915Sopenharmony_ci			(unsigned long long)sle64_to_cpu(ra->current_lsn));
385987da915Sopenharmony_ci	ntfs_log_info("log_clients = %u (0x%x)\n", le16_to_cpu(ra->log_clients),
386987da915Sopenharmony_ci			le16_to_cpu(ra->log_clients));
387987da915Sopenharmony_ci	ntfs_log_info("client_free_list = %i (0x%x)\n",
388987da915Sopenharmony_ci			(s16)le16_to_cpu(ra->client_free_list),
389987da915Sopenharmony_ci			le16_to_cpu(ra->client_free_list));
390987da915Sopenharmony_ci	ntfs_log_info("client_in_use_list = %i (0x%x)\n",
391987da915Sopenharmony_ci			(s16)le16_to_cpu(ra->client_in_use_list),
392987da915Sopenharmony_ci			le16_to_cpu(ra->client_in_use_list));
393987da915Sopenharmony_ci	ntfs_log_info("flags = 0x%.4x\n", le16_to_cpu(ra->flags));
394987da915Sopenharmony_ci	ntfs_log_info("seq_number_bits = %u (0x%x)\n",
395987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(ra->seq_number_bits),
396987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(ra->seq_number_bits));
397987da915Sopenharmony_ci	ntfs_log_info("restart_area_length = %u (0x%x)\n",
398987da915Sopenharmony_ci			le16_to_cpu(ra->restart_area_length),
399987da915Sopenharmony_ci			le16_to_cpu(ra->restart_area_length));
400987da915Sopenharmony_ci	ntfs_log_info("client_array_offset = %u (0x%x)\n",
401987da915Sopenharmony_ci			le16_to_cpu(ra->client_array_offset),
402987da915Sopenharmony_ci			le16_to_cpu(ra->client_array_offset));
403987da915Sopenharmony_ci	ntfs_log_info("file_size = %lli (0x%llx)\n",
404987da915Sopenharmony_ci			(long long)sle64_to_cpu(ra->file_size),
405987da915Sopenharmony_ci			(unsigned long long)sle64_to_cpu(ra->file_size));
406987da915Sopenharmony_ci	ntfs_log_info("last_lsn_data_length = %u (0x%x)\n",
407987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(ra->last_lsn_data_length),
408987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(ra->last_lsn_data_length));
409987da915Sopenharmony_ci	ntfs_log_info("log_record_header_length = %u (0x%x)\n",
410987da915Sopenharmony_ci			le16_to_cpu(ra->log_record_header_length),
411987da915Sopenharmony_ci			le16_to_cpu(ra->log_record_header_length));
412987da915Sopenharmony_ci	ntfs_log_info("log_page_data_offset = %u (0x%x)\n",
413987da915Sopenharmony_ci			le16_to_cpu(ra->log_page_data_offset),
414987da915Sopenharmony_ci			le16_to_cpu(ra->log_page_data_offset));
415987da915Sopenharmony_ci	ntfs_log_info("restart_log_open_count = %u (0x%x)\n",
416987da915Sopenharmony_ci			(unsigned)le32_to_cpu(ra->restart_log_open_count),
417987da915Sopenharmony_ci			(unsigned)le32_to_cpu(ra->restart_log_open_count));
418987da915Sopenharmony_ci	lcr = (LOG_CLIENT_RECORD*)((u8*)ra +
419987da915Sopenharmony_ci			le16_to_cpu(ra->client_array_offset));
420987da915Sopenharmony_ci	for (client = 0; client < le16_to_cpu(ra->log_clients); client++) {
421987da915Sopenharmony_ci		char *client_name;
422987da915Sopenharmony_ci
423987da915Sopenharmony_ci		ntfs_log_info("\nLog client record number %i:\n", client + 1);
424987da915Sopenharmony_ci		ntfs_log_info("oldest_lsn = %lli (0x%llx)\n",
425987da915Sopenharmony_ci				(long long)sle64_to_cpu(lcr->oldest_lsn),
426987da915Sopenharmony_ci				(unsigned long long)
427987da915Sopenharmony_ci				sle64_to_cpu(lcr->oldest_lsn));
428987da915Sopenharmony_ci		ntfs_log_info("client_restart_lsn = %lli (0x%llx)\n", (long long)
429987da915Sopenharmony_ci				sle64_to_cpu(lcr->client_restart_lsn),
430987da915Sopenharmony_ci				(unsigned long long)
431987da915Sopenharmony_ci				sle64_to_cpu(lcr->client_restart_lsn));
432987da915Sopenharmony_ci		ntfs_log_info("prev_client = %i (0x%x)\n",
433987da915Sopenharmony_ci				(s16)le16_to_cpu(lcr->prev_client),
434987da915Sopenharmony_ci				le16_to_cpu(lcr->prev_client));
435987da915Sopenharmony_ci		ntfs_log_info("next_client = %i (0x%x)\n",
436987da915Sopenharmony_ci				(s16)le16_to_cpu(lcr->next_client),
437987da915Sopenharmony_ci				le16_to_cpu(lcr->next_client));
438987da915Sopenharmony_ci		ntfs_log_info("seq_number = %u (0x%x)\n", le16_to_cpu(lcr->seq_number),
439987da915Sopenharmony_ci				le16_to_cpu(lcr->seq_number));
440987da915Sopenharmony_ci		ntfs_log_info("client_name_length = %u (0x%x)\n",
441987da915Sopenharmony_ci				(unsigned int)le32_to_cpu(lcr->client_name_length) / 2,
442987da915Sopenharmony_ci				(unsigned int)le32_to_cpu(lcr->client_name_length) / 2);
443987da915Sopenharmony_ci		if (le32_to_cpu(lcr->client_name_length)) {
444987da915Sopenharmony_ci			client_name = NULL;
445987da915Sopenharmony_ci			if (ntfs_ucstombs(lcr->client_name,
446987da915Sopenharmony_ci					le32_to_cpu(lcr->client_name_length) /
447987da915Sopenharmony_ci					2, &client_name, 0) < 0) {
448987da915Sopenharmony_ci				ntfs_log_perror("Failed to convert log client name");
449987da915Sopenharmony_ci				client_name = strdup("<conversion error>");
450987da915Sopenharmony_ci			}
451987da915Sopenharmony_ci		} else
452987da915Sopenharmony_ci			client_name = strdup("<unnamed>");
453987da915Sopenharmony_ci		ntfs_log_info("client_name = %s\n", client_name);
454987da915Sopenharmony_ci		free(client_name);
455987da915Sopenharmony_ci		/*
456987da915Sopenharmony_ci		 * Log client records are fixed size so we can simply use the
457987da915Sopenharmony_ci		 * C increment operator to get to the next one.
458987da915Sopenharmony_ci		 */
459987da915Sopenharmony_ci		lcr++;
460987da915Sopenharmony_ci	}
461987da915Sopenharmony_ci}
462987da915Sopenharmony_ci
463987da915Sopenharmony_ci/**
464987da915Sopenharmony_ci * dump_restart_areas()
465987da915Sopenharmony_ci */
466987da915Sopenharmony_cistatic void *dump_restart_areas(RESTART_PAGE_HEADER *rstr, u8 *buf,
467987da915Sopenharmony_ci		unsigned int page_size)
468987da915Sopenharmony_ci{
469987da915Sopenharmony_ci	int pass = 1;
470987da915Sopenharmony_ci
471987da915Sopenharmony_cirstr_pass_loc:
472987da915Sopenharmony_ci	if (ntfs_is_chkd_record(rstr->magic))
473987da915Sopenharmony_ci		log_err_exit(buf, "The %s restart page header in $LogFile has "
474987da915Sopenharmony_ci				"been modified by chkdsk.  Do not know how to "
475987da915Sopenharmony_ci				"handle this yet.  Reboot into Windows to fix "
476987da915Sopenharmony_ci				"this.\n", (u8*)rstr == buf ? "first" :
477987da915Sopenharmony_ci				"second");
478987da915Sopenharmony_ci	if (ntfs_mst_post_read_fixup((NTFS_RECORD*)rstr, page_size) ||
479987da915Sopenharmony_ci			ntfs_is_baad_record(rstr->magic))
480987da915Sopenharmony_ci		log_err_exit(buf, "$LogFile incomplete multi sector transfer "
481987da915Sopenharmony_ci				"detected in restart page header.  Cannot "
482987da915Sopenharmony_ci				"handle this yet.\n");
483987da915Sopenharmony_ci	if (pass == 1)
484987da915Sopenharmony_ci		ntfs_log_info("$LogFile version %i.%i.\n",
485987da915Sopenharmony_ci				sle16_to_cpu(rstr->major_ver),
486987da915Sopenharmony_ci				sle16_to_cpu(rstr->minor_ver));
487987da915Sopenharmony_ci	else /* if (pass == 2) */ {
488987da915Sopenharmony_ci		RESTART_AREA *ra;
489987da915Sopenharmony_ci
490987da915Sopenharmony_ci		/*
491987da915Sopenharmony_ci		 * rstr is now the second restart page so we declare rstr1
492987da915Sopenharmony_ci		 * as the first restart page as this one has been verified in
493987da915Sopenharmony_ci		 * the first pass so we can use all its members safely.
494987da915Sopenharmony_ci		 */
495987da915Sopenharmony_ci		RESTART_PAGE_HEADER *rstr1 = (RESTART_PAGE_HEADER*)buf;
496987da915Sopenharmony_ci
497987da915Sopenharmony_ci		/* Exclude the usa from the comparison. */
498987da915Sopenharmony_ci		ra = (RESTART_AREA*)((u8*)rstr1 +
499987da915Sopenharmony_ci				le16_to_cpu(rstr1->restart_area_offset));
500987da915Sopenharmony_ci		if (!memcmp(rstr1, rstr, le16_to_cpu(rstr1->usa_ofs)) &&
501987da915Sopenharmony_ci				!memcmp((u8*)rstr1 + le16_to_cpu(
502987da915Sopenharmony_ci				rstr1->restart_area_offset), (u8*)rstr +
503987da915Sopenharmony_ci				le16_to_cpu(rstr->restart_area_offset),
504987da915Sopenharmony_ci				le16_to_cpu(ra->restart_area_length))) {
505987da915Sopenharmony_ci			puts("\nSkipping analysis of second restart page "
506987da915Sopenharmony_ci					"because it fully matches the first "
507987da915Sopenharmony_ci					"one.");
508987da915Sopenharmony_ci			goto skip_rstr_pass;
509987da915Sopenharmony_ci		}
510987da915Sopenharmony_ci		/*
511987da915Sopenharmony_ci		 * The $LogFile versions specified in each of the two restart
512987da915Sopenharmony_ci		 * page headers must match.
513987da915Sopenharmony_ci		 */
514987da915Sopenharmony_ci		if (rstr1->major_ver != rstr->major_ver ||
515987da915Sopenharmony_ci				rstr1->minor_ver != rstr->minor_ver)
516987da915Sopenharmony_ci			log_err_exit(buf, "Second restart area specifies "
517987da915Sopenharmony_ci					"different $LogFile version to first "
518987da915Sopenharmony_ci					"restart area.  Cannot handle this "
519987da915Sopenharmony_ci					"yet.\n");
520987da915Sopenharmony_ci	}
521987da915Sopenharmony_ci	/* The restart page header is in rstr and it is mst deprotected. */
522987da915Sopenharmony_ci	ntfs_log_info("\n%s restart page:\n", pass == 1 ? "1st" : "2nd");
523987da915Sopenharmony_ci	dump_restart_areas_header(rstr);
524987da915Sopenharmony_ci
525987da915Sopenharmony_ci	ntfs_log_info("\nRestart area:\n");
526987da915Sopenharmony_ci	dump_restart_areas_area(rstr);
527987da915Sopenharmony_ci
528987da915Sopenharmony_ciskip_rstr_pass:
529987da915Sopenharmony_ci	if (pass == 1) {
530987da915Sopenharmony_ci		rstr = (RESTART_PAGE_HEADER*)((u8*)rstr + page_size);
531987da915Sopenharmony_ci		++pass;
532987da915Sopenharmony_ci		goto rstr_pass_loc;
533987da915Sopenharmony_ci	}
534987da915Sopenharmony_ci
535987da915Sopenharmony_ci	return rstr;
536987da915Sopenharmony_ci}
537987da915Sopenharmony_ci
538987da915Sopenharmony_ci/**
539987da915Sopenharmony_ci * dump_log_records()
540987da915Sopenharmony_ci */
541987da915Sopenharmony_cistatic void dump_log_record(LOG_RECORD *lr)
542987da915Sopenharmony_ci{
543987da915Sopenharmony_ci	unsigned int i;
544987da915Sopenharmony_ci	ntfs_log_info("this lsn = 0x%llx\n",
545987da915Sopenharmony_ci			(unsigned long long)sle64_to_cpu(lr->this_lsn));
546987da915Sopenharmony_ci	ntfs_log_info("client previous lsn = 0x%llx\n", (unsigned long long)
547987da915Sopenharmony_ci			sle64_to_cpu(lr->client_previous_lsn));
548987da915Sopenharmony_ci	ntfs_log_info("client undo next lsn = 0x%llx\n", (unsigned long long)
549987da915Sopenharmony_ci			sle64_to_cpu(lr->client_undo_next_lsn));
550987da915Sopenharmony_ci	ntfs_log_info("client data length = 0x%x\n",
551987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(lr->client_data_length));
552987da915Sopenharmony_ci	ntfs_log_info("client_id.seq_number = 0x%x\n",
553987da915Sopenharmony_ci			le16_to_cpu(lr->client_id.seq_number));
554987da915Sopenharmony_ci	ntfs_log_info("client_id.client_index = 0x%x\n",
555987da915Sopenharmony_ci			le16_to_cpu(lr->client_id.client_index));
556987da915Sopenharmony_ci	ntfs_log_info("record type = 0x%x\n",
557987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(lr->record_type));
558987da915Sopenharmony_ci	ntfs_log_info("transaction_id = 0x%x\n",
559987da915Sopenharmony_ci			(unsigned int)le32_to_cpu(lr->transaction_id));
560987da915Sopenharmony_ci	ntfs_log_info("flags = 0x%x:", le16_to_cpu(lr->log_record_flags));
561987da915Sopenharmony_ci	if (!lr->log_record_flags)
562987da915Sopenharmony_ci		ntfs_log_info(" NONE\n");
563987da915Sopenharmony_ci	else {
564987da915Sopenharmony_ci		int _b = 0;
565987da915Sopenharmony_ci
566987da915Sopenharmony_ci		if (lr->log_record_flags & LOG_RECORD_MULTI_PAGE) {
567987da915Sopenharmony_ci			ntfs_log_info(" LOG_RECORD_MULTI_PAGE");
568987da915Sopenharmony_ci			_b = 1;
569987da915Sopenharmony_ci		}
570987da915Sopenharmony_ci		if (lr->log_record_flags & ~LOG_RECORD_MULTI_PAGE) {
571987da915Sopenharmony_ci			if (_b)
572987da915Sopenharmony_ci				ntfs_log_info(" |");
573987da915Sopenharmony_ci			ntfs_log_info(" Unknown flags");
574987da915Sopenharmony_ci		}
575987da915Sopenharmony_ci		ntfs_log_info("\n");
576987da915Sopenharmony_ci	}
577987da915Sopenharmony_ci	ntfs_log_info("redo_operation = 0x%x\n", le16_to_cpu(lr->redo_operation));
578987da915Sopenharmony_ci	ntfs_log_info("undo_operation = 0x%x\n", le16_to_cpu(lr->undo_operation));
579987da915Sopenharmony_ci	ntfs_log_info("redo_offset = 0x%x\n", le16_to_cpu(lr->redo_offset));
580987da915Sopenharmony_ci	ntfs_log_info("redo_length = 0x%x\n", le16_to_cpu(lr->redo_length));
581987da915Sopenharmony_ci	ntfs_log_info("undo_offset = 0x%x\n", le16_to_cpu(lr->undo_offset));
582987da915Sopenharmony_ci	ntfs_log_info("undo_length = 0x%x\n", le16_to_cpu(lr->undo_length));
583987da915Sopenharmony_ci	ntfs_log_info("target_attribute = 0x%x\n", le16_to_cpu(lr->target_attribute));
584987da915Sopenharmony_ci	ntfs_log_info("lcns_to_follow = 0x%x\n", le16_to_cpu(lr->lcns_to_follow));
585987da915Sopenharmony_ci	ntfs_log_info("record_offset = 0x%x\n", le16_to_cpu(lr->record_offset));
586987da915Sopenharmony_ci	ntfs_log_info("attribute_offset = 0x%x\n", le16_to_cpu(lr->attribute_offset));
587987da915Sopenharmony_ci	ntfs_log_info("target_vcn = 0x%llx\n",
588987da915Sopenharmony_ci			(unsigned long long)sle64_to_cpu(lr->target_vcn));
589987da915Sopenharmony_ci	if (le16_to_cpu(lr->lcns_to_follow) > 0)
590987da915Sopenharmony_ci		ntfs_log_info("Array of lcns:\n");
591987da915Sopenharmony_ci	for (i = 0; i < le16_to_cpu(lr->lcns_to_follow); i++)
592987da915Sopenharmony_ci		ntfs_log_info("lcn_list[%u].lcn = 0x%llx\n", i,
593987da915Sopenharmony_ci			(unsigned long long)sle64_to_cpu(lr->lcn_list[i]));
594987da915Sopenharmony_ci}
595987da915Sopenharmony_ci
596987da915Sopenharmony_ci/**
597987da915Sopenharmony_ci * dump_log_records()
598987da915Sopenharmony_ci */
599987da915Sopenharmony_cistatic void dump_log_records(RECORD_PAGE_HEADER *rcrd, u8 *buf,
600987da915Sopenharmony_ci		int buf_size, unsigned int page_size)
601987da915Sopenharmony_ci{
602987da915Sopenharmony_ci	LOG_RECORD *lr;
603987da915Sopenharmony_ci	int pass = 0;
604987da915Sopenharmony_ci	int client;
605987da915Sopenharmony_ci
606987da915Sopenharmony_ci	/* Reuse pass for log area. */
607987da915Sopenharmony_circrd_pass_loc:
608987da915Sopenharmony_ci	rcrd = (RECORD_PAGE_HEADER*)((u8*)rcrd + page_size);
609987da915Sopenharmony_ci	if ((u8*)rcrd + page_size > buf + buf_size)
610987da915Sopenharmony_ci		return;
611987da915Sopenharmony_ci	ntfs_log_info("\nLog record page number %i", pass);
612987da915Sopenharmony_ci	if (!ntfs_is_rcrd_record(rcrd->magic) &&
613987da915Sopenharmony_ci			!ntfs_is_chkd_record(rcrd->magic)) {
614987da915Sopenharmony_ci		unsigned int i;
615987da915Sopenharmony_ci		for (i = 0; i < page_size; i++)
616987da915Sopenharmony_ci			if (((u8*)rcrd)[i] != (u8)-1)
617987da915Sopenharmony_ci				break;
618987da915Sopenharmony_ci		if (i < page_size)
619987da915Sopenharmony_ci			puts(" is corrupt (magic is not RCRD or CHKD).");
620987da915Sopenharmony_ci		else
621987da915Sopenharmony_ci			puts(" is empty.");
622987da915Sopenharmony_ci		pass++;
623987da915Sopenharmony_ci		goto rcrd_pass_loc;
624987da915Sopenharmony_ci	} else
625987da915Sopenharmony_ci		puts(":");
626987da915Sopenharmony_ci	/* Dump log record page */
627987da915Sopenharmony_ci	ntfs_log_info("magic = %s\n", ntfs_is_rcrd_record(rcrd->magic) ? "RCRD" :
628987da915Sopenharmony_ci			"CHKD");
629987da915Sopenharmony_ci// TODO: I am here... (AIA)
630987da915Sopenharmony_ci	ntfs_log_info("copy.last_lsn/file_offset = 0x%llx\n", (unsigned long long)
631987da915Sopenharmony_ci			sle64_to_cpu(rcrd->copy.last_lsn));
632987da915Sopenharmony_ci	ntfs_log_info("flags = 0x%x\n", (unsigned int)le32_to_cpu(rcrd->flags));
633987da915Sopenharmony_ci	ntfs_log_info("page count = %i\n", le16_to_cpu(rcrd->page_count));
634987da915Sopenharmony_ci	ntfs_log_info("page position = %i\n", le16_to_cpu(rcrd->page_position));
635987da915Sopenharmony_ci	ntfs_log_info("header.next_record_offset = 0x%llx\n", (unsigned long long)
636987da915Sopenharmony_ci			le16_to_cpu(rcrd->next_record_offset));
637987da915Sopenharmony_ci	ntfs_log_info("header.last_end_lsn = 0x%llx\n", (unsigned long long)
638987da915Sopenharmony_ci			sle64_to_cpu(rcrd->last_end_lsn));
639987da915Sopenharmony_ci	/*
640987da915Sopenharmony_ci	 * Where does the 0x40 come from? Is it just usa_offset +
641987da915Sopenharmony_ci	 * usa_client * 2 + 7 & ~7 or is it derived from somewhere?
642987da915Sopenharmony_ci	 */
643987da915Sopenharmony_ci	lr = (LOG_RECORD*)((u8*)rcrd + 0x40);
644987da915Sopenharmony_ci	client = 0;
645987da915Sopenharmony_ci	do {
646987da915Sopenharmony_ci		ntfs_log_info("\nLog record %i:\n", client);
647987da915Sopenharmony_ci		dump_log_record(lr);
648987da915Sopenharmony_ci		client++;
649987da915Sopenharmony_ci		lr = (LOG_RECORD*)((u8*)lr + 0x70);
650987da915Sopenharmony_ci	} while (((u8*)lr + 0x70 <= (u8*)rcrd +
651987da915Sopenharmony_ci			le16_to_cpu(rcrd->next_record_offset)));
652987da915Sopenharmony_ci
653987da915Sopenharmony_ci	pass++;
654987da915Sopenharmony_ci	goto rcrd_pass_loc;
655987da915Sopenharmony_ci}
656987da915Sopenharmony_ci
657987da915Sopenharmony_ci/**
658987da915Sopenharmony_ci * main -
659987da915Sopenharmony_ci */
660987da915Sopenharmony_ciint main(int argc, char **argv)
661987da915Sopenharmony_ci{
662987da915Sopenharmony_ci	RESTART_PAGE_HEADER *rstr;
663987da915Sopenharmony_ci	RECORD_PAGE_HEADER *rcrd;
664987da915Sopenharmony_ci	unsigned int page_size;
665987da915Sopenharmony_ci	int buf_size, br, err;
666987da915Sopenharmony_ci	logfile_file logfile;
667987da915Sopenharmony_ci	u8 *buf;
668987da915Sopenharmony_ci
669987da915Sopenharmony_ci	ntfs_log_set_handler(ntfs_log_handler_outerr);
670987da915Sopenharmony_ci
671987da915Sopenharmony_ci	ntfs_log_info("\n");
672987da915Sopenharmony_ci	if (argc < 2 || argc > 3)
673987da915Sopenharmony_ci		/* print usage and exit */
674987da915Sopenharmony_ci		usage(argv[0]);
675987da915Sopenharmony_ci	/*
676987da915Sopenharmony_ci	 * If one argument, it is a device containing an NTFS volume which we
677987da915Sopenharmony_ci	 * need to mount and read the $LogFile from so we can dump its
678987da915Sopenharmony_ci	 * contents.
679987da915Sopenharmony_ci	 *
680987da915Sopenharmony_ci	 * If two arguments the first one must be "-f" and the second one is
681987da915Sopenharmony_ci	 * the path and name of the $LogFile (or copy thereof) which we need to
682987da915Sopenharmony_ci	 * read and dump the contents of.
683987da915Sopenharmony_ci	 */
684987da915Sopenharmony_ci
685987da915Sopenharmony_ci	if (argc == 2) {
686987da915Sopenharmony_ci		logfile_open(TRUE, argv[1], &logfile);
687987da915Sopenharmony_ci	} else /* if (argc == 3) */ {
688987da915Sopenharmony_ci		if (strncmp(argv[1], "-f", strlen("-f")))
689987da915Sopenharmony_ci			usage(argv[0]);
690987da915Sopenharmony_ci
691987da915Sopenharmony_ci		logfile_open(FALSE, argv[2], &logfile);
692987da915Sopenharmony_ci	}
693987da915Sopenharmony_ci
694987da915Sopenharmony_ci	buf_size = 64 * 1024 * 1024;
695987da915Sopenharmony_ci
696987da915Sopenharmony_ci	if (logfile.data_size <= buf_size)
697987da915Sopenharmony_ci		buf_size = logfile.data_size;
698987da915Sopenharmony_ci	else
699987da915Sopenharmony_ci		ntfs_log_error("Warning: $LogFile is too big.  "
700987da915Sopenharmony_ci			"Only analysing the first 64MiB.\n");
701987da915Sopenharmony_ci
702987da915Sopenharmony_ci	/* For simplicity we read all of $LogFile/$DATA into memory. */
703987da915Sopenharmony_ci	buf = malloc(buf_size);
704987da915Sopenharmony_ci	if (!buf) {
705987da915Sopenharmony_ci		ntfs_log_perror("Failed to allocate buffer for file data");
706987da915Sopenharmony_ci		logfile_close(&logfile);
707987da915Sopenharmony_ci		exit(1);
708987da915Sopenharmony_ci	}
709987da915Sopenharmony_ci
710987da915Sopenharmony_ci	br = logfile_pread(&logfile, 0, buf_size, buf);
711987da915Sopenharmony_ci	err = errno;
712987da915Sopenharmony_ci	logfile_close(&logfile);
713987da915Sopenharmony_ci	if (br != buf_size) {
714987da915Sopenharmony_ci		log_err_exit(buf, "Failed to read $LogFile/$DATA: %s\n",
715987da915Sopenharmony_ci				br < 0 ? strerror(err) : "Partial read.");
716987da915Sopenharmony_ci	}
717987da915Sopenharmony_ci
718987da915Sopenharmony_ci	/*
719987da915Sopenharmony_ci	 * We now have the entirety of the journal ($LogFile/$DATA or argv[2])
720987da915Sopenharmony_ci	 * in the memory buffer buf and this has a size of buf_size.  Note we
721987da915Sopenharmony_ci	 * apply a size capping at 64MiB, so if the journal is any bigger we
722987da915Sopenharmony_ci	 * only have the first 64MiB.  This should not be a problem as I have
723987da915Sopenharmony_ci	 * never seen such a large $LogFile.  Usually it is only a few MiB in
724987da915Sopenharmony_ci	 * size.
725987da915Sopenharmony_ci	 */
726987da915Sopenharmony_ci	rstr = (RESTART_PAGE_HEADER*)buf;
727987da915Sopenharmony_ci
728987da915Sopenharmony_ci	/* Check for presence of restart area signature. */
729987da915Sopenharmony_ci	if (!ntfs_is_rstr_record(rstr->magic) &&
730987da915Sopenharmony_ci			!ntfs_is_chkd_record(rstr->magic)) {
731987da915Sopenharmony_ci		s8 *pos = (s8*)buf;
732987da915Sopenharmony_ci		s8 *end = pos + buf_size;
733987da915Sopenharmony_ci		while (pos < end && *pos == -1)
734987da915Sopenharmony_ci			pos++;
735987da915Sopenharmony_ci		if (pos != end)
736987da915Sopenharmony_ci			log_err_exit(buf, "$LogFile contents are corrupt "
737987da915Sopenharmony_ci					"(magic RSTR is missing).  Cannot "
738987da915Sopenharmony_ci					"handle this yet.\n");
739987da915Sopenharmony_ci		/* All bytes are -1. */
740987da915Sopenharmony_ci		free(buf);
741987da915Sopenharmony_ci		puts("$LogFile is not initialized.");
742987da915Sopenharmony_ci		return 0;
743987da915Sopenharmony_ci	}
744987da915Sopenharmony_ci
745987da915Sopenharmony_ci	/*
746987da915Sopenharmony_ci	 * First, verify the restart page header for consistency.
747987da915Sopenharmony_ci	 */
748987da915Sopenharmony_ci	restart_header_sanity(rstr, buf);
749987da915Sopenharmony_ci	page_size = le32_to_cpu(rstr->log_page_size);
750987da915Sopenharmony_ci
751987da915Sopenharmony_ci	/*
752987da915Sopenharmony_ci	 * Second, verify the restart area itself.
753987da915Sopenharmony_ci	 */
754987da915Sopenharmony_ci	// TODO: Implement this.
755987da915Sopenharmony_ci	ntfs_log_error("Warning:  Sanity checking of restart area not implemented "
756987da915Sopenharmony_ci		"yet.\n");
757987da915Sopenharmony_ci	/*
758987da915Sopenharmony_ci	 * Third and last, verify the array of log client records.
759987da915Sopenharmony_ci	 */
760987da915Sopenharmony_ci	// TODO: Implement this.
761987da915Sopenharmony_ci	ntfs_log_error("Warning:  Sanity checking of array of log client records not "
762987da915Sopenharmony_ci		"implemented yet.\n");
763987da915Sopenharmony_ci
764987da915Sopenharmony_ci	/*
765987da915Sopenharmony_ci	 * Dump the restart headers & areas.
766987da915Sopenharmony_ci	 */
767987da915Sopenharmony_ci	rcrd = (RECORD_PAGE_HEADER*)dump_restart_areas(rstr, buf, page_size);
768987da915Sopenharmony_ci	ntfs_log_info("\n\nFinished with restart pages.  "
769987da915Sopenharmony_ci		"Beginning with log pages.\n");
770987da915Sopenharmony_ci
771987da915Sopenharmony_ci	/*
772987da915Sopenharmony_ci	 * Dump the log areas.
773987da915Sopenharmony_ci	 */
774987da915Sopenharmony_ci	dump_log_records(rcrd, buf, buf_size, page_size);
775987da915Sopenharmony_ci
776987da915Sopenharmony_ci	free(buf);
777987da915Sopenharmony_ci	return 0;
778987da915Sopenharmony_ci}
779987da915Sopenharmony_ci
780