• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * ntfsmftalloc - Part of the Linux-NTFS project.
3  *
4  * Copyright (c) 2002-2005 Anton Altaparmakov
5  *
6  * This utility will allocate and initialize an mft record.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program (in the main directory of the Linux-NTFS source
20  * in the file COPYING); if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "config.h"
25 
26 #ifdef HAVE_UNISTD_H
27 #	include <unistd.h>
28 #endif
29 #ifdef HAVE_STDLIB_H
30 #	include <stdlib.h>
31 #endif
32 #ifdef HAVE_STDIO_H
33 #	include <stdio.h>
34 #endif
35 #ifdef HAVE_STDARG_H
36 #	include <stdarg.h>
37 #endif
38 #ifdef HAVE_STRING_H
39 #	include <string.h>
40 #endif
41 #ifdef HAVE_ERRNO_H
42 #	include <errno.h>
43 #endif
44 #ifdef HAVE_TIME_H
45 #include <time.h>
46 #endif
47 #ifdef HAVE_GETOPT_H
48 #	include <getopt.h>
49 #else
50 	extern int optind;
51 #endif
52 #ifdef HAVE_LIMITS_H
53 #include <limits.h>
54 #endif
55 #ifndef LLONG_MAX
56 #	define LLONG_MAX 9223372036854775807LL
57 #endif
58 
59 #include "types.h"
60 #include "attrib.h"
61 #include "inode.h"
62 #include "layout.h"
63 #include "volume.h"
64 #include "mft.h"
65 #include "utils.h"
66 /* #include "version.h" */
67 #include "logging.h"
68 
69 static const char *EXEC_NAME = "ntfsmftalloc";
70 
71 /* Need these global so ntfsmftalloc_exit can access them. */
72 static BOOL success = FALSE;
73 
74 static char *dev_name;
75 
76 static ntfs_volume *vol;
77 static ntfs_inode *ni = NULL;
78 static ntfs_inode *base_ni = NULL;
79 static s64 base_mft_no = -1;
80 
81 static struct {
82 				/* -h, print usage and exit. */
83 	int no_action;		/* -n, do not write to device, only display
84 				       what would be done. */
85 	int quiet;		/* -q, quiet execution. */
86 	int verbose;		/* -v, verbose execution, given twice, really
87 				       verbose execution (debug mode). */
88 	int force;		/* -f, force allocation. */
89 				/* -V, print version and exit. */
90 } opts;
91 
92 /**
93  * err_exit - error output and terminate; ignores quiet (-q)
94  */
95 __attribute__((noreturn))
96 __attribute__((format(printf, 1, 2)))
err_exit(const char * fmt,...)97 static void err_exit(const char *fmt, ...)
98 {
99 	va_list ap;
100 
101 	fprintf(stderr, "ERROR: ");
102 	va_start(ap, fmt);
103 	vfprintf(stderr, fmt, ap);
104 	va_end(ap);
105 	fprintf(stderr, "Aborting...\n");
106 	exit(1);
107 }
108 
109 /**
110  * copyright - print copyright statements
111  */
copyright(void)112 static void copyright(void)
113 {
114 	ntfs_log_info("Copyright (c) 2004-2005 Anton Altaparmakov\n"
115 			"Allocate and initialize a base or an extent mft "
116 			"record.  If a base mft record\nis not specified, a "
117 			"base mft record is allocated and initialized.  "
118 			"Otherwise,\nan extent mft record is allocated and "
119 			"initialized to point to the specified\nbase mft "
120 			"record.\n");
121 }
122 
123 /**
124  * license - print license statement
125  */
license(void)126 static void license(void)
127 {
128 	ntfs_log_info("%s", ntfs_gpl);
129 }
130 
131 /**
132  * usage - print a list of the parameters to the program
133  */
134 __attribute__((noreturn))
usage(void)135 static void usage(void)
136 {
137 	copyright();
138 	ntfs_log_info("Usage: %s [options] device [base-mft-record]\n"
139 			"    -n    Do not write to disk\n"
140 			"    -f    Force execution despite errors\n"
141 			"    -q    Quiet execution\n"
142 			"    -v    Verbose execution\n"
143 			"    -vv   Very verbose execution\n"
144 			"    -V    Display version information\n"
145 			"    -l    Display licensing information\n"
146 			"    -h    Display this help\n", EXEC_NAME);
147 	ntfs_log_info("%s%s", ntfs_bugs, ntfs_home);
148 	exit(1);
149 }
150 
151 /**
152  * parse_options
153  */
parse_options(int argc,char * argv[])154 static void parse_options(int argc, char *argv[])
155 {
156 	long long ll;
157 	char *s;
158 	int c;
159 
160 	if (argc && *argv)
161 		EXEC_NAME = *argv;
162 	ntfs_log_info("%s v%s (libntfs-3g)\n", EXEC_NAME, VERSION);
163 	while ((c = getopt(argc, argv, "fh?nqvVl")) != EOF) {
164 		switch (c) {
165 		case 'f':
166 			opts.force = 1;
167 			break;
168 		case 'n':
169 			opts.no_action = 1;
170 			break;
171 		case 'q':
172 			opts.quiet = 1;
173 			ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
174 			break;
175 		case 'v':
176 			opts.verbose++;
177 			ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
178 			break;
179 		case 'V':
180 			/* Version number already printed, so just exit. */
181 			exit(0);
182 		case 'l':
183 			copyright();
184 			license();
185 			exit(0);
186 		case 'h':
187 		case '?':
188 		default:
189 			usage();
190 		}
191 	}
192 
193 	if (opts.verbose > 1)
194 		ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE |
195 			NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_QUIET);
196 
197 	if (optind == argc)
198 		usage();
199 	/* Get the device. */
200 	dev_name = argv[optind++];
201 	ntfs_log_verbose("device name = %s\n", dev_name);
202 	if (optind != argc) {
203 		/* Get the base mft record number. */
204 		ll = strtoll(argv[optind++], &s, 0);
205 		if (*s || !ll || (ll >= LLONG_MAX && errno == ERANGE))
206 			err_exit("Invalid base mft record number: %s\n",
207 					argv[optind - 1]);
208 		base_mft_no = ll;
209 		ntfs_log_verbose("base mft record number = 0x%llx\n", (long long)ll);
210 	}
211 	if (optind != argc)
212 		usage();
213 }
214 
215 /**
216  * dump_mft_record
217  */
dump_mft_record(MFT_RECORD * m)218 static void dump_mft_record(MFT_RECORD *m)
219 {
220 	ATTR_RECORD *a;
221 	unsigned int u;
222 	MFT_REF r;
223 
224 	ntfs_log_info("-- Beginning dump of mft record. --\n");
225 	u = le32_to_cpu(m->magic);
226 	ntfs_log_info("Mft record signature (magic) = %c%c%c%c\n", u & 0xff,
227 			u >> 8 & 0xff, u >> 16 & 0xff, u >> 24 & 0xff);
228 	u = le16_to_cpu(m->usa_ofs);
229 	ntfs_log_info("Update sequence array offset = %u (0x%x)\n", u, u);
230 	ntfs_log_info("Update sequence array size = %u\n", le16_to_cpu(m->usa_count));
231 	ntfs_log_info("$LogFile sequence number (lsn) = %llu\n",
232 			(unsigned long long)sle64_to_cpu(m->lsn));
233 	ntfs_log_info("Sequence number = %u\n", le16_to_cpu(m->sequence_number));
234 	ntfs_log_info("Reference (hard link) count = %u\n",
235 						le16_to_cpu(m->link_count));
236 	u = le16_to_cpu(m->attrs_offset);
237 	ntfs_log_info("First attribute offset = %u (0x%x)\n", u, u);
238 	ntfs_log_info("Flags = %u: ", le16_to_cpu(m->flags));
239 	if (m->flags & MFT_RECORD_IN_USE)
240 		ntfs_log_info("MFT_RECORD_IN_USE");
241 	else
242 		ntfs_log_info("MFT_RECORD_NOT_IN_USE");
243 	if (m->flags & MFT_RECORD_IS_DIRECTORY)
244 		ntfs_log_info(" | MFT_RECORD_IS_DIRECTORY");
245 	ntfs_log_info("\n");
246 	u = le32_to_cpu(m->bytes_in_use);
247 	ntfs_log_info("Bytes in use = %u (0x%x)\n", u, u);
248 	u = le32_to_cpu(m->bytes_allocated);
249 	ntfs_log_info("Bytes allocated = %u (0x%x)\n", u, u);
250 	r = le64_to_cpu(m->base_mft_record);
251 	ntfs_log_info("Base mft record reference:\n\tMft record number = %llu\n\t"
252 			"Sequence number = %u\n",
253 			(unsigned long long)MREF(r), MSEQNO(r));
254 	ntfs_log_info("Next attribute instance = %u\n",
255 			le16_to_cpu(m->next_attr_instance));
256 	a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
257 	ntfs_log_info("-- Beginning dump of attributes within mft record. --\n");
258 	while ((char*)a < (char*)m + le32_to_cpu(m->bytes_in_use)) {
259 		if (a->type == AT_END)
260 			break;
261 		a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
262 	};
263 	ntfs_log_info("-- End of attributes. --\n");
264 }
265 
266 /**
267  * ntfsmftalloc_exit
268  */
ntfsmftalloc_exit(void)269 static void ntfsmftalloc_exit(void)
270 {
271 	if (success)
272 		return;
273 	/* If there is a base inode, close that instead of the extent inode. */
274 	if (base_ni)
275 		ni = base_ni;
276 	/* Close the inode. */
277 	if (ni && ntfs_inode_close(ni)) {
278 		ntfs_log_perror("Warning: Failed to close inode 0x%llx",
279 				(long long)ni->mft_no);
280 	}
281 	/* Unmount the volume. */
282 	if (ntfs_umount(vol, 0) == -1)
283 		ntfs_log_perror("Warning: Could not umount %s", dev_name);
284 }
285 
286 /**
287  * main
288  */
main(int argc,char ** argv)289 int main(int argc, char **argv)
290 {
291 	unsigned long mnt_flags, ul;
292 	int err;
293 
294 	ntfs_log_set_handler(ntfs_log_handler_outerr);
295 
296 	/* Initialize opts to zero / required values. */
297 	memset(&opts, 0, sizeof(opts));
298 	/* Parse command line options. */
299 	parse_options(argc, argv);
300 	utils_set_locale();
301 	/* Make sure the file system is not mounted. */
302 	if (ntfs_check_if_mounted(dev_name, &mnt_flags))
303 		ntfs_log_error("Failed to determine whether %s is mounted: %s\n",
304 				dev_name, strerror(errno));
305 	else if (mnt_flags & NTFS_MF_MOUNTED) {
306 		ntfs_log_error("%s is mounted.\n", dev_name);
307 		if (!opts.force)
308 			err_exit("Refusing to run!\n");
309 		ntfs_log_error("ntfsmftalloc forced anyway. Hope /etc/mtab "
310 				"is incorrect.\n");
311 	}
312 	/* Mount the device. */
313 	if (opts.no_action) {
314 		ntfs_log_quiet("Running in READ-ONLY mode!\n");
315 		ul = NTFS_MNT_RDONLY;
316 	} else
317 		ul = 0;
318 	vol = ntfs_mount(dev_name, ul);
319 	if (!vol)
320 		err_exit("Failed to mount %s: %s\n", dev_name, strerror(errno));
321 	/* Register our exit function which will unlock and close the device. */
322 	err = atexit(&ntfsmftalloc_exit);
323 	if (err == -1) {
324 		ntfs_log_error("Could not set up exit() function because atexit() "
325 				"failed: %s Aborting...\n", strerror(errno));
326 		ntfsmftalloc_exit();
327 		exit(1);
328 	}
329 	if (base_mft_no != -1) {
330 		base_ni = ntfs_inode_open(vol, base_mft_no);
331 		if (!base_ni)
332 			err_exit("Failed to open base inode 0x%llx: %s\n",
333 					(long long)base_mft_no,
334 					strerror(errno));
335 	}
336 	/* Open the specified inode. */
337 	ni = ntfs_mft_record_alloc(vol, base_ni);
338 	if (!ni)
339 		err_exit("Failed to allocate mft record: %s\n",
340 				strerror(errno));
341 	ntfs_log_info("Allocated %s mft record 0x%llx", base_ni ? "extent" : "base",
342 			(long long)ni->mft_no);
343 	if (base_ni)
344 		ntfs_log_info(" with base mft record 0x%llx",
345 				(long long)base_mft_no);
346 	ntfs_log_info(".\n");
347 	if (!opts.quiet && opts.verbose > 1) {
348 		ntfs_log_verbose("Dumping allocated mft record 0x%llx:\n",
349 				(long long)ni->mft_no);
350 		dump_mft_record(ni->mrec);
351 	}
352 	/* Close the (base) inode. */
353 	if (base_ni)
354 		ni = base_ni;
355 	err = ntfs_inode_close(ni);
356 	if (err)
357 		err_exit("Failed to close inode 0x%llx: %s\n",
358 				(long long)ni->mft_no, strerror(errno));
359 	/* Unmount the volume. */
360 	err = ntfs_umount(vol, 0);
361 	/* Disable our ntfsmftalloc_exit() handler. */
362 	success = TRUE;
363 	if (err == -1)
364 		ntfs_log_perror("Warning: Failed to umount %s", dev_name);
365 	else
366 		ntfs_log_quiet("ntfsmftalloc completed successfully.\n");
367 	return 0;
368 }
369