summaryrefslogtreecommitdiff
path: root/ntfsprogs/ntfsmftalloc.c (plain)
blob: 246ab54a88d70894bfb4da556c6fa5947e596617
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
69static const char *EXEC_NAME = "ntfsmftalloc";
70
71/* Need these global so ntfsmftalloc_exit can access them. */
72static BOOL success = FALSE;
73
74static char *dev_name;
75
76static ntfs_volume *vol;
77static ntfs_inode *ni = NULL;
78static ntfs_inode *base_ni = NULL;
79static s64 base_mft_no = -1;
80
81static 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)))
97static 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 */
112static 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 */
126static 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))
135static 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 */
154static 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 */
218static 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)le64_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 */
269static 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 */
289int 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