blob: 506b5406327b33ed7d3ce35f18734c483482a348
1 | /** |
2 | * mkntfs - Part of the Linux-NTFS project. |
3 | * |
4 | * Copyright (c) 2000-2011 Anton Altaparmakov |
5 | * Copyright (c) 2001-2005 Richard Russon |
6 | * Copyright (c) 2002-2006 Szabolcs Szakacsits |
7 | * Copyright (c) 2005 Erik Sornes |
8 | * Copyright (c) 2007 Yura Pakhuchiy |
9 | * Copyright (c) 2010 Jean-Pierre Andre |
10 | * |
11 | * This utility will create an NTFS 1.2 or 3.1 volume on a user |
12 | * specified (block) device. |
13 | * |
14 | * Some things (option handling and determination of mount status) have been |
15 | * adapted from e2fsprogs-1.19 and lib/ext2fs/ismounted.c and misc/mke2fs.c in |
16 | * particular. |
17 | * |
18 | * This program is free software; you can redistribute it and/or modify |
19 | * it under the terms of the GNU General Public License as published by |
20 | * the Free Software Foundation; either version 2 of the License, or |
21 | * (at your option) any later version. |
22 | * |
23 | * This program is distributed in the hope that it will be useful, |
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
26 | * GNU General Public License for more details. |
27 | * |
28 | * You should have received a copy of the GNU General Public License |
29 | * along with this program (in the main directory of the Linux-NTFS source |
30 | * in the file COPYING); if not, write to the Free Software Foundation, |
31 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
32 | */ |
33 | |
34 | #ifdef HAVE_CONFIG_H |
35 | #include "config.h" |
36 | #endif |
37 | |
38 | #ifdef HAVE_UNISTD_H |
39 | #include <unistd.h> |
40 | #endif |
41 | #ifdef HAVE_STDLIB_H |
42 | #include <stdlib.h> |
43 | #endif |
44 | #ifdef HAVE_STDIO_H |
45 | #include <stdio.h> |
46 | #endif |
47 | #ifdef HAVE_STDARG_H |
48 | #include <stdarg.h> |
49 | #endif |
50 | #ifdef HAVE_STRING_H |
51 | #include <string.h> |
52 | #endif |
53 | #ifdef HAVE_ERRNO_H |
54 | #include <errno.h> |
55 | #endif |
56 | #ifdef HAVE_TIME_H |
57 | #include <time.h> |
58 | #endif |
59 | #ifdef HAVE_SYS_STAT_H |
60 | #include <sys/stat.h> |
61 | #endif |
62 | #ifdef HAVE_FCNTL_H |
63 | #include <fcntl.h> |
64 | #endif |
65 | #ifdef HAVE_LIMITS_H |
66 | #include <limits.h> |
67 | #endif |
68 | #ifdef HAVE_LIBGEN_H |
69 | #include <libgen.h> |
70 | #endif |
71 | #ifdef ENABLE_UUID |
72 | #include <uuid/uuid.h> |
73 | #endif |
74 | |
75 | |
76 | #ifdef HAVE_GETOPT_H |
77 | #include <getopt.h> |
78 | #else |
79 | extern char *optarg; |
80 | extern int optind; |
81 | #endif |
82 | |
83 | #ifdef HAVE_LINUX_MAJOR_H |
84 | # include <linux/major.h> |
85 | # ifndef MAJOR |
86 | # define MAJOR(dev) ((dev) >> 8) |
87 | # define MINOR(dev) ((dev) & 0xff) |
88 | # endif |
89 | # ifndef IDE_DISK_MAJOR |
90 | # ifndef IDE0_MAJOR |
91 | # define IDE0_MAJOR 3 |
92 | # define IDE1_MAJOR 22 |
93 | # define IDE2_MAJOR 33 |
94 | # define IDE3_MAJOR 34 |
95 | # define IDE4_MAJOR 56 |
96 | # define IDE5_MAJOR 57 |
97 | # define IDE6_MAJOR 88 |
98 | # define IDE7_MAJOR 89 |
99 | # define IDE8_MAJOR 90 |
100 | # define IDE9_MAJOR 91 |
101 | # endif |
102 | # define IDE_DISK_MAJOR(M) \ |
103 | ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \ |
104 | (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \ |
105 | (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \ |
106 | (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \ |
107 | (M) == IDE8_MAJOR || (M) == IDE9_MAJOR) |
108 | # endif |
109 | # ifndef SCSI_DISK_MAJOR |
110 | # ifndef SCSI_DISK0_MAJOR |
111 | # define SCSI_DISK0_MAJOR 8 |
112 | # define SCSI_DISK1_MAJOR 65 |
113 | # define SCSI_DISK7_MAJOR 71 |
114 | # endif |
115 | # define SCSI_DISK_MAJOR(M) \ |
116 | ((M) == SCSI_DISK0_MAJOR || \ |
117 | ((M) >= SCSI_DISK1_MAJOR && \ |
118 | (M) <= SCSI_DISK7_MAJOR)) |
119 | # endif |
120 | #endif |
121 | |
122 | #include "security.h" |
123 | #include "types.h" |
124 | #include "attrib.h" |
125 | #include "bitmap.h" |
126 | #include "bootsect.h" |
127 | #include "device.h" |
128 | #include "dir.h" |
129 | #include "mft.h" |
130 | #include "mst.h" |
131 | #include "runlist.h" |
132 | #include "utils.h" |
133 | #include "ntfstime.h" |
134 | #include "sd.h" |
135 | #include "boot.h" |
136 | #include "attrdef.h" |
137 | /* #include "version.h" */ |
138 | #include "logging.h" |
139 | #include "support.h" |
140 | #include "unistr.h" |
141 | #include "misc.h" |
142 | |
143 | #if defined(__sun) && defined (__SVR4) |
144 | #undef basename |
145 | #define basename(name) name |
146 | #endif |
147 | |
148 | #ifdef ANDROID |
149 | #define LOG_TAG "mkntfs" |
150 | #endif |
151 | |
152 | typedef enum { WRITE_STANDARD, WRITE_BITMAP, WRITE_LOGFILE } WRITE_TYPE; |
153 | |
154 | #ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS |
155 | #error "No default device io operations! Cannot build mkntfs. \ |
156 | You need to run ./configure without the --disable-default-device-io-ops \ |
157 | switch if you want to be able to build the NTFS utilities." |
158 | #endif |
159 | |
160 | /* Page size on ia32. Can change to 8192 on Alpha. */ |
161 | #define NTFS_PAGE_SIZE 4096 |
162 | |
163 | static char EXEC_NAME[] = "mkntfs"; |
164 | |
165 | struct BITMAP_ALLOCATION { |
166 | struct BITMAP_ALLOCATION *next; |
167 | LCN lcn; /* first allocated cluster */ |
168 | s64 length; /* count of consecutive clusters */ |
169 | } ; |
170 | |
171 | /* Upcase $Info, used since Windows 8 */ |
172 | struct UPCASEINFO { |
173 | le32 len; |
174 | le32 filler; |
175 | le64 crc; |
176 | le32 osmajor; |
177 | le32 osminor; |
178 | le32 build; |
179 | le16 packmajor; |
180 | le16 packminor; |
181 | } ; |
182 | |
183 | /** |
184 | * global variables |
185 | */ |
186 | static u8 *g_buf = NULL; |
187 | static int g_mft_bitmap_byte_size = 0; |
188 | static u8 *g_mft_bitmap = NULL; |
189 | static int g_lcn_bitmap_byte_size = 0; |
190 | static int g_dynamic_buf_size = 0; |
191 | static u8 *g_dynamic_buf = NULL; |
192 | static struct UPCASEINFO *g_upcaseinfo = NULL; |
193 | static runlist *g_rl_mft = NULL; |
194 | static runlist *g_rl_mft_bmp = NULL; |
195 | static runlist *g_rl_mftmirr = NULL; |
196 | static runlist *g_rl_logfile = NULL; |
197 | static runlist *g_rl_boot = NULL; |
198 | static runlist *g_rl_bad = NULL; |
199 | static INDEX_ALLOCATION *g_index_block = NULL; |
200 | static ntfs_volume *g_vol = NULL; |
201 | static int g_mft_size = 0; |
202 | static long long g_mft_lcn = 0; /* lcn of $MFT, $DATA attribute */ |
203 | static long long g_mftmirr_lcn = 0; /* lcn of $MFTMirr, $DATA */ |
204 | static long long g_logfile_lcn = 0; /* lcn of $LogFile, $DATA */ |
205 | static int g_logfile_size = 0; /* in bytes, determined from volume_size */ |
206 | static long long g_mft_zone_end = 0; /* Determined from volume_size and mft_zone_multiplier, in clusters */ |
207 | static long long g_num_bad_blocks = 0; /* Number of bad clusters */ |
208 | static long long *g_bad_blocks = NULL; /* Array of bad clusters */ |
209 | |
210 | static struct BITMAP_ALLOCATION *g_allocation = NULL; /* Head of cluster allocations */ |
211 | |
212 | /** |
213 | * struct mkntfs_options |
214 | */ |
215 | static struct mkntfs_options { |
216 | char *dev_name; /* Name of the device, or file, to use */ |
217 | BOOL enable_compression; /* -C, enables compression of all files on the volume by default. */ |
218 | BOOL quick_format; /* -f or -Q, fast format, don't zero the volume first. */ |
219 | BOOL force; /* -F, force fs creation. */ |
220 | long heads; /* -H, number of heads on device */ |
221 | BOOL disable_indexing; /* -I, disables indexing of file contents on the volume by default. */ |
222 | BOOL no_action; /* -n, do not write to device, only display what would be done. */ |
223 | long long part_start_sect; /* -p, start sector of partition on parent device */ |
224 | long sector_size; /* -s, in bytes, power of 2, default is 512 bytes. */ |
225 | long sectors_per_track; /* -S, number of sectors per track on device */ |
226 | BOOL use_epoch_time; /* -T, fake the time to be 00:00:00 UTC, Jan 1, 1970. */ |
227 | long mft_zone_multiplier; /* -z, value from 1 to 4. Default is 1. */ |
228 | long long num_sectors; /* size of device in sectors */ |
229 | long cluster_size; /* -c, format with this cluster-size */ |
230 | BOOL with_uuid; /* -U, request setting an uuid */ |
231 | char *label; /* -L, volume label */ |
232 | } opts; |
233 | |
234 | |
235 | /** |
236 | * mkntfs_license |
237 | */ |
238 | static void mkntfs_license(void) |
239 | { |
240 | ntfs_log_info("%s", ntfs_gpl); |
241 | } |
242 | |
243 | /** |
244 | * mkntfs_usage |
245 | */ |
246 | static void mkntfs_usage(void) |
247 | { |
248 | ntfs_log_info("\nUsage: %s [options] device [number-of-sectors]\n" |
249 | "\n" |
250 | "Basic options:\n" |
251 | " -f, --fast Perform a quick format\n" |
252 | " -Q, --quick Perform a quick format\n" |
253 | " -L, --label STRING Set the volume label\n" |
254 | " -C, --enable-compression Enable compression on the volume\n" |
255 | " -I, --no-indexing Disable indexing on the volume\n" |
256 | " -n, --no-action Do not write to disk\n" |
257 | "\n" |
258 | "Advanced options:\n" |
259 | " -c, --cluster-size BYTES Specify the cluster size for the volume\n" |
260 | " -s, --sector-size BYTES Specify the sector size for the device\n" |
261 | " -p, --partition-start SECTOR Specify the partition start sector\n" |
262 | " -H, --heads NUM Specify the number of heads\n" |
263 | " -S, --sectors-per-track NUM Specify the number of sectors per track\n" |
264 | " -z, --mft-zone-multiplier NUM Set the MFT zone multiplier\n" |
265 | " -T, --zero-time Fake the time to be 00:00 UTC, Jan 1, 1970\n" |
266 | " -F, --force Force execution despite errors\n" |
267 | "\n" |
268 | "Output options:\n" |
269 | " -q, --quiet Quiet execution\n" |
270 | " -v, --verbose Verbose execution\n" |
271 | " --debug Very verbose execution\n" |
272 | "\n" |
273 | "Help options:\n" |
274 | " -V, --version Display version\n" |
275 | " -l, --license Display licensing information\n" |
276 | " -h, --help Display this help\n" |
277 | "\n", basename(EXEC_NAME)); |
278 | ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); |
279 | } |
280 | |
281 | /** |
282 | * mkntfs_version |
283 | */ |
284 | static void mkntfs_version(void) |
285 | { |
286 | ntfs_log_info("\n%s v%s (libntfs-3g)\n\n", EXEC_NAME, VERSION); |
287 | ntfs_log_info("Create an NTFS volume on a user specified (block) " |
288 | "device.\n\n"); |
289 | ntfs_log_info("Copyright (c) 2000-2007 Anton Altaparmakov\n"); |
290 | ntfs_log_info("Copyright (c) 2001-2005 Richard Russon\n"); |
291 | ntfs_log_info("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); |
292 | ntfs_log_info("Copyright (c) 2005 Erik Sornes\n"); |
293 | ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n"); |
294 | ntfs_log_info("Copyright (c) 2010-2012 Jean-Pierre Andre\n"); |
295 | ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); |
296 | } |
297 | |
298 | /* |
299 | * crc64, adapted from http://rpm5.org/docs/api/digest_8c-source.html |
300 | * ECMA-182 polynomial, see |
301 | * http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-182.pdf |
302 | */ |
303 | /* make sure the needed types are defined */ |
304 | #undef byte |
305 | #undef uint32_t |
306 | #undef uint64_t |
307 | #define byte u8 |
308 | #define uint32_t u32 |
309 | #define uint64_t u64 |
310 | static uint64_t crc64(uint64_t crc, const byte * data, size_t size) |
311 | /*@*/ |
312 | { |
313 | static uint64_t polynomial = 0x9a6c9329ac4bc9b5ULL; |
314 | static uint64_t xorout = 0xffffffffffffffffULL; |
315 | static uint64_t table[256]; |
316 | |
317 | crc ^= xorout; |
318 | |
319 | if (data == NULL) { |
320 | /* generate the table of CRC remainders for all possible bytes */ |
321 | uint64_t c; |
322 | uint32_t i, j; |
323 | for (i = 0; i < 256; i++) { |
324 | c = i; |
325 | for (j = 0; j < 8; j++) { |
326 | if (c & 1) |
327 | c = polynomial ^ (c >> 1); |
328 | else |
329 | c = (c >> 1); |
330 | } |
331 | table[i] = c; |
332 | } |
333 | } else |
334 | while (size) { |
335 | crc = table[(crc ^ *data) & 0xff] ^ (crc >> 8); |
336 | size--; |
337 | data++; |
338 | } |
339 | |
340 | crc ^= xorout; |
341 | |
342 | return crc; |
343 | } |
344 | |
345 | /* |
346 | * Mark a run of clusters as allocated |
347 | * |
348 | * Returns FALSE if unsuccessful |
349 | */ |
350 | |
351 | static BOOL bitmap_allocate(LCN lcn, s64 length) |
352 | { |
353 | BOOL done; |
354 | struct BITMAP_ALLOCATION *p; |
355 | struct BITMAP_ALLOCATION *q; |
356 | struct BITMAP_ALLOCATION *newall; |
357 | |
358 | done = TRUE; |
359 | if (length) { |
360 | p = g_allocation; |
361 | q = (struct BITMAP_ALLOCATION*)NULL; |
362 | /* locate the first run which starts beyond the requested lcn */ |
363 | while (p && (p->lcn <= lcn)) { |
364 | q = p; |
365 | p = p->next; |
366 | } |
367 | /* make sure the requested lcns were not allocated */ |
368 | if ((q && ((q->lcn + q->length) > lcn)) |
369 | || (p && ((lcn + length) > p->lcn))) { |
370 | ntfs_log_error("Bitmap allocation error\n"); |
371 | done = FALSE; |
372 | } |
373 | if (q && ((q->lcn + q->length) == lcn)) { |
374 | /* extend current run, no overlapping possible */ |
375 | q->length += length; |
376 | } else { |
377 | newall = (struct BITMAP_ALLOCATION*) |
378 | ntfs_malloc(sizeof(struct BITMAP_ALLOCATION)); |
379 | if (newall) { |
380 | newall->lcn = lcn; |
381 | newall->length = length; |
382 | newall->next = p; |
383 | if (q) q->next = newall; |
384 | else g_allocation = newall; |
385 | } else { |
386 | done = FALSE; |
387 | ntfs_log_perror("Not enough memory"); |
388 | } |
389 | } |
390 | } |
391 | return (done); |
392 | } |
393 | |
394 | /* |
395 | * Mark a run of cluster as not allocated |
396 | * |
397 | * Returns FALSE if unsuccessful |
398 | * (freeing free clusters is not considered as an error) |
399 | */ |
400 | |
401 | static BOOL bitmap_deallocate(LCN lcn, s64 length) |
402 | { |
403 | BOOL done; |
404 | struct BITMAP_ALLOCATION *p; |
405 | struct BITMAP_ALLOCATION *q; |
406 | LCN first, last; |
407 | s64 begin_length, end_length; |
408 | |
409 | done = TRUE; |
410 | if (length) { |
411 | p = g_allocation; |
412 | q = (struct BITMAP_ALLOCATION*)NULL; |
413 | /* locate a run which has a common portion */ |
414 | while (p) { |
415 | first = (p->lcn > lcn ? p->lcn : lcn); |
416 | last = ((p->lcn + p->length) < (lcn + length) |
417 | ? p->lcn + p->length : lcn + length); |
418 | if (first < last) { |
419 | /* get the parts which must be kept */ |
420 | begin_length = first - p->lcn; |
421 | end_length = p->lcn + p->length - last; |
422 | /* delete the entry */ |
423 | if (q) |
424 | q->next = p->next; |
425 | else |
426 | g_allocation = p->next; |
427 | free(p); |
428 | /* reallocate the beginning and the end */ |
429 | if (begin_length |
430 | && !bitmap_allocate(first - begin_length, |
431 | begin_length)) |
432 | done = FALSE; |
433 | if (end_length |
434 | && !bitmap_allocate(last, end_length)) |
435 | done = FALSE; |
436 | /* restart a full search */ |
437 | p = g_allocation; |
438 | q = (struct BITMAP_ALLOCATION*)NULL; |
439 | } else { |
440 | q = p; |
441 | p = p->next; |
442 | } |
443 | } |
444 | } |
445 | return (done); |
446 | } |
447 | |
448 | /* |
449 | * Get the allocation status of a single cluster |
450 | * and mark as allocated |
451 | * |
452 | * Returns 1 if the cluster was previously allocated |
453 | */ |
454 | |
455 | static int bitmap_get_and_set(LCN lcn, unsigned long length) |
456 | { |
457 | struct BITMAP_ALLOCATION *p; |
458 | struct BITMAP_ALLOCATION *q; |
459 | int bit; |
460 | |
461 | if (length == 1) { |
462 | p = g_allocation; |
463 | q = (struct BITMAP_ALLOCATION*)NULL; |
464 | /* locate the first run which starts beyond the requested lcn */ |
465 | while (p && (p->lcn <= lcn)) { |
466 | q = p; |
467 | p = p->next; |
468 | } |
469 | if (q && (q->lcn <= lcn) && ((q->lcn + q->length) > lcn)) |
470 | bit = 1; /* was allocated */ |
471 | else { |
472 | bitmap_allocate(lcn, length); |
473 | bit = 0; |
474 | } |
475 | } else { |
476 | ntfs_log_error("Can only allocate a single cluster at a time\n"); |
477 | bit = 0; |
478 | } |
479 | return (bit); |
480 | } |
481 | |
482 | /* |
483 | * Build a section of the bitmap according to allocation |
484 | */ |
485 | |
486 | static void bitmap_build(u8 *buf, LCN lcn, s64 length) |
487 | { |
488 | struct BITMAP_ALLOCATION *p; |
489 | LCN first, last; |
490 | int j; /* byte number */ |
491 | int bn; /* bit number */ |
492 | |
493 | for (j=0; (8*j)<length; j++) |
494 | buf[j] = 0; |
495 | for (p=g_allocation; p; p=p->next) { |
496 | first = (p->lcn > lcn ? p->lcn : lcn); |
497 | last = ((p->lcn + p->length) < (lcn + length) |
498 | ? p->lcn + p->length : lcn + length); |
499 | if (first < last) { |
500 | bn = first - lcn; |
501 | /* initial partial byte, if any */ |
502 | while ((bn < (last - lcn)) && (bn & 7)) { |
503 | buf[bn >> 3] |= 1 << (bn & 7); |
504 | bn++; |
505 | } |
506 | /* full bytes */ |
507 | while (bn < (last - lcn - 7)) { |
508 | buf[bn >> 3] = 255; |
509 | bn += 8; |
510 | } |
511 | /* final partial byte, if any */ |
512 | while (bn < (last - lcn)) { |
513 | buf[bn >> 3] |= 1 << (bn & 7); |
514 | bn++; |
515 | } |
516 | } |
517 | } |
518 | } |
519 | |
520 | /** |
521 | * mkntfs_parse_long |
522 | */ |
523 | static BOOL mkntfs_parse_long(const char *string, const char *name, long *num) |
524 | { |
525 | char *end = NULL; |
526 | long tmp; |
527 | |
528 | if (!string || !name || !num) |
529 | return FALSE; |
530 | |
531 | if (*num >= 0) { |
532 | ntfs_log_error("You may only specify the %s once.\n", name); |
533 | return FALSE; |
534 | } |
535 | |
536 | tmp = strtol(string, &end, 0); |
537 | if (end && *end) { |
538 | ntfs_log_error("Cannot understand the %s '%s'.\n", name, string); |
539 | return FALSE; |
540 | } else { |
541 | *num = tmp; |
542 | return TRUE; |
543 | } |
544 | } |
545 | |
546 | /** |
547 | * mkntfs_parse_llong |
548 | */ |
549 | static BOOL mkntfs_parse_llong(const char *string, const char *name, |
550 | long long *num) |
551 | { |
552 | char *end = NULL; |
553 | long long tmp; |
554 | |
555 | if (!string || !name || !num) |
556 | return FALSE; |
557 | |
558 | if (*num >= 0) { |
559 | ntfs_log_error("You may only specify the %s once.\n", name); |
560 | return FALSE; |
561 | } |
562 | |
563 | tmp = strtoll(string, &end, 0); |
564 | if (end && *end) { |
565 | ntfs_log_error("Cannot understand the %s '%s'.\n", name, |
566 | string); |
567 | return FALSE; |
568 | } else { |
569 | *num = tmp; |
570 | return TRUE; |
571 | } |
572 | } |
573 | |
574 | /** |
575 | * mkntfs_init_options |
576 | */ |
577 | static void mkntfs_init_options(struct mkntfs_options *opts2) |
578 | { |
579 | if (!opts2) |
580 | return; |
581 | |
582 | memset(opts2, 0, sizeof(*opts2)); |
583 | |
584 | /* Mark all the numeric options as "unset". */ |
585 | opts2->cluster_size = -1; |
586 | opts2->heads = -1; |
587 | opts2->mft_zone_multiplier = -1; |
588 | opts2->num_sectors = -1; |
589 | opts2->part_start_sect = -1; |
590 | opts2->sector_size = -1; |
591 | opts2->sectors_per_track = -1; |
592 | } |
593 | |
594 | /** |
595 | * mkntfs_parse_options |
596 | */ |
597 | static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options *opts2) |
598 | { |
599 | static const char *sopt = "-c:CfFhH:IlL:np:qQs:S:TUvVz:"; |
600 | static const struct option lopt[] = { |
601 | { "cluster-size", required_argument, NULL, 'c' }, |
602 | { "debug", no_argument, NULL, 'Z' }, |
603 | { "enable-compression", no_argument, NULL, 'C' }, |
604 | { "fast", no_argument, NULL, 'f' }, |
605 | { "force", no_argument, NULL, 'F' }, |
606 | { "heads", required_argument, NULL, 'H' }, |
607 | { "help", no_argument, NULL, 'h' }, |
608 | { "label", required_argument, NULL, 'L' }, |
609 | { "license", no_argument, NULL, 'l' }, |
610 | { "mft-zone-multiplier",required_argument, NULL, 'z' }, |
611 | { "no-action", no_argument, NULL, 'n' }, |
612 | { "no-indexing", no_argument, NULL, 'I' }, |
613 | { "partition-start", required_argument, NULL, 'p' }, |
614 | { "quick", no_argument, NULL, 'Q' }, |
615 | { "quiet", no_argument, NULL, 'q' }, |
616 | { "sector-size", required_argument, NULL, 's' }, |
617 | { "sectors-per-track", required_argument, NULL, 'S' }, |
618 | { "with-uuid", no_argument, NULL, 'U' }, |
619 | { "verbose", no_argument, NULL, 'v' }, |
620 | { "version", no_argument, NULL, 'V' }, |
621 | { "zero-time", no_argument, NULL, 'T' }, |
622 | { NULL, 0, NULL, 0 } |
623 | }; |
624 | |
625 | int c = -1; |
626 | int lic = 0; |
627 | int err = 0; |
628 | int ver = 0; |
629 | |
630 | if (!argv || !opts2) { |
631 | ntfs_log_error("Internal error: invalid parameters to " |
632 | "mkntfs_options.\n"); |
633 | return FALSE; |
634 | } |
635 | |
636 | opterr = 0; /* We'll handle the errors, thank you. */ |
637 | |
638 | while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { |
639 | switch (c) { |
640 | case 1: /* A device, or a number of sectors */ |
641 | if (!opts2->dev_name) |
642 | opts2->dev_name = argv[optind - 1]; |
643 | else if (!mkntfs_parse_llong(optarg, |
644 | "number of sectors", |
645 | &opts2->num_sectors)) |
646 | err++; |
647 | break; |
648 | case 'C': |
649 | opts2->enable_compression = TRUE; |
650 | break; |
651 | case 'c': |
652 | if (!mkntfs_parse_long(optarg, "cluster size", |
653 | &opts2->cluster_size)) |
654 | err++; |
655 | break; |
656 | case 'F': |
657 | opts2->force = TRUE; |
658 | break; |
659 | case 'f': /* fast */ |
660 | case 'Q': /* quick */ |
661 | opts2->quick_format = TRUE; |
662 | break; |
663 | case 'H': |
664 | if (!mkntfs_parse_long(optarg, "heads", &opts2->heads)) |
665 | err++; |
666 | break; |
667 | case 'h': |
668 | err++; /* display help */ |
669 | break; |
670 | case 'I': |
671 | opts2->disable_indexing = TRUE; |
672 | break; |
673 | case 'L': |
674 | if (!opts2->label) { |
675 | opts2->label = argv[optind-1]; |
676 | } else { |
677 | ntfs_log_error("You may only specify the label " |
678 | "once.\n"); |
679 | err++; |
680 | } |
681 | break; |
682 | case 'l': |
683 | lic++; /* display the license */ |
684 | break; |
685 | case 'n': |
686 | opts2->no_action = TRUE; |
687 | break; |
688 | case 'p': |
689 | if (!mkntfs_parse_llong(optarg, "partition start", |
690 | &opts2->part_start_sect)) |
691 | err++; |
692 | break; |
693 | case 'q': |
694 | ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET | |
695 | NTFS_LOG_LEVEL_VERBOSE | |
696 | NTFS_LOG_LEVEL_PROGRESS); |
697 | break; |
698 | case 's': |
699 | if (!mkntfs_parse_long(optarg, "sector size", |
700 | &opts2->sector_size)) |
701 | err++; |
702 | break; |
703 | case 'S': |
704 | if (!mkntfs_parse_long(optarg, "sectors per track", |
705 | &opts2->sectors_per_track)) |
706 | err++; |
707 | break; |
708 | case 'T': |
709 | opts2->use_epoch_time = TRUE; |
710 | break; |
711 | case 'U': |
712 | opts2->with_uuid = TRUE; |
713 | break; |
714 | case 'v': |
715 | ntfs_log_set_levels(NTFS_LOG_LEVEL_QUIET | |
716 | NTFS_LOG_LEVEL_VERBOSE | |
717 | NTFS_LOG_LEVEL_PROGRESS); |
718 | break; |
719 | case 'V': |
720 | ver++; /* display version info */ |
721 | break; |
722 | case 'Z': /* debug - turn on everything */ |
723 | ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | |
724 | NTFS_LOG_LEVEL_TRACE | |
725 | NTFS_LOG_LEVEL_VERBOSE | |
726 | NTFS_LOG_LEVEL_QUIET); |
727 | break; |
728 | case 'z': |
729 | if (!mkntfs_parse_long(optarg, "mft zone multiplier", |
730 | &opts2->mft_zone_multiplier)) |
731 | err++; |
732 | break; |
733 | default: |
734 | if (ntfs_log_parse_option (argv[optind-1])) |
735 | break; |
736 | if (((optopt == 'c') || (optopt == 'H') || |
737 | (optopt == 'L') || (optopt == 'p') || |
738 | (optopt == 's') || (optopt == 'S') || |
739 | (optopt == 'N') || (optopt == 'z')) && |
740 | (!optarg)) { |
741 | ntfs_log_error("Option '%s' requires an " |
742 | "argument.\n", argv[optind-1]); |
743 | } else if (optopt != '?') { |
744 | ntfs_log_error("Unknown option '%s'.\n", |
745 | argv[optind - 1]); |
746 | } |
747 | err++; |
748 | break; |
749 | } |
750 | } |
751 | |
752 | if (!err && !ver && !lic) { |
753 | if (opts2->dev_name == NULL) { |
754 | if (argc > 1) |
755 | ntfs_log_error("You must specify a device.\n"); |
756 | err++; |
757 | } |
758 | } |
759 | |
760 | if (ver) |
761 | mkntfs_version(); |
762 | if (lic) |
763 | mkntfs_license(); |
764 | if (err) |
765 | mkntfs_usage(); |
766 | |
767 | return (!err && !ver && !lic); |
768 | } |
769 | |
770 | |
771 | /** |
772 | * mkntfs_time |
773 | */ |
774 | static ntfs_time mkntfs_time(void) |
775 | { |
776 | struct timespec ts; |
777 | |
778 | ts.tv_sec = 0; |
779 | ts.tv_nsec = 0; |
780 | if (!opts.use_epoch_time) |
781 | ts.tv_sec = time(NULL); |
782 | return timespec2ntfs(ts); |
783 | } |
784 | |
785 | /** |
786 | * append_to_bad_blocks |
787 | */ |
788 | static BOOL append_to_bad_blocks(unsigned long long block) |
789 | { |
790 | long long *new_buf; |
791 | |
792 | if (!(g_num_bad_blocks & 15)) { |
793 | new_buf = realloc(g_bad_blocks, (g_num_bad_blocks + 16) * |
794 | sizeof(long long)); |
795 | if (!new_buf) { |
796 | ntfs_log_perror("Reallocating memory for bad blocks " |
797 | "list failed"); |
798 | return FALSE; |
799 | } |
800 | g_bad_blocks = new_buf; |
801 | } |
802 | g_bad_blocks[g_num_bad_blocks++] = block; |
803 | return TRUE; |
804 | } |
805 | |
806 | /** |
807 | * mkntfs_write |
808 | */ |
809 | static long long mkntfs_write(struct ntfs_device *dev, |
810 | const void *b, long long count) |
811 | { |
812 | long long bytes_written, total; |
813 | int retry; |
814 | |
815 | if (opts.no_action) |
816 | return count; |
817 | total = 0LL; |
818 | retry = 0; |
819 | do { |
820 | bytes_written = dev->d_ops->write(dev, b, count); |
821 | if (bytes_written == -1LL) { |
822 | retry = errno; |
823 | ntfs_log_perror("Error writing to %s", dev->d_name); |
824 | errno = retry; |
825 | return bytes_written; |
826 | } else if (!bytes_written) { |
827 | retry++; |
828 | } else { |
829 | count -= bytes_written; |
830 | total += bytes_written; |
831 | } |
832 | } while (count && retry < 3); |
833 | if (count) |
834 | ntfs_log_error("Failed to complete writing to %s after three retries." |
835 | "\n", dev->d_name); |
836 | return total; |
837 | } |
838 | |
839 | /** |
840 | * Build and write a part of the global bitmap |
841 | * without overflowing from the allocated buffer |
842 | * |
843 | * mkntfs_bitmap_write |
844 | */ |
845 | static s64 mkntfs_bitmap_write(struct ntfs_device *dev, |
846 | s64 offset, s64 length) |
847 | { |
848 | s64 partial_length; |
849 | s64 written; |
850 | |
851 | partial_length = length; |
852 | if (partial_length > g_dynamic_buf_size) |
853 | partial_length = g_dynamic_buf_size; |
854 | /* create a partial bitmap section, and write it */ |
855 | bitmap_build(g_dynamic_buf,offset << 3,partial_length << 3); |
856 | written = dev->d_ops->write(dev, g_dynamic_buf, partial_length); |
857 | return (written); |
858 | } |
859 | |
860 | /** |
861 | * Build and write a part of the log file |
862 | * without overflowing from the allocated buffer |
863 | * |
864 | * mkntfs_logfile_write |
865 | */ |
866 | static s64 mkntfs_logfile_write(struct ntfs_device *dev, |
867 | s64 offset __attribute__((unused)), s64 length) |
868 | { |
869 | s64 partial_length; |
870 | s64 written; |
871 | |
872 | partial_length = length; |
873 | if (partial_length > g_dynamic_buf_size) |
874 | partial_length = g_dynamic_buf_size; |
875 | /* create a partial bad cluster section, and write it */ |
876 | memset(g_dynamic_buf, -1, partial_length); |
877 | written = dev->d_ops->write(dev, g_dynamic_buf, partial_length); |
878 | return (written); |
879 | } |
880 | |
881 | /** |
882 | * ntfs_rlwrite - Write to disk the clusters contained in the runlist @rl |
883 | * taking the data from @val. Take @val_len bytes from @val and pad the |
884 | * rest with zeroes. |
885 | * |
886 | * If the @rl specifies a completely sparse file, @val is allowed to be NULL. |
887 | * |
888 | * @inited_size if not NULL points to an output variable which will contain |
889 | * the actual number of bytes written to disk. I.e. this will not include |
890 | * sparse bytes for example. |
891 | * |
892 | * Return the number of bytes written (minus padding) or -1 on error. Errno |
893 | * will be set to the error code. |
894 | */ |
895 | static s64 ntfs_rlwrite(struct ntfs_device *dev, const runlist *rl, |
896 | const u8 *val, const s64 val_len, s64 *inited_size, |
897 | WRITE_TYPE write_type) |
898 | { |
899 | s64 bytes_written, total, length, delta; |
900 | int retry, i; |
901 | |
902 | if (inited_size) |
903 | *inited_size = 0LL; |
904 | if (opts.no_action) |
905 | return val_len; |
906 | total = 0LL; |
907 | delta = 0LL; |
908 | for (i = 0; rl[i].length; i++) { |
909 | length = rl[i].length * g_vol->cluster_size; |
910 | /* Don't write sparse runs. */ |
911 | if (rl[i].lcn == -1) { |
912 | total += length; |
913 | if (!val) |
914 | continue; |
915 | /* TODO: Check that *val is really zero at pos and len. */ |
916 | continue; |
917 | } |
918 | /* |
919 | * Break up the write into the real data write and then a write |
920 | * of zeroes between the end of the real data and the end of |
921 | * the (last) run. |
922 | */ |
923 | if (total + length > val_len) { |
924 | delta = length; |
925 | length = val_len - total; |
926 | delta -= length; |
927 | } |
928 | if (dev->d_ops->seek(dev, rl[i].lcn * g_vol->cluster_size, |
929 | SEEK_SET) == (off_t)-1) |
930 | return -1LL; |
931 | retry = 0; |
932 | do { |
933 | /* use specific functions if buffer is not prefilled */ |
934 | switch (write_type) { |
935 | case WRITE_BITMAP : |
936 | bytes_written = mkntfs_bitmap_write(dev, |
937 | total, length); |
938 | break; |
939 | case WRITE_LOGFILE : |
940 | bytes_written = mkntfs_logfile_write(dev, |
941 | total, length); |
942 | break; |
943 | default : |
944 | bytes_written = dev->d_ops->write(dev, |
945 | val + total, length); |
946 | break; |
947 | } |
948 | if (bytes_written == -1LL) { |
949 | retry = errno; |
950 | ntfs_log_perror("Error writing to %s", |
951 | dev->d_name); |
952 | errno = retry; |
953 | return bytes_written; |
954 | } |
955 | if (bytes_written) { |
956 | length -= bytes_written; |
957 | total += bytes_written; |
958 | if (inited_size) |
959 | *inited_size += bytes_written; |
960 | } else { |
961 | retry++; |
962 | } |
963 | } while (length && retry < 3); |
964 | if (length) { |
965 | ntfs_log_error("Failed to complete writing to %s after three " |
966 | "retries.\n", dev->d_name); |
967 | return total; |
968 | } |
969 | } |
970 | if (delta) { |
971 | int eo; |
972 | char *b = ntfs_calloc(delta); |
973 | if (!b) |
974 | return -1; |
975 | bytes_written = mkntfs_write(dev, b, delta); |
976 | eo = errno; |
977 | free(b); |
978 | errno = eo; |
979 | if (bytes_written == -1LL) |
980 | return bytes_written; |
981 | } |
982 | return total; |
983 | } |
984 | |
985 | /** |
986 | * make_room_for_attribute - make room for an attribute inside an mft record |
987 | * @m: mft record |
988 | * @pos: position at which to make space |
989 | * @size: byte size to make available at this position |
990 | * |
991 | * @pos points to the attribute in front of which we want to make space. |
992 | * |
993 | * Return 0 on success or -errno on error. Possible error codes are: |
994 | * |
995 | * -ENOSPC There is not enough space available to complete |
996 | * operation. The caller has to make space before calling |
997 | * this. |
998 | * -EINVAL Can only occur if mkntfs was compiled with -DDEBUG. Means |
999 | * the input parameters were faulty. |
1000 | */ |
1001 | static int make_room_for_attribute(MFT_RECORD *m, char *pos, const u32 size) |
1002 | { |
1003 | u32 biu; |
1004 | |
1005 | if (!size) |
1006 | return 0; |
1007 | #ifdef DEBUG |
1008 | /* |
1009 | * Rigorous consistency checks. Always return -EINVAL even if more |
1010 | * appropriate codes exist for simplicity of parsing the return value. |
1011 | */ |
1012 | if (size != ((size + 7) & ~7)) { |
1013 | ntfs_log_error("make_room_for_attribute() received non 8-byte aligned " |
1014 | "size.\n"); |
1015 | return -EINVAL; |
1016 | } |
1017 | if (!m || !pos) |
1018 | return -EINVAL; |
1019 | if (pos < (char*)m || pos + size < (char*)m || |
1020 | pos > (char*)m + le32_to_cpu(m->bytes_allocated) || |
1021 | pos + size > (char*)m + le32_to_cpu(m->bytes_allocated)) |
1022 | return -EINVAL; |
1023 | /* The -8 is for the attribute terminator. */ |
1024 | if (pos - (char*)m > (int)le32_to_cpu(m->bytes_in_use) - 8) |
1025 | return -EINVAL; |
1026 | #endif |
1027 | biu = le32_to_cpu(m->bytes_in_use); |
1028 | /* Do we have enough space? */ |
1029 | if (biu + size > le32_to_cpu(m->bytes_allocated)) |
1030 | return -ENOSPC; |
1031 | /* Move everything after pos to pos + size. */ |
1032 | memmove(pos + size, pos, biu - (pos - (char*)m)); |
1033 | /* Update mft record. */ |
1034 | m->bytes_in_use = cpu_to_le32(biu + size); |
1035 | return 0; |
1036 | } |
1037 | |
1038 | /** |
1039 | * deallocate_scattered_clusters |
1040 | */ |
1041 | static void deallocate_scattered_clusters(const runlist *rl) |
1042 | { |
1043 | int i; |
1044 | |
1045 | if (!rl) |
1046 | return; |
1047 | /* Iterate over all runs in the runlist @rl. */ |
1048 | for (i = 0; rl[i].length; i++) { |
1049 | /* Skip sparse runs. */ |
1050 | if (rl[i].lcn == -1LL) |
1051 | continue; |
1052 | /* Deallocate the current run. */ |
1053 | bitmap_deallocate(rl[i].lcn, rl[i].length); |
1054 | } |
1055 | } |
1056 | |
1057 | /** |
1058 | * allocate_scattered_clusters |
1059 | * @clusters: Amount of clusters to allocate. |
1060 | * |
1061 | * Allocate @clusters and create a runlist of the allocated clusters. |
1062 | * |
1063 | * Return the allocated runlist. Caller has to free the runlist when finished |
1064 | * with it. |
1065 | * |
1066 | * On error return NULL and errno is set to the error code. |
1067 | * |
1068 | * TODO: We should be returning the size as well, but for mkntfs this is not |
1069 | * necessary. |
1070 | */ |
1071 | static runlist * allocate_scattered_clusters(s64 clusters) |
1072 | { |
1073 | runlist *rl = NULL, *rlt; |
1074 | VCN vcn = 0LL; |
1075 | LCN lcn, end, prev_lcn = 0LL; |
1076 | int rlpos = 0; |
1077 | int rlsize = 0; |
1078 | s64 prev_run_len = 0LL; |
1079 | char bit; |
1080 | |
1081 | end = g_vol->nr_clusters; |
1082 | /* Loop until all clusters are allocated. */ |
1083 | while (clusters) { |
1084 | /* Loop in current zone until we run out of free clusters. */ |
1085 | for (lcn = g_mft_zone_end; lcn < end; lcn++) { |
1086 | bit = bitmap_get_and_set(lcn,1); |
1087 | if (bit) |
1088 | continue; |
1089 | /* |
1090 | * Reallocate memory if necessary. Make sure we have |
1091 | * enough for the terminator entry as well. |
1092 | */ |
1093 | if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) { |
1094 | rlsize += 4096; /* PAGE_SIZE */ |
1095 | rlt = realloc(rl, rlsize); |
1096 | if (!rlt) |
1097 | goto err_end; |
1098 | rl = rlt; |
1099 | } |
1100 | /* Coalesce with previous run if adjacent LCNs. */ |
1101 | if (prev_lcn == lcn - prev_run_len) { |
1102 | rl[rlpos - 1].length = ++prev_run_len; |
1103 | vcn++; |
1104 | } else { |
1105 | rl[rlpos].vcn = vcn++; |
1106 | rl[rlpos].lcn = lcn; |
1107 | prev_lcn = lcn; |
1108 | rl[rlpos].length = 1LL; |
1109 | prev_run_len = 1LL; |
1110 | rlpos++; |
1111 | } |
1112 | /* Done? */ |
1113 | if (!--clusters) { |
1114 | /* Add terminator element and return. */ |
1115 | rl[rlpos].vcn = vcn; |
1116 | rl[rlpos].lcn = 0LL; |
1117 | rl[rlpos].length = 0LL; |
1118 | return rl; |
1119 | } |
1120 | |
1121 | } |
1122 | /* Switch to next zone, decreasing mft zone by factor 2. */ |
1123 | end = g_mft_zone_end; |
1124 | g_mft_zone_end >>= 1; |
1125 | /* Have we run out of space on the volume? */ |
1126 | if (g_mft_zone_end <= 0) |
1127 | goto err_end; |
1128 | } |
1129 | return rl; |
1130 | err_end: |
1131 | if (rl) { |
1132 | /* Add terminator element. */ |
1133 | rl[rlpos].vcn = vcn; |
1134 | rl[rlpos].lcn = -1LL; |
1135 | rl[rlpos].length = 0LL; |
1136 | /* Deallocate all allocated clusters. */ |
1137 | deallocate_scattered_clusters(rl); |
1138 | /* Free the runlist. */ |
1139 | free(rl); |
1140 | } |
1141 | return NULL; |
1142 | } |
1143 | |
1144 | /** |
1145 | * ntfs_attr_find - find (next) attribute in mft record |
1146 | * @type: attribute type to find |
1147 | * @name: attribute name to find (optional, i.e. NULL means don't care) |
1148 | * @name_len: attribute name length (only needed if @name present) |
1149 | * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) |
1150 | * @val: attribute value to find (optional, resident attributes only) |
1151 | * @val_len: attribute value length |
1152 | * @ctx: search context with mft record and attribute to search from |
1153 | * |
1154 | * You shouldn't need to call this function directly. Use lookup_attr() instead. |
1155 | * |
1156 | * ntfs_attr_find() takes a search context @ctx as parameter and searches the |
1157 | * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an |
1158 | * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() |
1159 | * returns 0 and @ctx->attr will point to the found attribute. |
1160 | * |
1161 | * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and |
1162 | * @ctx->attr will point to the attribute before which the attribute being |
1163 | * searched for would need to be inserted if such an action were to be desired. |
1164 | * |
1165 | * On actual error, ntfs_attr_find() returns -1 with errno set to the error |
1166 | * code but not to ENOENT. In this case @ctx->attr is undefined and in |
1167 | * particular do not rely on it not changing. |
1168 | * |
1169 | * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it |
1170 | * is FALSE, the search begins after @ctx->attr. |
1171 | * |
1172 | * If @type is AT_UNUSED, return the first found attribute, i.e. one can |
1173 | * enumerate all attributes by setting @type to AT_UNUSED and then calling |
1174 | * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to |
1175 | * indicate that there are no more entries. During the enumeration, each |
1176 | * successful call of ntfs_attr_find() will return the next attribute in the |
1177 | * mft record @ctx->mrec. |
1178 | * |
1179 | * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. |
1180 | * AT_END is not a valid attribute, its length is zero for example, thus it is |
1181 | * safer to return error instead of success in this case. This also allows us |
1182 | * to interoperate cleanly with ntfs_external_attr_find(). |
1183 | * |
1184 | * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present |
1185 | * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, |
1186 | * match both named and unnamed attributes. |
1187 | * |
1188 | * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and |
1189 | * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record |
1190 | * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at |
1191 | * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case |
1192 | * sensitive. When @name is present, @name_len is the @name length in Unicode |
1193 | * characters. |
1194 | * |
1195 | * If @name is not present (NULL), we assume that the unnamed attribute is |
1196 | * being searched for. |
1197 | * |
1198 | * Finally, the resident attribute value @val is looked for, if present. |
1199 | * If @val is not present (NULL), @val_len is ignored. |
1200 | * |
1201 | * ntfs_attr_find() only searches the specified mft record and it ignores the |
1202 | * presence of an attribute list attribute (unless it is the one being searched |
1203 | * for, obviously). If you need to take attribute lists into consideration, use |
1204 | * ntfs_attr_lookup() instead (see below). This also means that you cannot use |
1205 | * ntfs_attr_find() to search for extent records of non-resident attributes, as |
1206 | * extents with lowest_vcn != 0 are usually described by the attribute list |
1207 | * attribute only. - Note that it is possible that the first extent is only in |
1208 | * the attribute list while the last extent is in the base mft record, so don't |
1209 | * rely on being able to find the first extent in the base mft record. |
1210 | * |
1211 | * Warning: Never use @val when looking for attribute types which can be |
1212 | * non-resident as this most likely will result in a crash! |
1213 | */ |
1214 | static int mkntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, |
1215 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
1216 | const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) |
1217 | { |
1218 | ATTR_RECORD *a; |
1219 | ntfschar *upcase = g_vol->upcase; |
1220 | u32 upcase_len = g_vol->upcase_len; |
1221 | |
1222 | /* |
1223 | * Iterate over attributes in mft record starting at @ctx->attr, or the |
1224 | * attribute following that, if @ctx->is_first is TRUE. |
1225 | */ |
1226 | if (ctx->is_first) { |
1227 | a = ctx->attr; |
1228 | ctx->is_first = FALSE; |
1229 | } else { |
1230 | a = (ATTR_RECORD*)((char*)ctx->attr + |
1231 | le32_to_cpu(ctx->attr->length)); |
1232 | } |
1233 | for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) { |
1234 | if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec + |
1235 | le32_to_cpu(ctx->mrec->bytes_allocated)) |
1236 | break; |
1237 | ctx->attr = a; |
1238 | if (((type != AT_UNUSED) && (le32_to_cpu(a->type) > |
1239 | le32_to_cpu(type))) || |
1240 | (a->type == AT_END)) { |
1241 | errno = ENOENT; |
1242 | return -1; |
1243 | } |
1244 | if (!a->length) |
1245 | break; |
1246 | /* If this is an enumeration return this attribute. */ |
1247 | if (type == AT_UNUSED) |
1248 | return 0; |
1249 | if (a->type != type) |
1250 | continue; |
1251 | /* |
1252 | * If @name is AT_UNNAMED we want an unnamed attribute. |
1253 | * If @name is present, compare the two names. |
1254 | * Otherwise, match any attribute. |
1255 | */ |
1256 | if (name == AT_UNNAMED) { |
1257 | /* The search failed if the found attribute is named. */ |
1258 | if (a->name_length) { |
1259 | errno = ENOENT; |
1260 | return -1; |
1261 | } |
1262 | } else if (name && !ntfs_names_are_equal(name, name_len, |
1263 | (ntfschar*)((char*)a + le16_to_cpu(a->name_offset)), |
1264 | a->name_length, ic, upcase, upcase_len)) { |
1265 | int rc; |
1266 | |
1267 | rc = ntfs_names_full_collate(name, name_len, |
1268 | (ntfschar*)((char*)a + |
1269 | le16_to_cpu(a->name_offset)), |
1270 | a->name_length, IGNORE_CASE, |
1271 | upcase, upcase_len); |
1272 | /* |
1273 | * If @name collates before a->name, there is no |
1274 | * matching attribute. |
1275 | */ |
1276 | if (rc == -1) { |
1277 | errno = ENOENT; |
1278 | return -1; |
1279 | } |
1280 | /* If the strings are not equal, continue search. */ |
1281 | if (rc) |
1282 | continue; |
1283 | rc = ntfs_names_full_collate(name, name_len, |
1284 | (ntfschar*)((char*)a + |
1285 | le16_to_cpu(a->name_offset)), |
1286 | a->name_length, CASE_SENSITIVE, |
1287 | upcase, upcase_len); |
1288 | if (rc == -1) { |
1289 | errno = ENOENT; |
1290 | return -1; |
1291 | } |
1292 | if (rc) |
1293 | continue; |
1294 | } |
1295 | /* |
1296 | * The names match or @name not present and attribute is |
1297 | * unnamed. If no @val specified, we have found the attribute |
1298 | * and are done. |
1299 | */ |
1300 | if (!val) { |
1301 | return 0; |
1302 | /* @val is present; compare values. */ |
1303 | } else { |
1304 | int rc; |
1305 | |
1306 | rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset), |
1307 | min(val_len, |
1308 | le32_to_cpu(a->value_length))); |
1309 | /* |
1310 | * If @val collates before the current attribute's |
1311 | * value, there is no matching attribute. |
1312 | */ |
1313 | if (!rc) { |
1314 | u32 avl; |
1315 | avl = le32_to_cpu(a->value_length); |
1316 | if (val_len == avl) |
1317 | return 0; |
1318 | if (val_len < avl) { |
1319 | errno = ENOENT; |
1320 | return -1; |
1321 | } |
1322 | } else if (rc < 0) { |
1323 | errno = ENOENT; |
1324 | return -1; |
1325 | } |
1326 | } |
1327 | } |
1328 | ntfs_log_trace("File is corrupt. Run chkdsk.\n"); |
1329 | errno = EIO; |
1330 | return -1; |
1331 | } |
1332 | |
1333 | /** |
1334 | * ntfs_attr_lookup - find an attribute in an ntfs inode |
1335 | * @type: attribute type to find |
1336 | * @name: attribute name to find (optional, i.e. NULL means don't care) |
1337 | * @name_len: attribute name length (only needed if @name present) |
1338 | * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) |
1339 | * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) |
1340 | * @val: attribute value to find (optional, resident attributes only) |
1341 | * @val_len: attribute value length |
1342 | * @ctx: search context with mft record and attribute to search from |
1343 | * |
1344 | * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must |
1345 | * be the base mft record and @ctx must have been obtained from a call to |
1346 | * ntfs_attr_get_search_ctx(). |
1347 | * |
1348 | * This function transparently handles attribute lists and @ctx is used to |
1349 | * continue searches where they were left off at. |
1350 | * |
1351 | * If @type is AT_UNUSED, return the first found attribute, i.e. one can |
1352 | * enumerate all attributes by setting @type to AT_UNUSED and then calling |
1353 | * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT |
1354 | * to indicate that there are no more entries. During the enumeration, each |
1355 | * successful call of ntfs_attr_lookup() will return the next attribute, with |
1356 | * the current attribute being described by the search context @ctx. |
1357 | * |
1358 | * If @type is AT_END, seek to the end of the base mft record ignoring the |
1359 | * attribute list completely and return -1 with errno set to ENOENT. AT_END is |
1360 | * not a valid attribute, its length is zero for example, thus it is safer to |
1361 | * return error instead of success in this case. It should never be needed to |
1362 | * do this, but we implement the functionality because it allows for simpler |
1363 | * code inside ntfs_external_attr_find(). |
1364 | * |
1365 | * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present |
1366 | * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, |
1367 | * match both named and unnamed attributes. |
1368 | * |
1369 | * After finishing with the attribute/mft record you need to call |
1370 | * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any |
1371 | * mapped extent inodes, etc). |
1372 | * |
1373 | * Return 0 if the search was successful and -1 if not, with errno set to the |
1374 | * error code. |
1375 | * |
1376 | * On success, @ctx->attr is the found attribute, it is in mft record |
1377 | * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this |
1378 | * attribute with @ctx->base_* being the base mft record to which @ctx->attr |
1379 | * belongs. If no attribute list attribute is present @ctx->al_entry and |
1380 | * @ctx->base_* are NULL. |
1381 | * |
1382 | * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the |
1383 | * attribute which collates just after the attribute being searched for in the |
1384 | * base ntfs inode, i.e. if one wants to add the attribute to the mft record |
1385 | * this is the correct place to insert it into, and if there is not enough |
1386 | * space, the attribute should be placed in an extent mft record. |
1387 | * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list |
1388 | * at which the new attribute's attribute list entry should be inserted. The |
1389 | * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. |
1390 | * The only exception to this is when @type is AT_END, in which case |
1391 | * @ctx->al_entry is set to NULL also (see above). |
1392 | * |
1393 | * The following error codes are defined: |
1394 | * ENOENT Attribute not found, not an error as such. |
1395 | * EINVAL Invalid arguments. |
1396 | * EIO I/O error or corrupt data structures found. |
1397 | * ENOMEM Not enough memory to allocate necessary buffers. |
1398 | */ |
1399 | static int mkntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, |
1400 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
1401 | const VCN lowest_vcn __attribute__((unused)), const u8 *val, |
1402 | const u32 val_len, ntfs_attr_search_ctx *ctx) |
1403 | { |
1404 | ntfs_inode *base_ni; |
1405 | |
1406 | if (!ctx || !ctx->mrec || !ctx->attr) { |
1407 | errno = EINVAL; |
1408 | return -1; |
1409 | } |
1410 | if (ctx->base_ntfs_ino) |
1411 | base_ni = ctx->base_ntfs_ino; |
1412 | else |
1413 | base_ni = ctx->ntfs_ino; |
1414 | if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) |
1415 | return mkntfs_attr_find(type, name, name_len, ic, val, val_len, |
1416 | ctx); |
1417 | errno = EOPNOTSUPP; |
1418 | return -1; |
1419 | } |
1420 | |
1421 | /** |
1422 | * insert_positioned_attr_in_mft_record |
1423 | * |
1424 | * Create a non-resident attribute with a predefined on disk location |
1425 | * specified by the runlist @rl. The clusters specified by @rl are assumed to |
1426 | * be allocated already. |
1427 | * |
1428 | * Return 0 on success and -errno on error. |
1429 | */ |
1430 | static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, |
1431 | const ATTR_TYPES type, const char *name, u32 name_len, |
1432 | const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, |
1433 | const runlist *rl, const u8 *val, const s64 val_len) |
1434 | { |
1435 | ntfs_attr_search_ctx *ctx; |
1436 | ATTR_RECORD *a; |
1437 | u16 hdr_size; |
1438 | int asize, mpa_size, err, i; |
1439 | s64 bw = 0, inited_size; |
1440 | VCN highest_vcn; |
1441 | ntfschar *uname = NULL; |
1442 | int uname_len = 0; |
1443 | /* |
1444 | if (base record) |
1445 | attr_lookup(); |
1446 | else |
1447 | */ |
1448 | |
1449 | uname = ntfs_str2ucs(name, &uname_len); |
1450 | if (!uname) |
1451 | return -errno; |
1452 | |
1453 | /* Check if the attribute is already there. */ |
1454 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
1455 | if (!ctx) { |
1456 | ntfs_log_error("Failed to allocate attribute search context.\n"); |
1457 | err = -ENOMEM; |
1458 | goto err_out; |
1459 | } |
1460 | if (ic == IGNORE_CASE) { |
1461 | ntfs_log_error("FIXME: Hit unimplemented code path #1.\n"); |
1462 | err = -EOPNOTSUPP; |
1463 | goto err_out; |
1464 | } |
1465 | if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, NULL, 0, ctx)) { |
1466 | err = -EEXIST; |
1467 | goto err_out; |
1468 | } |
1469 | if (errno != ENOENT) { |
1470 | ntfs_log_error("Corrupt inode.\n"); |
1471 | err = -errno; |
1472 | goto err_out; |
1473 | } |
1474 | a = ctx->attr; |
1475 | if (flags & ATTR_COMPRESSION_MASK) { |
1476 | ntfs_log_error("Compressed attributes not supported yet.\n"); |
1477 | /* FIXME: Compress attribute into a temporary buffer, set */ |
1478 | /* val accordingly and save the compressed size. */ |
1479 | err = -EOPNOTSUPP; |
1480 | goto err_out; |
1481 | } |
1482 | if (flags & (ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) { |
1483 | ntfs_log_error("Encrypted/sparse attributes not supported.\n"); |
1484 | err = -EOPNOTSUPP; |
1485 | goto err_out; |
1486 | } |
1487 | if (flags & ATTR_COMPRESSION_MASK) { |
1488 | hdr_size = 72; |
1489 | /* FIXME: This compression stuff is all wrong. Never mind for */ |
1490 | /* now. (AIA) */ |
1491 | if (val_len) |
1492 | mpa_size = 0; /* get_size_for_compressed_mapping_pairs(rl); */ |
1493 | else |
1494 | mpa_size = 0; |
1495 | } else { |
1496 | hdr_size = 64; |
1497 | if (val_len) { |
1498 | mpa_size = ntfs_get_size_for_mapping_pairs(g_vol, rl, 0, INT_MAX); |
1499 | if (mpa_size < 0) { |
1500 | err = -errno; |
1501 | ntfs_log_error("Failed to get size for mapping " |
1502 | "pairs.\n"); |
1503 | goto err_out; |
1504 | } |
1505 | } else { |
1506 | mpa_size = 0; |
1507 | } |
1508 | } |
1509 | /* Mapping pairs array and next attribute must be 8-byte aligned. */ |
1510 | asize = (((int)hdr_size + ((name_len + 7) & ~7) + mpa_size) + 7) & ~7; |
1511 | /* Get the highest vcn. */ |
1512 | for (i = 0, highest_vcn = 0LL; rl[i].length; i++) |
1513 | highest_vcn += rl[i].length; |
1514 | /* Does the value fit inside the allocated size? */ |
1515 | if (highest_vcn * g_vol->cluster_size < val_len) { |
1516 | ntfs_log_error("BUG: Allocated size is smaller than data size!\n"); |
1517 | err = -EINVAL; |
1518 | goto err_out; |
1519 | } |
1520 | err = make_room_for_attribute(m, (char*)a, asize); |
1521 | if (err == -ENOSPC) { |
1522 | /* |
1523 | * FIXME: Make space! (AIA) |
1524 | * can we make it non-resident? if yes, do that. |
1525 | * does it fit now? yes -> do it. |
1526 | * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? |
1527 | * yes -> make non-resident |
1528 | * does it fit now? yes -> do it. |
1529 | * make all attributes non-resident |
1530 | * does it fit now? yes -> do it. |
1531 | * m is a base record? yes -> allocate extension record |
1532 | * does the new attribute fit in there? yes -> do it. |
1533 | * split up runlist into extents and place each in an extension |
1534 | * record. |
1535 | * FIXME: the check for needing extension records should be |
1536 | * earlier on as it is very quick: asize > m->bytes_allocated? |
1537 | */ |
1538 | err = -EOPNOTSUPP; |
1539 | goto err_out; |
1540 | #ifdef DEBUG |
1541 | } else if (err == -EINVAL) { |
1542 | ntfs_log_error("BUG(): in insert_positioned_attribute_in_mft_" |
1543 | "record(): make_room_for_attribute() returned " |
1544 | "error: EINVAL!\n"); |
1545 | goto err_out; |
1546 | #endif |
1547 | } |
1548 | a->type = type; |
1549 | a->length = cpu_to_le32(asize); |
1550 | a->non_resident = 1; |
1551 | a->name_length = name_len; |
1552 | a->name_offset = cpu_to_le16(hdr_size); |
1553 | a->flags = flags; |
1554 | a->instance = m->next_attr_instance; |
1555 | m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) |
1556 | + 1) & 0xffff); |
1557 | a->lowest_vcn = cpu_to_le64(0); |
1558 | a->highest_vcn = cpu_to_sle64(highest_vcn - 1LL); |
1559 | a->mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); |
1560 | memset(a->reserved1, 0, sizeof(a->reserved1)); |
1561 | /* FIXME: Allocated size depends on compression. */ |
1562 | a->allocated_size = cpu_to_sle64(highest_vcn * g_vol->cluster_size); |
1563 | a->data_size = cpu_to_sle64(val_len); |
1564 | if (name_len) |
1565 | memcpy((char*)a + hdr_size, uname, name_len << 1); |
1566 | if (flags & ATTR_COMPRESSION_MASK) { |
1567 | if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) { |
1568 | ntfs_log_error("Unknown compression format. Reverting " |
1569 | "to standard compression.\n"); |
1570 | a->flags &= ~ATTR_COMPRESSION_MASK; |
1571 | a->flags |= ATTR_IS_COMPRESSED; |
1572 | } |
1573 | a->compression_unit = 4; |
1574 | inited_size = val_len; |
1575 | /* FIXME: Set the compressed size. */ |
1576 | a->compressed_size = cpu_to_le64(0); |
1577 | /* FIXME: Write out the compressed data. */ |
1578 | /* FIXME: err = build_mapping_pairs_compressed(); */ |
1579 | err = -EOPNOTSUPP; |
1580 | } else { |
1581 | a->compression_unit = 0; |
1582 | if ((type == AT_DATA) |
1583 | && (m->mft_record_number |
1584 | == const_cpu_to_le32(FILE_LogFile))) |
1585 | bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len, |
1586 | &inited_size, WRITE_LOGFILE); |
1587 | else |
1588 | bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len, |
1589 | &inited_size, WRITE_STANDARD); |
1590 | if (bw != val_len) { |
1591 | ntfs_log_error("Error writing non-resident attribute " |
1592 | "value.\n"); |
1593 | return -errno; |
1594 | } |
1595 | err = ntfs_mapping_pairs_build(g_vol, (u8*)a + hdr_size + |
1596 | ((name_len + 7) & ~7), mpa_size, rl, 0, NULL); |
1597 | } |
1598 | a->initialized_size = cpu_to_sle64(inited_size); |
1599 | if (err < 0 || bw != val_len) { |
1600 | /* FIXME: Handle error. */ |
1601 | /* deallocate clusters */ |
1602 | /* remove attribute */ |
1603 | if (err >= 0) |
1604 | err = -EIO; |
1605 | ntfs_log_error("insert_positioned_attr_in_mft_record failed " |
1606 | "with error %i.\n", err < 0 ? err : (int)bw); |
1607 | } |
1608 | err_out: |
1609 | if (ctx) |
1610 | ntfs_attr_put_search_ctx(ctx); |
1611 | ntfs_ucsfree(uname); |
1612 | return err; |
1613 | } |
1614 | |
1615 | /** |
1616 | * insert_non_resident_attr_in_mft_record |
1617 | * |
1618 | * Return 0 on success and -errno on error. |
1619 | */ |
1620 | static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, |
1621 | const ATTR_TYPES type, const char *name, u32 name_len, |
1622 | const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, |
1623 | const u8 *val, const s64 val_len, |
1624 | WRITE_TYPE write_type) |
1625 | { |
1626 | ntfs_attr_search_ctx *ctx; |
1627 | ATTR_RECORD *a; |
1628 | u16 hdr_size; |
1629 | int asize, mpa_size, err, i; |
1630 | runlist *rl = NULL; |
1631 | s64 bw = 0; |
1632 | ntfschar *uname = NULL; |
1633 | int uname_len = 0; |
1634 | /* |
1635 | if (base record) |
1636 | attr_lookup(); |
1637 | else |
1638 | */ |
1639 | |
1640 | uname = ntfs_str2ucs(name, &uname_len); |
1641 | if (!uname) |
1642 | return -errno; |
1643 | |
1644 | /* Check if the attribute is already there. */ |
1645 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
1646 | if (!ctx) { |
1647 | ntfs_log_error("Failed to allocate attribute search context.\n"); |
1648 | err = -ENOMEM; |
1649 | goto err_out; |
1650 | } |
1651 | if (ic == IGNORE_CASE) { |
1652 | ntfs_log_error("FIXME: Hit unimplemented code path #2.\n"); |
1653 | err = -EOPNOTSUPP; |
1654 | goto err_out; |
1655 | } |
1656 | if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, NULL, 0, ctx)) { |
1657 | err = -EEXIST; |
1658 | goto err_out; |
1659 | } |
1660 | if (errno != ENOENT) { |
1661 | ntfs_log_error("Corrupt inode.\n"); |
1662 | err = -errno; |
1663 | goto err_out; |
1664 | } |
1665 | a = ctx->attr; |
1666 | if (flags & ATTR_COMPRESSION_MASK) { |
1667 | ntfs_log_error("Compressed attributes not supported yet.\n"); |
1668 | /* FIXME: Compress attribute into a temporary buffer, set */ |
1669 | /* val accordingly and save the compressed size. */ |
1670 | err = -EOPNOTSUPP; |
1671 | goto err_out; |
1672 | } |
1673 | if (flags & (ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) { |
1674 | ntfs_log_error("Encrypted/sparse attributes not supported.\n"); |
1675 | err = -EOPNOTSUPP; |
1676 | goto err_out; |
1677 | } |
1678 | if (val_len) { |
1679 | rl = allocate_scattered_clusters((val_len + |
1680 | g_vol->cluster_size - 1) / g_vol->cluster_size); |
1681 | if (!rl) { |
1682 | err = -errno; |
1683 | ntfs_log_perror("Failed to allocate scattered clusters"); |
1684 | goto err_out; |
1685 | } |
1686 | } else { |
1687 | rl = NULL; |
1688 | } |
1689 | if (flags & ATTR_COMPRESSION_MASK) { |
1690 | hdr_size = 72; |
1691 | /* FIXME: This compression stuff is all wrong. Never mind for */ |
1692 | /* now. (AIA) */ |
1693 | if (val_len) |
1694 | mpa_size = 0; /* get_size_for_compressed_mapping_pairs(rl); */ |
1695 | else |
1696 | mpa_size = 0; |
1697 | } else { |
1698 | hdr_size = 64; |
1699 | if (val_len) { |
1700 | mpa_size = ntfs_get_size_for_mapping_pairs(g_vol, rl, 0, INT_MAX); |
1701 | if (mpa_size < 0) { |
1702 | err = -errno; |
1703 | ntfs_log_error("Failed to get size for mapping " |
1704 | "pairs.\n"); |
1705 | goto err_out; |
1706 | } |
1707 | } else { |
1708 | mpa_size = 0; |
1709 | } |
1710 | } |
1711 | /* Mapping pairs array and next attribute must be 8-byte aligned. */ |
1712 | asize = (((int)hdr_size + ((name_len + 7) & ~7) + mpa_size) + 7) & ~7; |
1713 | err = make_room_for_attribute(m, (char*)a, asize); |
1714 | if (err == -ENOSPC) { |
1715 | /* |
1716 | * FIXME: Make space! (AIA) |
1717 | * can we make it non-resident? if yes, do that. |
1718 | * does it fit now? yes -> do it. |
1719 | * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? |
1720 | * yes -> make non-resident |
1721 | * does it fit now? yes -> do it. |
1722 | * make all attributes non-resident |
1723 | * does it fit now? yes -> do it. |
1724 | * m is a base record? yes -> allocate extension record |
1725 | * does the new attribute fit in there? yes -> do it. |
1726 | * split up runlist into extents and place each in an extension |
1727 | * record. |
1728 | * FIXME: the check for needing extension records should be |
1729 | * earlier on as it is very quick: asize > m->bytes_allocated? |
1730 | */ |
1731 | err = -EOPNOTSUPP; |
1732 | goto err_out; |
1733 | #ifdef DEBUG |
1734 | } else if (err == -EINVAL) { |
1735 | ntfs_log_error("BUG(): in insert_non_resident_attribute_in_" |
1736 | "mft_record(): make_room_for_attribute() " |
1737 | "returned error: EINVAL!\n"); |
1738 | goto err_out; |
1739 | #endif |
1740 | } |
1741 | a->type = type; |
1742 | a->length = cpu_to_le32(asize); |
1743 | a->non_resident = 1; |
1744 | a->name_length = name_len; |
1745 | a->name_offset = cpu_to_le16(hdr_size); |
1746 | a->flags = flags; |
1747 | a->instance = m->next_attr_instance; |
1748 | m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) |
1749 | + 1) & 0xffff); |
1750 | a->lowest_vcn = cpu_to_le64(0); |
1751 | for (i = 0; rl[i].length; i++) |
1752 | ; |
1753 | a->highest_vcn = cpu_to_sle64(rl[i].vcn - 1); |
1754 | a->mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); |
1755 | memset(a->reserved1, 0, sizeof(a->reserved1)); |
1756 | /* FIXME: Allocated size depends on compression. */ |
1757 | a->allocated_size = cpu_to_sle64((val_len + (g_vol->cluster_size - 1)) & |
1758 | ~(g_vol->cluster_size - 1)); |
1759 | a->data_size = cpu_to_sle64(val_len); |
1760 | a->initialized_size = cpu_to_sle64(val_len); |
1761 | if (name_len) |
1762 | memcpy((char*)a + hdr_size, uname, name_len << 1); |
1763 | if (flags & ATTR_COMPRESSION_MASK) { |
1764 | if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) { |
1765 | ntfs_log_error("Unknown compression format. Reverting " |
1766 | "to standard compression.\n"); |
1767 | a->flags &= ~ATTR_COMPRESSION_MASK; |
1768 | a->flags |= ATTR_IS_COMPRESSED; |
1769 | } |
1770 | a->compression_unit = 4; |
1771 | /* FIXME: Set the compressed size. */ |
1772 | a->compressed_size = cpu_to_le64(0); |
1773 | /* FIXME: Write out the compressed data. */ |
1774 | /* FIXME: err = build_mapping_pairs_compressed(); */ |
1775 | err = -EOPNOTSUPP; |
1776 | } else { |
1777 | a->compression_unit = 0; |
1778 | bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len, NULL, |
1779 | write_type); |
1780 | if (bw != val_len) { |
1781 | ntfs_log_error("Error writing non-resident attribute " |
1782 | "value.\n"); |
1783 | return -errno; |
1784 | } |
1785 | err = ntfs_mapping_pairs_build(g_vol, (u8*)a + hdr_size + |
1786 | ((name_len + 7) & ~7), mpa_size, rl, 0, NULL); |
1787 | } |
1788 | if (err < 0 || bw != val_len) { |
1789 | /* FIXME: Handle error. */ |
1790 | /* deallocate clusters */ |
1791 | /* remove attribute */ |
1792 | if (err >= 0) |
1793 | err = -EIO; |
1794 | ntfs_log_error("insert_non_resident_attr_in_mft_record failed with " |
1795 | "error %lld.\n", (long long) (err < 0 ? err : bw)); |
1796 | } |
1797 | err_out: |
1798 | if (ctx) |
1799 | ntfs_attr_put_search_ctx(ctx); |
1800 | ntfs_ucsfree(uname); |
1801 | free(rl); |
1802 | return err; |
1803 | } |
1804 | |
1805 | /** |
1806 | * insert_resident_attr_in_mft_record |
1807 | * |
1808 | * Return 0 on success and -errno on error. |
1809 | */ |
1810 | static int insert_resident_attr_in_mft_record(MFT_RECORD *m, |
1811 | const ATTR_TYPES type, const char *name, u32 name_len, |
1812 | const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, |
1813 | const RESIDENT_ATTR_FLAGS res_flags, |
1814 | const u8 *val, const u32 val_len) |
1815 | { |
1816 | ntfs_attr_search_ctx *ctx; |
1817 | ATTR_RECORD *a; |
1818 | int asize, err; |
1819 | ntfschar *uname = NULL; |
1820 | int uname_len = 0; |
1821 | /* |
1822 | if (base record) |
1823 | mkntfs_attr_lookup(); |
1824 | else |
1825 | */ |
1826 | |
1827 | uname = ntfs_str2ucs(name, &uname_len); |
1828 | if (!uname) |
1829 | return -errno; |
1830 | |
1831 | /* Check if the attribute is already there. */ |
1832 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
1833 | if (!ctx) { |
1834 | ntfs_log_error("Failed to allocate attribute search context.\n"); |
1835 | err = -ENOMEM; |
1836 | goto err_out; |
1837 | } |
1838 | if (ic == IGNORE_CASE) { |
1839 | ntfs_log_error("FIXME: Hit unimplemented code path #3.\n"); |
1840 | err = -EOPNOTSUPP; |
1841 | goto err_out; |
1842 | } |
1843 | if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, val, val_len, |
1844 | ctx)) { |
1845 | err = -EEXIST; |
1846 | goto err_out; |
1847 | } |
1848 | if (errno != ENOENT) { |
1849 | ntfs_log_error("Corrupt inode.\n"); |
1850 | err = -errno; |
1851 | goto err_out; |
1852 | } |
1853 | a = ctx->attr; |
1854 | /* sizeof(resident attribute record header) == 24 */ |
1855 | asize = ((24 + ((name_len*2 + 7) & ~7) + val_len) + 7) & ~7; |
1856 | err = make_room_for_attribute(m, (char*)a, asize); |
1857 | if (err == -ENOSPC) { |
1858 | /* |
1859 | * FIXME: Make space! (AIA) |
1860 | * can we make it non-resident? if yes, do that. |
1861 | * does it fit now? yes -> do it. |
1862 | * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? |
1863 | * yes -> make non-resident |
1864 | * does it fit now? yes -> do it. |
1865 | * make all attributes non-resident |
1866 | * does it fit now? yes -> do it. |
1867 | * m is a base record? yes -> allocate extension record |
1868 | * does the new attribute fit in there? yes -> do it. |
1869 | * split up runlist into extents and place each in an extension |
1870 | * record. |
1871 | * FIXME: the check for needing extension records should be |
1872 | * earlier on as it is very quick: asize > m->bytes_allocated? |
1873 | */ |
1874 | err = -EOPNOTSUPP; |
1875 | goto err_out; |
1876 | } |
1877 | #ifdef DEBUG |
1878 | if (err == -EINVAL) { |
1879 | ntfs_log_error("BUG(): in insert_resident_attribute_in_mft_" |
1880 | "record(): make_room_for_attribute() returned " |
1881 | "error: EINVAL!\n"); |
1882 | goto err_out; |
1883 | } |
1884 | #endif |
1885 | a->type = type; |
1886 | a->length = cpu_to_le32(asize); |
1887 | a->non_resident = 0; |
1888 | a->name_length = name_len; |
1889 | if (type == AT_OBJECT_ID) |
1890 | a->name_offset = const_cpu_to_le16(0); |
1891 | else |
1892 | a->name_offset = const_cpu_to_le16(24); |
1893 | a->flags = flags; |
1894 | a->instance = m->next_attr_instance; |
1895 | m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) |
1896 | + 1) & 0xffff); |
1897 | a->value_length = cpu_to_le32(val_len); |
1898 | a->value_offset = cpu_to_le16(24 + ((name_len*2 + 7) & ~7)); |
1899 | a->resident_flags = res_flags; |
1900 | a->reservedR = 0; |
1901 | if (name_len) |
1902 | memcpy((char*)a + 24, uname, name_len << 1); |
1903 | if (val_len) |
1904 | memcpy((char*)a + le16_to_cpu(a->value_offset), val, val_len); |
1905 | err_out: |
1906 | if (ctx) |
1907 | ntfs_attr_put_search_ctx(ctx); |
1908 | ntfs_ucsfree(uname); |
1909 | return err; |
1910 | } |
1911 | |
1912 | |
1913 | /** |
1914 | * add_attr_std_info |
1915 | * |
1916 | * Return 0 on success or -errno on error. |
1917 | */ |
1918 | static int add_attr_std_info(MFT_RECORD *m, const FILE_ATTR_FLAGS flags, |
1919 | le32 security_id) |
1920 | { |
1921 | STANDARD_INFORMATION si; |
1922 | int err, sd_size; |
1923 | |
1924 | sd_size = 48; |
1925 | |
1926 | si.creation_time = mkntfs_time(); |
1927 | si.last_data_change_time = si.creation_time; |
1928 | si.last_mft_change_time = si.creation_time; |
1929 | si.last_access_time = si.creation_time; |
1930 | si.file_attributes = flags; /* already LE */ |
1931 | si.maximum_versions = cpu_to_le32(0); |
1932 | si.version_number = cpu_to_le32(0); |
1933 | si.class_id = cpu_to_le32(0); |
1934 | si.security_id = security_id; |
1935 | if (si.security_id != const_cpu_to_le32(0)) |
1936 | sd_size = 72; |
1937 | /* FIXME: $Quota support... */ |
1938 | si.owner_id = cpu_to_le32(0); |
1939 | si.quota_charged = cpu_to_le64(0ULL); |
1940 | /* FIXME: $UsnJrnl support... Not needed on fresh w2k3-volume */ |
1941 | si.usn = cpu_to_le64(0ULL); |
1942 | /* NTFS 1.2: size of si = 48, NTFS 3.[01]: size of si = 72 */ |
1943 | err = insert_resident_attr_in_mft_record(m, AT_STANDARD_INFORMATION, |
1944 | NULL, 0, CASE_SENSITIVE, const_cpu_to_le16(0), |
1945 | 0, (u8*)&si, sd_size); |
1946 | if (err < 0) |
1947 | ntfs_log_perror("add_attr_std_info failed"); |
1948 | return err; |
1949 | } |
1950 | |
1951 | /* |
1952 | * Tell whether the unnamed data is non resident |
1953 | */ |
1954 | |
1955 | static BOOL non_resident_unnamed_data(MFT_RECORD *m) |
1956 | { |
1957 | ATTR_RECORD *a; |
1958 | ntfs_attr_search_ctx *ctx; |
1959 | BOOL nonres; |
1960 | |
1961 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
1962 | if (ctx && !mkntfs_attr_find(AT_DATA, |
1963 | (const ntfschar*)NULL, 0, CASE_SENSITIVE, |
1964 | (u8*)NULL, 0, ctx)) { |
1965 | a = ctx->attr; |
1966 | nonres = a->non_resident != 0; |
1967 | } else { |
1968 | ntfs_log_error("BUG: Unnamed data not found\n"); |
1969 | nonres = TRUE; |
1970 | } |
1971 | if (ctx) |
1972 | ntfs_attr_put_search_ctx(ctx); |
1973 | return (nonres); |
1974 | } |
1975 | |
1976 | /* |
1977 | * Get the time stored in the standard information attribute |
1978 | */ |
1979 | |
1980 | static ntfs_time stdinfo_time(MFT_RECORD *m) |
1981 | { |
1982 | STANDARD_INFORMATION *si; |
1983 | ntfs_attr_search_ctx *ctx; |
1984 | ntfs_time info_time; |
1985 | |
1986 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
1987 | if (ctx && !mkntfs_attr_find(AT_STANDARD_INFORMATION, |
1988 | (const ntfschar*)NULL, 0, CASE_SENSITIVE, |
1989 | (u8*)NULL, 0, ctx)) { |
1990 | si = (STANDARD_INFORMATION*)((char*)ctx->attr + |
1991 | le16_to_cpu(ctx->attr->value_offset)); |
1992 | info_time = si->creation_time; |
1993 | } else { |
1994 | ntfs_log_error("BUG: Standard information not found\n"); |
1995 | info_time = mkntfs_time(); |
1996 | } |
1997 | if (ctx) |
1998 | ntfs_attr_put_search_ctx(ctx); |
1999 | return (info_time); |
2000 | } |
2001 | |
2002 | /** |
2003 | * add_attr_file_name |
2004 | * |
2005 | * Return 0 on success or -errno on error. |
2006 | */ |
2007 | static int add_attr_file_name(MFT_RECORD *m, const leMFT_REF parent_dir, |
2008 | const s64 allocated_size, const s64 data_size, |
2009 | const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, |
2010 | const u32 reparse_point_tag, const char *file_name, |
2011 | const FILE_NAME_TYPE_FLAGS file_name_type) |
2012 | { |
2013 | ntfs_attr_search_ctx *ctx; |
2014 | STANDARD_INFORMATION *si; |
2015 | FILE_NAME_ATTR *fn; |
2016 | int i, fn_size; |
2017 | ntfschar *uname; |
2018 | |
2019 | /* Check if the attribute is already there. */ |
2020 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
2021 | if (!ctx) { |
2022 | ntfs_log_error("Failed to get attribute search context.\n"); |
2023 | return -ENOMEM; |
2024 | } |
2025 | if (mkntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, |
2026 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
2027 | int eo = errno; |
2028 | ntfs_log_error("BUG: Standard information attribute not " |
2029 | "present in file record.\n"); |
2030 | ntfs_attr_put_search_ctx(ctx); |
2031 | return -eo; |
2032 | } |
2033 | si = (STANDARD_INFORMATION*)((char*)ctx->attr + |
2034 | le16_to_cpu(ctx->attr->value_offset)); |
2035 | i = (strlen(file_name) + 1) * sizeof(ntfschar); |
2036 | fn_size = sizeof(FILE_NAME_ATTR) + i; |
2037 | fn = ntfs_malloc(fn_size); |
2038 | if (!fn) { |
2039 | ntfs_attr_put_search_ctx(ctx); |
2040 | return -errno; |
2041 | } |
2042 | fn->parent_directory = parent_dir; |
2043 | |
2044 | fn->creation_time = si->creation_time; |
2045 | fn->last_data_change_time = si->last_data_change_time; |
2046 | fn->last_mft_change_time = si->last_mft_change_time; |
2047 | fn->last_access_time = si->last_access_time; |
2048 | ntfs_attr_put_search_ctx(ctx); |
2049 | |
2050 | fn->allocated_size = cpu_to_sle64(allocated_size); |
2051 | fn->data_size = cpu_to_sle64(data_size); |
2052 | fn->file_attributes = flags; |
2053 | /* These are in a union so can't have both. */ |
2054 | if (packed_ea_size && reparse_point_tag) { |
2055 | free(fn); |
2056 | return -EINVAL; |
2057 | } |
2058 | if (packed_ea_size) { |
2059 | fn->packed_ea_size = cpu_to_le16(packed_ea_size); |
2060 | fn->reserved = cpu_to_le16(0); |
2061 | } else { |
2062 | fn->reparse_point_tag = cpu_to_le32(reparse_point_tag); |
2063 | } |
2064 | fn->file_name_type = file_name_type; |
2065 | uname = fn->file_name; |
2066 | i = ntfs_mbstoucs_libntfscompat(file_name, &uname, i); |
2067 | if (i < 1) { |
2068 | free(fn); |
2069 | return -EINVAL; |
2070 | } |
2071 | if (i > 0xff) { |
2072 | free(fn); |
2073 | return -ENAMETOOLONG; |
2074 | } |
2075 | /* No terminating null in file names. */ |
2076 | fn->file_name_length = i; |
2077 | fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); |
2078 | i = insert_resident_attr_in_mft_record(m, AT_FILE_NAME, NULL, 0, |
2079 | CASE_SENSITIVE, const_cpu_to_le16(0), |
2080 | RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); |
2081 | free(fn); |
2082 | if (i < 0) |
2083 | ntfs_log_error("add_attr_file_name failed: %s\n", strerror(-i)); |
2084 | return i; |
2085 | } |
2086 | |
2087 | /** |
2088 | * add_attr_object_id - |
2089 | * |
2090 | * Note we insert only a basic object id which only has the GUID and none of |
2091 | * the extended fields. This is because we currently only use this function |
2092 | * when creating the object id for the volume. |
2093 | * |
2094 | * Return 0 on success or -errno on error. |
2095 | */ |
2096 | static int add_attr_object_id(MFT_RECORD *m, const GUID *object_id) |
2097 | { |
2098 | OBJECT_ID_ATTR oi; |
2099 | int err; |
2100 | |
2101 | oi = (OBJECT_ID_ATTR) { |
2102 | .object_id = *object_id, |
2103 | }; |
2104 | err = insert_resident_attr_in_mft_record(m, AT_OBJECT_ID, NULL, |
2105 | 0, CASE_SENSITIVE, const_cpu_to_le16(0), |
2106 | 0, (u8*)&oi, sizeof(oi.object_id)); |
2107 | if (err < 0) |
2108 | ntfs_log_error("add_attr_vol_info failed: %s\n", strerror(-err)); |
2109 | return err; |
2110 | } |
2111 | |
2112 | /** |
2113 | * add_attr_sd |
2114 | * |
2115 | * Create the security descriptor attribute adding the security descriptor @sd |
2116 | * of length @sd_len to the mft record @m. |
2117 | * |
2118 | * Return 0 on success or -errno on error. |
2119 | */ |
2120 | static int add_attr_sd(MFT_RECORD *m, const u8 *sd, const s64 sd_len) |
2121 | { |
2122 | int err; |
2123 | |
2124 | /* Does it fit? NO: create non-resident. YES: create resident. */ |
2125 | if (le32_to_cpu(m->bytes_in_use) + 24 + sd_len > |
2126 | le32_to_cpu(m->bytes_allocated)) |
2127 | err = insert_non_resident_attr_in_mft_record(m, |
2128 | AT_SECURITY_DESCRIPTOR, NULL, 0, |
2129 | CASE_SENSITIVE, const_cpu_to_le16(0), sd, |
2130 | sd_len, WRITE_STANDARD); |
2131 | else |
2132 | err = insert_resident_attr_in_mft_record(m, |
2133 | AT_SECURITY_DESCRIPTOR, NULL, 0, |
2134 | CASE_SENSITIVE, const_cpu_to_le16(0), 0, sd, |
2135 | sd_len); |
2136 | if (err < 0) |
2137 | ntfs_log_error("add_attr_sd failed: %s\n", strerror(-err)); |
2138 | return err; |
2139 | } |
2140 | |
2141 | /** |
2142 | * add_attr_data |
2143 | * |
2144 | * Return 0 on success or -errno on error. |
2145 | */ |
2146 | static int add_attr_data(MFT_RECORD *m, const char *name, const u32 name_len, |
2147 | const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, |
2148 | const u8 *val, const s64 val_len) |
2149 | { |
2150 | int err; |
2151 | |
2152 | /* |
2153 | * Does it fit? NO: create non-resident. YES: create resident. |
2154 | * |
2155 | * FIXME: Introduced arbitrary limit of mft record allocated size - 512. |
2156 | * This is to get around the problem that if $Bitmap/$DATA becomes too |
2157 | * big, but is just small enough to be resident, we would make it |
2158 | * resident, and later run out of space when creating the other |
2159 | * attributes and this would cause us to abort as making resident |
2160 | * attributes non-resident is not supported yet. |
2161 | * The proper fix is to support making resident attribute non-resident. |
2162 | */ |
2163 | if (le32_to_cpu(m->bytes_in_use) + 24 + val_len > |
2164 | min(le32_to_cpu(m->bytes_allocated), |
2165 | le32_to_cpu(m->bytes_allocated) - 512)) |
2166 | err = insert_non_resident_attr_in_mft_record(m, AT_DATA, name, |
2167 | name_len, ic, flags, val, val_len, |
2168 | WRITE_STANDARD); |
2169 | else |
2170 | err = insert_resident_attr_in_mft_record(m, AT_DATA, name, |
2171 | name_len, ic, flags, 0, val, val_len); |
2172 | |
2173 | if (err < 0) |
2174 | ntfs_log_error("add_attr_data failed: %s\n", strerror(-err)); |
2175 | return err; |
2176 | } |
2177 | |
2178 | /** |
2179 | * add_attr_data_positioned |
2180 | * |
2181 | * Create a non-resident data attribute with a predefined on disk location |
2182 | * specified by the runlist @rl. The clusters specified by @rl are assumed to |
2183 | * be allocated already. |
2184 | * |
2185 | * Return 0 on success or -errno on error. |
2186 | */ |
2187 | static int add_attr_data_positioned(MFT_RECORD *m, const char *name, |
2188 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
2189 | const ATTR_FLAGS flags, const runlist *rl, |
2190 | const u8 *val, const s64 val_len) |
2191 | { |
2192 | int err; |
2193 | |
2194 | err = insert_positioned_attr_in_mft_record(m, AT_DATA, name, name_len, |
2195 | ic, flags, rl, val, val_len); |
2196 | if (err < 0) |
2197 | ntfs_log_error("add_attr_data_positioned failed: %s\n", |
2198 | strerror(-err)); |
2199 | return err; |
2200 | } |
2201 | |
2202 | /** |
2203 | * add_attr_vol_name |
2204 | * |
2205 | * Create volume name attribute specifying the volume name @vol_name as a null |
2206 | * terminated char string of length @vol_name_len (number of characters not |
2207 | * including the terminating null), which is converted internally to a little |
2208 | * endian ntfschar string. The name is at least 1 character long (though |
2209 | * Windows accepts zero characters), and at most 128 characters long (not |
2210 | * counting the terminating null). |
2211 | * |
2212 | * Return 0 on success or -errno on error. |
2213 | */ |
2214 | static int add_attr_vol_name(MFT_RECORD *m, const char *vol_name, |
2215 | const int vol_name_len __attribute__((unused))) |
2216 | { |
2217 | ntfschar *uname = NULL; |
2218 | int uname_len = 0; |
2219 | int i; |
2220 | |
2221 | if (vol_name) { |
2222 | uname_len = ntfs_mbstoucs(vol_name, &uname); |
2223 | if (uname_len < 0) |
2224 | return -errno; |
2225 | if (uname_len > 128) { |
2226 | free(uname); |
2227 | return -ENAMETOOLONG; |
2228 | } |
2229 | } |
2230 | i = insert_resident_attr_in_mft_record(m, AT_VOLUME_NAME, NULL, 0, |
2231 | CASE_SENSITIVE, const_cpu_to_le16(0), |
2232 | 0, (u8*)uname, uname_len*sizeof(ntfschar)); |
2233 | free(uname); |
2234 | if (i < 0) |
2235 | ntfs_log_error("add_attr_vol_name failed: %s\n", strerror(-i)); |
2236 | return i; |
2237 | } |
2238 | |
2239 | /** |
2240 | * add_attr_vol_info |
2241 | * |
2242 | * Return 0 on success or -errno on error. |
2243 | */ |
2244 | static int add_attr_vol_info(MFT_RECORD *m, const VOLUME_FLAGS flags, |
2245 | const u8 major_ver, const u8 minor_ver) |
2246 | { |
2247 | VOLUME_INFORMATION vi; |
2248 | int err; |
2249 | |
2250 | memset(&vi, 0, sizeof(vi)); |
2251 | vi.major_ver = major_ver; |
2252 | vi.minor_ver = minor_ver; |
2253 | vi.flags = flags & VOLUME_FLAGS_MASK; |
2254 | err = insert_resident_attr_in_mft_record(m, AT_VOLUME_INFORMATION, NULL, |
2255 | 0, CASE_SENSITIVE, const_cpu_to_le16(0), |
2256 | 0, (u8*)&vi, sizeof(vi)); |
2257 | if (err < 0) |
2258 | ntfs_log_error("add_attr_vol_info failed: %s\n", strerror(-err)); |
2259 | return err; |
2260 | } |
2261 | |
2262 | /** |
2263 | * add_attr_index_root |
2264 | * |
2265 | * Return 0 on success or -errno on error. |
2266 | */ |
2267 | static int add_attr_index_root(MFT_RECORD *m, const char *name, |
2268 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
2269 | const ATTR_TYPES indexed_attr_type, |
2270 | const COLLATION_RULES collation_rule, |
2271 | const u32 index_block_size) |
2272 | { |
2273 | INDEX_ROOT *r; |
2274 | INDEX_ENTRY_HEADER *e; |
2275 | int err, val_len; |
2276 | |
2277 | val_len = sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER); |
2278 | r = ntfs_malloc(val_len); |
2279 | if (!r) |
2280 | return -errno; |
2281 | r->type = (indexed_attr_type == AT_FILE_NAME) |
2282 | ? AT_FILE_NAME : const_cpu_to_le32(0); |
2283 | if (indexed_attr_type == AT_FILE_NAME && |
2284 | collation_rule != COLLATION_FILE_NAME) { |
2285 | free(r); |
2286 | ntfs_log_error("add_attr_index_root: indexed attribute is $FILE_NAME " |
2287 | "but collation rule is not COLLATION_FILE_NAME.\n"); |
2288 | return -EINVAL; |
2289 | } |
2290 | r->collation_rule = collation_rule; |
2291 | r->index_block_size = cpu_to_le32(index_block_size); |
2292 | if (index_block_size >= g_vol->cluster_size) { |
2293 | if (index_block_size % g_vol->cluster_size) { |
2294 | ntfs_log_error("add_attr_index_root: index block size is not " |
2295 | "a multiple of the cluster size.\n"); |
2296 | free(r); |
2297 | return -EINVAL; |
2298 | } |
2299 | r->clusters_per_index_block = index_block_size / |
2300 | g_vol->cluster_size; |
2301 | } else { /* if (g_vol->cluster_size > index_block_size) */ |
2302 | if (index_block_size & (index_block_size - 1)) { |
2303 | ntfs_log_error("add_attr_index_root: index block size is not " |
2304 | "a power of 2.\n"); |
2305 | free(r); |
2306 | return -EINVAL; |
2307 | } |
2308 | if (index_block_size < (u32)opts.sector_size) { |
2309 | ntfs_log_error("add_attr_index_root: index block size " |
2310 | "is smaller than the sector size.\n"); |
2311 | free(r); |
2312 | return -EINVAL; |
2313 | } |
2314 | r->clusters_per_index_block = index_block_size |
2315 | >> NTFS_BLOCK_SIZE_BITS; |
2316 | } |
2317 | memset(&r->reserved, 0, sizeof(r->reserved)); |
2318 | r->index.entries_offset = const_cpu_to_le32(sizeof(INDEX_HEADER)); |
2319 | r->index.index_length = const_cpu_to_le32(sizeof(INDEX_HEADER) + |
2320 | sizeof(INDEX_ENTRY_HEADER)); |
2321 | r->index.allocated_size = r->index.index_length; |
2322 | r->index.ih_flags = SMALL_INDEX; |
2323 | memset(&r->index.reserved, 0, sizeof(r->index.reserved)); |
2324 | e = (INDEX_ENTRY_HEADER*)((u8*)&r->index + |
2325 | le32_to_cpu(r->index.entries_offset)); |
2326 | /* |
2327 | * No matter whether this is a file index or a view as this is a |
2328 | * termination entry, hence no key value / data is associated with it |
2329 | * at all. Thus, we just need the union to be all zero. |
2330 | */ |
2331 | e->indexed_file = const_cpu_to_le64(0LL); |
2332 | e->length = const_cpu_to_le16(sizeof(INDEX_ENTRY_HEADER)); |
2333 | e->key_length = const_cpu_to_le16(0); |
2334 | e->flags = INDEX_ENTRY_END; |
2335 | e->reserved = const_cpu_to_le16(0); |
2336 | err = insert_resident_attr_in_mft_record(m, AT_INDEX_ROOT, name, |
2337 | name_len, ic, const_cpu_to_le16(0), 0, |
2338 | (u8*)r, val_len); |
2339 | free(r); |
2340 | if (err < 0) |
2341 | ntfs_log_error("add_attr_index_root failed: %s\n", strerror(-err)); |
2342 | return err; |
2343 | } |
2344 | |
2345 | /** |
2346 | * add_attr_index_alloc |
2347 | * |
2348 | * Return 0 on success or -errno on error. |
2349 | */ |
2350 | static int add_attr_index_alloc(MFT_RECORD *m, const char *name, |
2351 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
2352 | const u8 *index_alloc_val, const u32 index_alloc_val_len) |
2353 | { |
2354 | int err; |
2355 | |
2356 | err = insert_non_resident_attr_in_mft_record(m, AT_INDEX_ALLOCATION, |
2357 | name, name_len, ic, const_cpu_to_le16(0), |
2358 | index_alloc_val, index_alloc_val_len, WRITE_STANDARD); |
2359 | if (err < 0) |
2360 | ntfs_log_error("add_attr_index_alloc failed: %s\n", strerror(-err)); |
2361 | return err; |
2362 | } |
2363 | |
2364 | /** |
2365 | * add_attr_bitmap |
2366 | * |
2367 | * Return 0 on success or -errno on error. |
2368 | */ |
2369 | static int add_attr_bitmap(MFT_RECORD *m, const char *name, const u32 name_len, |
2370 | const IGNORE_CASE_BOOL ic, const u8 *bitmap, |
2371 | const u32 bitmap_len) |
2372 | { |
2373 | int err; |
2374 | |
2375 | /* Does it fit? NO: create non-resident. YES: create resident. */ |
2376 | if (le32_to_cpu(m->bytes_in_use) + 24 + bitmap_len > |
2377 | le32_to_cpu(m->bytes_allocated)) |
2378 | err = insert_non_resident_attr_in_mft_record(m, AT_BITMAP, name, |
2379 | name_len, ic, const_cpu_to_le16(0), bitmap, |
2380 | bitmap_len, WRITE_STANDARD); |
2381 | else |
2382 | err = insert_resident_attr_in_mft_record(m, AT_BITMAP, name, |
2383 | name_len, ic, const_cpu_to_le16(0), 0, |
2384 | bitmap, bitmap_len); |
2385 | |
2386 | if (err < 0) |
2387 | ntfs_log_error("add_attr_bitmap failed: %s\n", strerror(-err)); |
2388 | return err; |
2389 | } |
2390 | |
2391 | /** |
2392 | * add_attr_bitmap_positioned |
2393 | * |
2394 | * Create a non-resident bitmap attribute with a predefined on disk location |
2395 | * specified by the runlist @rl. The clusters specified by @rl are assumed to |
2396 | * be allocated already. |
2397 | * |
2398 | * Return 0 on success or -errno on error. |
2399 | */ |
2400 | static int add_attr_bitmap_positioned(MFT_RECORD *m, const char *name, |
2401 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
2402 | const runlist *rl, const u8 *bitmap, const u32 bitmap_len) |
2403 | { |
2404 | int err; |
2405 | |
2406 | err = insert_positioned_attr_in_mft_record(m, AT_BITMAP, name, name_len, |
2407 | ic, const_cpu_to_le16(0), rl, bitmap, bitmap_len); |
2408 | if (err < 0) |
2409 | ntfs_log_error("add_attr_bitmap_positioned failed: %s\n", |
2410 | strerror(-err)); |
2411 | return err; |
2412 | } |
2413 | |
2414 | |
2415 | /** |
2416 | * upgrade_to_large_index |
2417 | * |
2418 | * Create bitmap and index allocation attributes, modify index root |
2419 | * attribute accordingly and move all of the index entries from the index root |
2420 | * into the index allocation. |
2421 | * |
2422 | * Return 0 on success or -errno on error. |
2423 | */ |
2424 | static int upgrade_to_large_index(MFT_RECORD *m, const char *name, |
2425 | u32 name_len, const IGNORE_CASE_BOOL ic, |
2426 | INDEX_ALLOCATION **idx) |
2427 | { |
2428 | ntfs_attr_search_ctx *ctx; |
2429 | ATTR_RECORD *a; |
2430 | INDEX_ROOT *r; |
2431 | INDEX_ENTRY *re; |
2432 | INDEX_ALLOCATION *ia_val = NULL; |
2433 | ntfschar *uname = NULL; |
2434 | int uname_len = 0; |
2435 | u8 bmp[8]; |
2436 | char *re_start, *re_end; |
2437 | int i, err, index_block_size; |
2438 | |
2439 | uname = ntfs_str2ucs(name, &uname_len); |
2440 | if (!uname) |
2441 | return -errno; |
2442 | |
2443 | /* Find the index root attribute. */ |
2444 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
2445 | if (!ctx) { |
2446 | ntfs_log_error("Failed to allocate attribute search context.\n"); |
2447 | ntfs_ucsfree(uname); |
2448 | return -ENOMEM; |
2449 | } |
2450 | if (ic == IGNORE_CASE) { |
2451 | ntfs_log_error("FIXME: Hit unimplemented code path #4.\n"); |
2452 | err = -EOPNOTSUPP; |
2453 | ntfs_ucsfree(uname); |
2454 | goto err_out; |
2455 | } |
2456 | err = mkntfs_attr_lookup(AT_INDEX_ROOT, uname, uname_len, ic, 0, NULL, 0, |
2457 | ctx); |
2458 | ntfs_ucsfree(uname); |
2459 | if (err) { |
2460 | err = -ENOTDIR; |
2461 | goto err_out; |
2462 | } |
2463 | a = ctx->attr; |
2464 | if (a->non_resident || a->flags) { |
2465 | err = -EINVAL; |
2466 | goto err_out; |
2467 | } |
2468 | r = (INDEX_ROOT*)((char*)a + le16_to_cpu(a->value_offset)); |
2469 | re_end = (char*)r + le32_to_cpu(a->value_length); |
2470 | re_start = (char*)&r->index + le32_to_cpu(r->index.entries_offset); |
2471 | re = (INDEX_ENTRY*)re_start; |
2472 | index_block_size = le32_to_cpu(r->index_block_size); |
2473 | memset(bmp, 0, sizeof(bmp)); |
2474 | ntfs_bit_set(bmp, 0ULL, 1); |
2475 | /* Bitmap has to be at least 8 bytes in size. */ |
2476 | err = add_attr_bitmap(m, name, name_len, ic, bmp, sizeof(bmp)); |
2477 | if (err) |
2478 | goto err_out; |
2479 | ia_val = ntfs_calloc(index_block_size); |
2480 | if (!ia_val) { |
2481 | err = -errno; |
2482 | goto err_out; |
2483 | } |
2484 | /* Setup header. */ |
2485 | ia_val->magic = magic_INDX; |
2486 | ia_val->usa_ofs = cpu_to_le16(sizeof(INDEX_ALLOCATION)); |
2487 | if (index_block_size >= NTFS_BLOCK_SIZE) { |
2488 | ia_val->usa_count = cpu_to_le16(index_block_size / |
2489 | NTFS_BLOCK_SIZE + 1); |
2490 | } else { |
2491 | ia_val->usa_count = cpu_to_le16(1); |
2492 | ntfs_log_error("Sector size is bigger than index block size. " |
2493 | "Setting usa_count to 1. If Windows chkdsk " |
2494 | "reports this as corruption, please email %s " |
2495 | "stating that you saw this message and that " |
2496 | "the filesystem created was corrupt. " |
2497 | "Thank you.", NTFS_DEV_LIST); |
2498 | } |
2499 | /* Set USN to 1. */ |
2500 | *(le16*)((char*)ia_val + le16_to_cpu(ia_val->usa_ofs)) = |
2501 | cpu_to_le16(1); |
2502 | ia_val->lsn = cpu_to_le64(0); |
2503 | ia_val->index_block_vcn = cpu_to_le64(0); |
2504 | ia_val->index.ih_flags = LEAF_NODE; |
2505 | /* Align to 8-byte boundary. */ |
2506 | ia_val->index.entries_offset = cpu_to_le32((sizeof(INDEX_HEADER) + |
2507 | le16_to_cpu(ia_val->usa_count) * 2 + 7) & ~7); |
2508 | ia_val->index.allocated_size = cpu_to_le32(index_block_size - |
2509 | (sizeof(INDEX_ALLOCATION) - sizeof(INDEX_HEADER))); |
2510 | /* Find the last entry in the index root and save it in re. */ |
2511 | while ((char*)re < re_end && !(re->ie_flags & INDEX_ENTRY_END)) { |
2512 | /* Next entry in index root. */ |
2513 | re = (INDEX_ENTRY*)((char*)re + le16_to_cpu(re->length)); |
2514 | } |
2515 | /* Copy all the entries including the termination entry. */ |
2516 | i = (char*)re - re_start + le16_to_cpu(re->length); |
2517 | memcpy((char*)&ia_val->index + |
2518 | le32_to_cpu(ia_val->index.entries_offset), re_start, i); |
2519 | /* Finish setting up index allocation. */ |
2520 | ia_val->index.index_length = cpu_to_le32(i + |
2521 | le32_to_cpu(ia_val->index.entries_offset)); |
2522 | /* Move the termination entry forward to the beginning if necessary. */ |
2523 | if ((char*)re > re_start) { |
2524 | memmove(re_start, (char*)re, le16_to_cpu(re->length)); |
2525 | re = (INDEX_ENTRY*)re_start; |
2526 | } |
2527 | /* Now fixup empty index root with pointer to index allocation VCN 0. */ |
2528 | r->index.ih_flags = LARGE_INDEX; |
2529 | re->ie_flags |= INDEX_ENTRY_NODE; |
2530 | if (le16_to_cpu(re->length) < sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)) |
2531 | re->length = cpu_to_le16(le16_to_cpu(re->length) + sizeof(VCN)); |
2532 | r->index.index_length = cpu_to_le32(le32_to_cpu(r->index.entries_offset) |
2533 | + le16_to_cpu(re->length)); |
2534 | r->index.allocated_size = r->index.index_length; |
2535 | /* Resize index root attribute. */ |
2536 | if (ntfs_resident_attr_value_resize(m, a, sizeof(INDEX_ROOT) - |
2537 | sizeof(INDEX_HEADER) + |
2538 | le32_to_cpu(r->index.allocated_size))) { |
2539 | /* TODO: Remove the added bitmap! */ |
2540 | /* Revert index root from index allocation. */ |
2541 | err = -errno; |
2542 | goto err_out; |
2543 | } |
2544 | /* Set VCN pointer to 0LL. */ |
2545 | *(leVCN*)((char*)re + cpu_to_le16(re->length) - sizeof(VCN)) = |
2546 | cpu_to_le64(0); |
2547 | err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)ia_val, index_block_size); |
2548 | if (err) { |
2549 | err = -errno; |
2550 | ntfs_log_error("ntfs_mst_pre_write_fixup() failed in " |
2551 | "upgrade_to_large_index.\n"); |
2552 | goto err_out; |
2553 | } |
2554 | err = add_attr_index_alloc(m, name, name_len, ic, (u8*)ia_val, |
2555 | index_block_size); |
2556 | ntfs_mst_post_write_fixup((NTFS_RECORD*)ia_val); |
2557 | if (err) { |
2558 | /* TODO: Remove the added bitmap! */ |
2559 | /* Revert index root from index allocation. */ |
2560 | goto err_out; |
2561 | } |
2562 | *idx = ia_val; |
2563 | ntfs_attr_put_search_ctx(ctx); |
2564 | return 0; |
2565 | err_out: |
2566 | ntfs_attr_put_search_ctx(ctx); |
2567 | free(ia_val); |
2568 | return err; |
2569 | } |
2570 | |
2571 | /** |
2572 | * make_room_for_index_entry_in_index_block |
2573 | * |
2574 | * Create space of @size bytes at position @pos inside the index block @idx. |
2575 | * |
2576 | * Return 0 on success or -errno on error. |
2577 | */ |
2578 | static int make_room_for_index_entry_in_index_block(INDEX_BLOCK *idx, |
2579 | INDEX_ENTRY *pos, u32 size) |
2580 | { |
2581 | u32 biu; |
2582 | |
2583 | if (!size) |
2584 | return 0; |
2585 | #ifdef DEBUG |
2586 | /* |
2587 | * Rigorous consistency checks. Always return -EINVAL even if more |
2588 | * appropriate codes exist for simplicity of parsing the return value. |
2589 | */ |
2590 | if (size != ((size + 7) & ~7)) { |
2591 | ntfs_log_error("make_room_for_index_entry_in_index_block() received " |
2592 | "non 8-byte aligned size.\n"); |
2593 | return -EINVAL; |
2594 | } |
2595 | if (!idx || !pos) |
2596 | return -EINVAL; |
2597 | if ((char*)pos < (char*)idx || (char*)pos + size < (char*)idx || |
2598 | (char*)pos > (char*)idx + sizeof(INDEX_BLOCK) - |
2599 | sizeof(INDEX_HEADER) + |
2600 | le32_to_cpu(idx->index.allocated_size) || |
2601 | (char*)pos + size > (char*)idx + sizeof(INDEX_BLOCK) - |
2602 | sizeof(INDEX_HEADER) + |
2603 | le32_to_cpu(idx->index.allocated_size)) |
2604 | return -EINVAL; |
2605 | /* The - sizeof(INDEX_ENTRY_HEADER) is for the index terminator. */ |
2606 | if ((char*)pos - (char*)&idx->index > |
2607 | (int)le32_to_cpu(idx->index.index_length) |
2608 | - (int)sizeof(INDEX_ENTRY_HEADER)) |
2609 | return -EINVAL; |
2610 | #endif |
2611 | biu = le32_to_cpu(idx->index.index_length); |
2612 | /* Do we have enough space? */ |
2613 | if (biu + size > le32_to_cpu(idx->index.allocated_size)) |
2614 | return -ENOSPC; |
2615 | /* Move everything after pos to pos + size. */ |
2616 | memmove((char*)pos + size, (char*)pos, biu - ((char*)pos - |
2617 | (char*)&idx->index)); |
2618 | /* Update index block. */ |
2619 | idx->index.index_length = cpu_to_le32(biu + size); |
2620 | return 0; |
2621 | } |
2622 | |
2623 | /** |
2624 | * ntfs_index_keys_compare |
2625 | * |
2626 | * not all types of COLLATION_RULES supported yet... |
2627 | * added as needed.. (remove this comment when all are added) |
2628 | */ |
2629 | static int ntfs_index_keys_compare(u8 *key1, u8 *key2, int key1_length, |
2630 | int key2_length, COLLATION_RULES collation_rule) |
2631 | { |
2632 | u32 u1, u2; |
2633 | int i; |
2634 | |
2635 | if (collation_rule == COLLATION_NTOFS_ULONG) { |
2636 | /* i.e. $SII or $QUOTA-$Q */ |
2637 | u1 = le32_to_cpup((const le32*)key1); |
2638 | u2 = le32_to_cpup((const le32*)key2); |
2639 | if (u1 < u2) |
2640 | return -1; |
2641 | if (u1 > u2) |
2642 | return 1; |
2643 | /* u1 == u2 */ |
2644 | return 0; |
2645 | } |
2646 | if (collation_rule == COLLATION_NTOFS_ULONGS) { |
2647 | /* i.e $OBJID-$O */ |
2648 | i = 0; |
2649 | while (i < min(key1_length, key2_length)) { |
2650 | u1 = le32_to_cpup((const le32*)(key1 + i)); |
2651 | u2 = le32_to_cpup((const le32*)(key2 + i)); |
2652 | if (u1 < u2) |
2653 | return -1; |
2654 | if (u1 > u2) |
2655 | return 1; |
2656 | /* u1 == u2 */ |
2657 | i += sizeof(u32); |
2658 | } |
2659 | if (key1_length < key2_length) |
2660 | return -1; |
2661 | if (key1_length > key2_length) |
2662 | return 1; |
2663 | return 0; |
2664 | } |
2665 | if (collation_rule == COLLATION_NTOFS_SECURITY_HASH) { |
2666 | /* i.e. $SDH */ |
2667 | u1 = le32_to_cpu(((SDH_INDEX_KEY*)key1)->hash); |
2668 | u2 = le32_to_cpu(((SDH_INDEX_KEY*)key2)->hash); |
2669 | if (u1 < u2) |
2670 | return -1; |
2671 | if (u1 > u2) |
2672 | return 1; |
2673 | /* u1 == u2 */ |
2674 | u1 = le32_to_cpu(((SDH_INDEX_KEY*)key1)->security_id); |
2675 | u2 = le32_to_cpu(((SDH_INDEX_KEY*)key2)->security_id); |
2676 | if (u1 < u2) |
2677 | return -1; |
2678 | if (u1 > u2) |
2679 | return 1; |
2680 | return 0; |
2681 | } |
2682 | if (collation_rule == COLLATION_NTOFS_SID) { |
2683 | /* i.e. $QUOTA-O */ |
2684 | i = memcmp(key1, key2, min(key1_length, key2_length)); |
2685 | if (!i) { |
2686 | if (key1_length < key2_length) |
2687 | return -1; |
2688 | if (key1_length > key2_length) |
2689 | return 1; |
2690 | } |
2691 | return i; |
2692 | } |
2693 | ntfs_log_critical("ntfs_index_keys_compare called without supported " |
2694 | "collation rule.\n"); |
2695 | return 0; /* Claim they're equal. What else can we do? */ |
2696 | } |
2697 | |
2698 | /** |
2699 | * insert_index_entry_in_res_dir_index |
2700 | * |
2701 | * i.e. insert an index_entry in some named index_root |
2702 | * simplified search method, works for mkntfs |
2703 | */ |
2704 | static int insert_index_entry_in_res_dir_index(INDEX_ENTRY *idx, u32 idx_size, |
2705 | MFT_RECORD *m, ntfschar *name, u32 name_size, ATTR_TYPES type) |
2706 | { |
2707 | ntfs_attr_search_ctx *ctx; |
2708 | INDEX_HEADER *idx_header; |
2709 | INDEX_ENTRY *idx_entry, *idx_end; |
2710 | ATTR_RECORD *a; |
2711 | COLLATION_RULES collation_rule; |
2712 | int err, i; |
2713 | |
2714 | err = 0; |
2715 | /* does it fit ?*/ |
2716 | if (g_vol->mft_record_size > idx_size + le32_to_cpu(m->bytes_allocated)) |
2717 | return -ENOSPC; |
2718 | /* find the INDEX_ROOT attribute:*/ |
2719 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
2720 | if (!ctx) { |
2721 | ntfs_log_error("Failed to allocate attribute search " |
2722 | "context.\n"); |
2723 | err = -ENOMEM; |
2724 | goto err_out; |
2725 | } |
2726 | if (mkntfs_attr_lookup(AT_INDEX_ROOT, name, name_size, |
2727 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
2728 | err = -EEXIST; |
2729 | goto err_out; |
2730 | } |
2731 | /* found attribute */ |
2732 | a = (ATTR_RECORD*)ctx->attr; |
2733 | collation_rule = ((INDEX_ROOT*)((u8*)a + |
2734 | le16_to_cpu(a->value_offset)))->collation_rule; |
2735 | idx_header = (INDEX_HEADER*)((u8*)a + le16_to_cpu(a->value_offset) |
2736 | + 0x10); |
2737 | idx_entry = (INDEX_ENTRY*)((u8*)idx_header + |
2738 | le32_to_cpu(idx_header->entries_offset)); |
2739 | idx_end = (INDEX_ENTRY*)((u8*)idx_entry + |
2740 | le32_to_cpu(idx_header->index_length)); |
2741 | /* |
2742 | * Loop until we exceed valid memory (corruption case) or until we |
2743 | * reach the last entry. |
2744 | */ |
2745 | if (type == AT_FILE_NAME) { |
2746 | while (((u8*)idx_entry < (u8*)idx_end) && |
2747 | !(idx_entry->ie_flags & INDEX_ENTRY_END)) { |
2748 | /* |
2749 | i = ntfs_file_values_compare(&idx->key.file_name, |
2750 | &idx_entry->key.file_name, 1, |
2751 | IGNORE_CASE, g_vol->upcase, |
2752 | g_vol->upcase_len); |
2753 | */ |
2754 | i = ntfs_names_full_collate(idx->key.file_name.file_name, idx->key.file_name.file_name_length, |
2755 | idx_entry->key.file_name.file_name, idx_entry->key.file_name.file_name_length, |
2756 | IGNORE_CASE, g_vol->upcase, |
2757 | g_vol->upcase_len); |
2758 | /* |
2759 | * If @file_name collates before ie->key.file_name, |
2760 | * there is no matching index entry. |
2761 | */ |
2762 | if (i == -1) |
2763 | break; |
2764 | /* If file names are not equal, continue search. */ |
2765 | if (i) |
2766 | goto do_next; |
2767 | if (idx->key.file_name.file_name_type != |
2768 | FILE_NAME_POSIX || |
2769 | idx_entry->key.file_name.file_name_type |
2770 | != FILE_NAME_POSIX) |
2771 | return -EEXIST; |
2772 | /* |
2773 | i = ntfs_file_values_compare(&idx->key.file_name, |
2774 | &idx_entry->key.file_name, 1, |
2775 | CASE_SENSITIVE, g_vol->upcase, |
2776 | g_vol->upcase_len); |
2777 | */ |
2778 | i = ntfs_names_full_collate(idx->key.file_name.file_name, idx->key.file_name.file_name_length, |
2779 | idx_entry->key.file_name.file_name, idx_entry->key.file_name.file_name_length, |
2780 | CASE_SENSITIVE, g_vol->upcase, |
2781 | g_vol->upcase_len); |
2782 | if (!i) |
2783 | return -EEXIST; |
2784 | if (i == -1) |
2785 | break; |
2786 | do_next: |
2787 | idx_entry = (INDEX_ENTRY*)((u8*)idx_entry + |
2788 | le16_to_cpu(idx_entry->length)); |
2789 | } |
2790 | } else if (type == AT_UNUSED) { /* case view */ |
2791 | while (((u8*)idx_entry < (u8*)idx_end) && |
2792 | !(idx_entry->ie_flags & INDEX_ENTRY_END)) { |
2793 | i = ntfs_index_keys_compare((u8*)idx + 0x10, |
2794 | (u8*)idx_entry + 0x10, |
2795 | le16_to_cpu(idx->key_length), |
2796 | le16_to_cpu(idx_entry->key_length), |
2797 | collation_rule); |
2798 | if (!i) |
2799 | return -EEXIST; |
2800 | if (i == -1) |
2801 | break; |
2802 | idx_entry = (INDEX_ENTRY*)((u8*)idx_entry + |
2803 | le16_to_cpu(idx_entry->length)); |
2804 | } |
2805 | } else |
2806 | return -EINVAL; |
2807 | memmove((u8*)idx_entry + idx_size, (u8*)idx_entry, |
2808 | le32_to_cpu(m->bytes_in_use) - |
2809 | ((u8*)idx_entry - (u8*)m)); |
2810 | memcpy((u8*)idx_entry, (u8*)idx, idx_size); |
2811 | /* Adjust various offsets, etc... */ |
2812 | m->bytes_in_use = cpu_to_le32(le32_to_cpu(m->bytes_in_use) + idx_size); |
2813 | a->length = cpu_to_le32(le32_to_cpu(a->length) + idx_size); |
2814 | a->value_length = cpu_to_le32(le32_to_cpu(a->value_length) + idx_size); |
2815 | idx_header->index_length = cpu_to_le32( |
2816 | le32_to_cpu(idx_header->index_length) + idx_size); |
2817 | idx_header->allocated_size = cpu_to_le32( |
2818 | le32_to_cpu(idx_header->allocated_size) + idx_size); |
2819 | err_out: |
2820 | if (ctx) |
2821 | ntfs_attr_put_search_ctx(ctx); |
2822 | return err; |
2823 | } |
2824 | |
2825 | /** |
2826 | * initialize_secure |
2827 | * |
2828 | * initializes $Secure's $SDH and $SII indexes from $SDS datastream |
2829 | */ |
2830 | static int initialize_secure(char *sds, u32 sds_size, MFT_RECORD *m) |
2831 | { |
2832 | int err, sdh_size, sii_size; |
2833 | SECURITY_DESCRIPTOR_HEADER *sds_header; |
2834 | INDEX_ENTRY *idx_entry_sdh, *idx_entry_sii; |
2835 | SDH_INDEX_DATA *sdh_data; |
2836 | SII_INDEX_DATA *sii_data; |
2837 | |
2838 | sds_header = (SECURITY_DESCRIPTOR_HEADER*)sds; |
2839 | sdh_size = sizeof(INDEX_ENTRY_HEADER); |
2840 | sdh_size += sizeof(SDH_INDEX_KEY) + sizeof(SDH_INDEX_DATA); |
2841 | sii_size = sizeof(INDEX_ENTRY_HEADER); |
2842 | sii_size += sizeof(SII_INDEX_KEY) + sizeof(SII_INDEX_DATA); |
2843 | idx_entry_sdh = ntfs_calloc(sizeof(INDEX_ENTRY)); |
2844 | if (!idx_entry_sdh) |
2845 | return -errno; |
2846 | idx_entry_sii = ntfs_calloc(sizeof(INDEX_ENTRY)); |
2847 | if (!idx_entry_sii) { |
2848 | free(idx_entry_sdh); |
2849 | return -errno; |
2850 | } |
2851 | err = 0; |
2852 | |
2853 | while ((char*)sds_header < (char*)sds + sds_size) { |
2854 | if (!sds_header->length) |
2855 | break; |
2856 | /* SDH index entry */ |
2857 | idx_entry_sdh->data_offset = const_cpu_to_le16(0x18); |
2858 | idx_entry_sdh->data_length = const_cpu_to_le16(0x14); |
2859 | idx_entry_sdh->reservedV = const_cpu_to_le32(0x00); |
2860 | idx_entry_sdh->length = const_cpu_to_le16(0x30); |
2861 | idx_entry_sdh->key_length = const_cpu_to_le16(0x08); |
2862 | idx_entry_sdh->ie_flags = const_cpu_to_le16(0x00); |
2863 | idx_entry_sdh->reserved = const_cpu_to_le16(0x00); |
2864 | idx_entry_sdh->key.sdh.hash = sds_header->hash; |
2865 | idx_entry_sdh->key.sdh.security_id = sds_header->security_id; |
2866 | sdh_data = (SDH_INDEX_DATA*)((u8*)idx_entry_sdh + |
2867 | le16_to_cpu(idx_entry_sdh->data_offset)); |
2868 | sdh_data->hash = sds_header->hash; |
2869 | sdh_data->security_id = sds_header->security_id; |
2870 | sdh_data->offset = sds_header->offset; |
2871 | sdh_data->length = sds_header->length; |
2872 | sdh_data->reserved_II = const_cpu_to_le32(0x00490049); |
2873 | |
2874 | /* SII index entry */ |
2875 | idx_entry_sii->data_offset = const_cpu_to_le16(0x14); |
2876 | idx_entry_sii->data_length = const_cpu_to_le16(0x14); |
2877 | idx_entry_sii->reservedV = const_cpu_to_le32(0x00); |
2878 | idx_entry_sii->length = const_cpu_to_le16(0x28); |
2879 | idx_entry_sii->key_length = const_cpu_to_le16(0x04); |
2880 | idx_entry_sii->ie_flags = const_cpu_to_le16(0x00); |
2881 | idx_entry_sii->reserved = const_cpu_to_le16(0x00); |
2882 | idx_entry_sii->key.sii.security_id = sds_header->security_id; |
2883 | sii_data = (SII_INDEX_DATA*)((u8*)idx_entry_sii + |
2884 | le16_to_cpu(idx_entry_sii->data_offset)); |
2885 | sii_data->hash = sds_header->hash; |
2886 | sii_data->security_id = sds_header->security_id; |
2887 | sii_data->offset = sds_header->offset; |
2888 | sii_data->length = sds_header->length; |
2889 | if ((err = insert_index_entry_in_res_dir_index(idx_entry_sdh, |
2890 | sdh_size, m, NTFS_INDEX_SDH, 4, AT_UNUSED))) |
2891 | break; |
2892 | if ((err = insert_index_entry_in_res_dir_index(idx_entry_sii, |
2893 | sii_size, m, NTFS_INDEX_SII, 4, AT_UNUSED))) |
2894 | break; |
2895 | sds_header = (SECURITY_DESCRIPTOR_HEADER*)((u8*)sds_header + |
2896 | ((le32_to_cpu(sds_header->length) + 15) & ~15)); |
2897 | } |
2898 | free(idx_entry_sdh); |
2899 | free(idx_entry_sii); |
2900 | return err; |
2901 | } |
2902 | |
2903 | /** |
2904 | * initialize_quota |
2905 | * |
2906 | * initialize $Quota with the default quota index-entries. |
2907 | */ |
2908 | static int initialize_quota(MFT_RECORD *m) |
2909 | { |
2910 | int o_size, q1_size, q2_size, err, i; |
2911 | INDEX_ENTRY *idx_entry_o, *idx_entry_q1, *idx_entry_q2; |
2912 | QUOTA_O_INDEX_DATA *idx_entry_o_data; |
2913 | QUOTA_CONTROL_ENTRY *idx_entry_q1_data, *idx_entry_q2_data; |
2914 | |
2915 | err = 0; |
2916 | /* q index entry num 1 */ |
2917 | q1_size = 0x48; |
2918 | idx_entry_q1 = ntfs_calloc(q1_size); |
2919 | if (!idx_entry_q1) |
2920 | return errno; |
2921 | idx_entry_q1->data_offset = const_cpu_to_le16(0x14); |
2922 | idx_entry_q1->data_length = const_cpu_to_le16(0x30); |
2923 | idx_entry_q1->reservedV = const_cpu_to_le32(0x00); |
2924 | idx_entry_q1->length = const_cpu_to_le16(0x48); |
2925 | idx_entry_q1->key_length = const_cpu_to_le16(0x04); |
2926 | idx_entry_q1->ie_flags = const_cpu_to_le16(0x00); |
2927 | idx_entry_q1->reserved = const_cpu_to_le16(0x00); |
2928 | idx_entry_q1->key.owner_id = const_cpu_to_le32(0x01); |
2929 | idx_entry_q1_data = (QUOTA_CONTROL_ENTRY*)((char*)idx_entry_q1 |
2930 | + le16_to_cpu(idx_entry_q1->data_offset)); |
2931 | idx_entry_q1_data->version = const_cpu_to_le32(0x02); |
2932 | idx_entry_q1_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; |
2933 | idx_entry_q1_data->bytes_used = const_cpu_to_le64(0x00); |
2934 | idx_entry_q1_data->change_time = mkntfs_time(); |
2935 | idx_entry_q1_data->threshold = cpu_to_sle64(-1); |
2936 | idx_entry_q1_data->limit = cpu_to_sle64(-1); |
2937 | idx_entry_q1_data->exceeded_time = const_cpu_to_le64(0); |
2938 | err = insert_index_entry_in_res_dir_index(idx_entry_q1, q1_size, m, |
2939 | NTFS_INDEX_Q, 2, AT_UNUSED); |
2940 | free(idx_entry_q1); |
2941 | if (err) |
2942 | return err; |
2943 | /* q index entry num 2 */ |
2944 | q2_size = 0x58; |
2945 | idx_entry_q2 = ntfs_calloc(q2_size); |
2946 | if (!idx_entry_q2) |
2947 | return errno; |
2948 | idx_entry_q2->data_offset = const_cpu_to_le16(0x14); |
2949 | idx_entry_q2->data_length = const_cpu_to_le16(0x40); |
2950 | idx_entry_q2->reservedV = const_cpu_to_le32(0x00); |
2951 | idx_entry_q2->length = const_cpu_to_le16(0x58); |
2952 | idx_entry_q2->key_length = const_cpu_to_le16(0x04); |
2953 | idx_entry_q2->ie_flags = const_cpu_to_le16(0x00); |
2954 | idx_entry_q2->reserved = const_cpu_to_le16(0x00); |
2955 | idx_entry_q2->key.owner_id = QUOTA_FIRST_USER_ID; |
2956 | idx_entry_q2_data = (QUOTA_CONTROL_ENTRY*)((char*)idx_entry_q2 |
2957 | + le16_to_cpu(idx_entry_q2->data_offset)); |
2958 | idx_entry_q2_data->version = const_cpu_to_le32(0x02); |
2959 | idx_entry_q2_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; |
2960 | idx_entry_q2_data->bytes_used = const_cpu_to_le64(0x00); |
2961 | idx_entry_q2_data->change_time = mkntfs_time(); |
2962 | idx_entry_q2_data->threshold = cpu_to_sle64(-1); |
2963 | idx_entry_q2_data->limit = cpu_to_sle64(-1); |
2964 | idx_entry_q2_data->exceeded_time = const_cpu_to_le64(0); |
2965 | idx_entry_q2_data->sid.revision = 1; |
2966 | idx_entry_q2_data->sid.sub_authority_count = 2; |
2967 | for (i = 0; i < 5; i++) |
2968 | idx_entry_q2_data->sid.identifier_authority.value[i] = 0; |
2969 | idx_entry_q2_data->sid.identifier_authority.value[5] = 0x05; |
2970 | idx_entry_q2_data->sid.sub_authority[0] = |
2971 | const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); |
2972 | idx_entry_q2_data->sid.sub_authority[1] = |
2973 | const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); |
2974 | err = insert_index_entry_in_res_dir_index(idx_entry_q2, q2_size, m, |
2975 | NTFS_INDEX_Q, 2, AT_UNUSED); |
2976 | free(idx_entry_q2); |
2977 | if (err) |
2978 | return err; |
2979 | o_size = 0x28; |
2980 | idx_entry_o = ntfs_calloc(o_size); |
2981 | if (!idx_entry_o) |
2982 | return errno; |
2983 | idx_entry_o->data_offset = const_cpu_to_le16(0x20); |
2984 | idx_entry_o->data_length = const_cpu_to_le16(0x04); |
2985 | idx_entry_o->reservedV = const_cpu_to_le32(0x00); |
2986 | idx_entry_o->length = const_cpu_to_le16(0x28); |
2987 | idx_entry_o->key_length = const_cpu_to_le16(0x10); |
2988 | idx_entry_o->ie_flags = const_cpu_to_le16(0x00); |
2989 | idx_entry_o->reserved = const_cpu_to_le16(0x00); |
2990 | idx_entry_o->key.sid.revision = 0x01; |
2991 | idx_entry_o->key.sid.sub_authority_count = 0x02; |
2992 | for (i = 0; i < 5; i++) |
2993 | idx_entry_o->key.sid.identifier_authority.value[i] = 0; |
2994 | idx_entry_o->key.sid.identifier_authority.value[5] = 0x05; |
2995 | idx_entry_o->key.sid.sub_authority[0] = |
2996 | const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); |
2997 | idx_entry_o->key.sid.sub_authority[1] = |
2998 | const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); |
2999 | idx_entry_o_data = (QUOTA_O_INDEX_DATA*)((char*)idx_entry_o |
3000 | + le16_to_cpu(idx_entry_o->data_offset)); |
3001 | idx_entry_o_data->owner_id = QUOTA_FIRST_USER_ID; |
3002 | /* 20 00 00 00 padding after here on ntfs 3.1. 3.0 is unchecked. */ |
3003 | idx_entry_o_data->unknown = const_cpu_to_le32(32); |
3004 | err = insert_index_entry_in_res_dir_index(idx_entry_o, o_size, m, |
3005 | NTFS_INDEX_O, 2, AT_UNUSED); |
3006 | free(idx_entry_o); |
3007 | |
3008 | return err; |
3009 | } |
3010 | |
3011 | /** |
3012 | * insert_file_link_in_dir_index |
3013 | * |
3014 | * Insert the fully completed FILE_NAME_ATTR @file_name which is inside |
3015 | * the file with mft reference @file_ref into the index (allocation) block |
3016 | * @idx (which belongs to @file_ref's parent directory). |
3017 | * |
3018 | * Return 0 on success or -errno on error. |
3019 | */ |
3020 | static int insert_file_link_in_dir_index(INDEX_BLOCK *idx, leMFT_REF file_ref, |
3021 | FILE_NAME_ATTR *file_name, u32 file_name_size) |
3022 | { |
3023 | int err, i; |
3024 | INDEX_ENTRY *ie; |
3025 | char *index_end; |
3026 | |
3027 | /* |
3028 | * Lookup dir entry @file_name in dir @idx to determine correct |
3029 | * insertion location. FIXME: Using a very oversimplified lookup |
3030 | * method which is sufficient for mkntfs but no good whatsoever in |
3031 | * real world scenario. (AIA) |
3032 | */ |
3033 | |
3034 | index_end = (char*)&idx->index + le32_to_cpu(idx->index.index_length); |
3035 | ie = (INDEX_ENTRY*)((char*)&idx->index + |
3036 | le32_to_cpu(idx->index.entries_offset)); |
3037 | /* |
3038 | * Loop until we exceed valid memory (corruption case) or until we |
3039 | * reach the last entry. |
3040 | */ |
3041 | while ((char*)ie < index_end && !(ie->ie_flags & INDEX_ENTRY_END)) { |
3042 | #if 0 |
3043 | #ifdef DEBUG |
3044 | ntfs_log_debug("file_name_attr1->file_name_length = %i\n", |
3045 | file_name->file_name_length); |
3046 | if (file_name->file_name_length) { |
3047 | char *__buf = NULL; |
3048 | i = ntfs_ucstombs((ntfschar*)&file_name->file_name, |
3049 | file_name->file_name_length, &__buf, 0); |
3050 | if (i < 0) |
3051 | ntfs_log_debug("Name contains non-displayable " |
3052 | "Unicode characters.\n"); |
3053 | ntfs_log_debug("file_name_attr1->file_name = %s\n", |
3054 | __buf); |
3055 | free(__buf); |
3056 | } |
3057 | ntfs_log_debug("file_name_attr2->file_name_length = %i\n", |
3058 | ie->key.file_name.file_name_length); |
3059 | if (ie->key.file_name.file_name_length) { |
3060 | char *__buf = NULL; |
3061 | i = ntfs_ucstombs(ie->key.file_name.file_name, |
3062 | ie->key.file_name.file_name_length + 1, &__buf, |
3063 | 0); |
3064 | if (i < 0) |
3065 | ntfs_log_debug("Name contains non-displayable " |
3066 | "Unicode characters.\n"); |
3067 | ntfs_log_debug("file_name_attr2->file_name = %s\n", |
3068 | __buf); |
3069 | free(__buf); |
3070 | } |
3071 | #endif |
3072 | #endif |
3073 | /* |
3074 | i = ntfs_file_values_compare(file_name, |
3075 | (FILE_NAME_ATTR*)&ie->key.file_name, 1, |
3076 | IGNORE_CASE, g_vol->upcase, g_vol->upcase_len); |
3077 | */ |
3078 | i = ntfs_names_full_collate(file_name->file_name, file_name->file_name_length, |
3079 | ((FILE_NAME_ATTR*)&ie->key.file_name)->file_name, ((FILE_NAME_ATTR*)&ie->key.file_name)->file_name_length, |
3080 | IGNORE_CASE, g_vol->upcase, g_vol->upcase_len); |
3081 | /* |
3082 | * If @file_name collates before ie->key.file_name, there is no |
3083 | * matching index entry. |
3084 | */ |
3085 | if (i == -1) |
3086 | break; |
3087 | /* If file names are not equal, continue search. */ |
3088 | if (i) |
3089 | goto do_next; |
3090 | /* File names are equal when compared ignoring case. */ |
3091 | /* |
3092 | * If BOTH file names are in the POSIX namespace, do a case |
3093 | * sensitive comparison as well. Otherwise the names match so |
3094 | * we return -EEXIST. FIXME: There are problems with this in a |
3095 | * real world scenario, when one is POSIX and one isn't, but |
3096 | * fine for mkntfs where we don't use POSIX namespace at all |
3097 | * and hence this following code is luxury. (AIA) |
3098 | */ |
3099 | if (file_name->file_name_type != FILE_NAME_POSIX || |
3100 | ie->key.file_name.file_name_type != FILE_NAME_POSIX) |
3101 | return -EEXIST; |
3102 | /* |
3103 | i = ntfs_file_values_compare(file_name, |
3104 | (FILE_NAME_ATTR*)&ie->key.file_name, 1, |
3105 | CASE_SENSITIVE, g_vol->upcase, |
3106 | g_vol->upcase_len); |
3107 | */ |
3108 | i = ntfs_names_full_collate(file_name->file_name, file_name->file_name_length, |
3109 | ((FILE_NAME_ATTR*)&ie->key.file_name)->file_name, ((FILE_NAME_ATTR*)&ie->key.file_name)->file_name_length, |
3110 | CASE_SENSITIVE, g_vol->upcase, g_vol->upcase_len); |
3111 | if (i == -1) |
3112 | break; |
3113 | /* Complete match. Bugger. Can't insert. */ |
3114 | if (!i) |
3115 | return -EEXIST; |
3116 | do_next: |
3117 | #ifdef DEBUG |
3118 | /* Next entry. */ |
3119 | if (!ie->length) { |
3120 | ntfs_log_debug("BUG: ie->length is zero, breaking out " |
3121 | "of loop.\n"); |
3122 | break; |
3123 | } |
3124 | #endif |
3125 | ie = (INDEX_ENTRY*)((char*)ie + le16_to_cpu(ie->length)); |
3126 | }; |
3127 | i = (sizeof(INDEX_ENTRY_HEADER) + file_name_size + 7) & ~7; |
3128 | err = make_room_for_index_entry_in_index_block(idx, ie, i); |
3129 | if (err) { |
3130 | ntfs_log_error("make_room_for_index_entry_in_index_block " |
3131 | "failed: %s\n", strerror(-err)); |
3132 | return err; |
3133 | } |
3134 | /* Create entry in place and copy file name attribute value. */ |
3135 | ie->indexed_file = file_ref; |
3136 | ie->length = cpu_to_le16(i); |
3137 | ie->key_length = cpu_to_le16(file_name_size); |
3138 | ie->ie_flags = cpu_to_le16(0); |
3139 | ie->reserved = cpu_to_le16(0); |
3140 | memcpy((char*)&ie->key.file_name, (char*)file_name, file_name_size); |
3141 | return 0; |
3142 | } |
3143 | |
3144 | /** |
3145 | * create_hardlink_res |
3146 | * |
3147 | * Create a file_name_attribute in the mft record @m_file which points to the |
3148 | * parent directory with mft reference @ref_parent. |
3149 | * |
3150 | * Then, insert an index entry with this file_name_attribute in the index |
3151 | * root @idx of the index_root attribute of the parent directory. |
3152 | * |
3153 | * @ref_file is the mft reference of @m_file. |
3154 | * |
3155 | * Return 0 on success or -errno on error. |
3156 | */ |
3157 | static int create_hardlink_res(MFT_RECORD *m_parent, const leMFT_REF ref_parent, |
3158 | MFT_RECORD *m_file, const leMFT_REF ref_file, |
3159 | const s64 allocated_size, const s64 data_size, |
3160 | const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, |
3161 | const u32 reparse_point_tag, const char *file_name, |
3162 | const FILE_NAME_TYPE_FLAGS file_name_type) |
3163 | { |
3164 | FILE_NAME_ATTR *fn; |
3165 | int i, fn_size, idx_size; |
3166 | INDEX_ENTRY *idx_entry_new; |
3167 | ntfschar *uname; |
3168 | |
3169 | /* Create the file_name attribute. */ |
3170 | i = (strlen(file_name) + 1) * sizeof(ntfschar); |
3171 | fn_size = sizeof(FILE_NAME_ATTR) + i; |
3172 | fn = ntfs_malloc(fn_size); |
3173 | if (!fn) |
3174 | return -errno; |
3175 | fn->parent_directory = ref_parent; |
3176 | fn->creation_time = stdinfo_time(m_file); |
3177 | fn->last_data_change_time = fn->creation_time; |
3178 | fn->last_mft_change_time = fn->creation_time; |
3179 | fn->last_access_time = fn->creation_time; |
3180 | fn->allocated_size = cpu_to_sle64(allocated_size); |
3181 | fn->data_size = cpu_to_sle64(data_size); |
3182 | fn->file_attributes = flags; |
3183 | /* These are in a union so can't have both. */ |
3184 | if (packed_ea_size && reparse_point_tag) { |
3185 | free(fn); |
3186 | return -EINVAL; |
3187 | } |
3188 | if (packed_ea_size) { |
3189 | free(fn); |
3190 | return -EINVAL; |
3191 | } |
3192 | if (packed_ea_size) { |
3193 | fn->packed_ea_size = cpu_to_le16(packed_ea_size); |
3194 | fn->reserved = cpu_to_le16(0); |
3195 | } else { |
3196 | fn->reparse_point_tag = cpu_to_le32(reparse_point_tag); |
3197 | } |
3198 | fn->file_name_type = file_name_type; |
3199 | uname = fn->file_name; |
3200 | i = ntfs_mbstoucs_libntfscompat(file_name, &uname, i); |
3201 | if (i < 1) { |
3202 | free(fn); |
3203 | return -EINVAL; |
3204 | } |
3205 | if (i > 0xff) { |
3206 | free(fn); |
3207 | return -ENAMETOOLONG; |
3208 | } |
3209 | /* No terminating null in file names. */ |
3210 | fn->file_name_length = i; |
3211 | fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); |
3212 | /* Increment the link count of @m_file. */ |
3213 | i = le16_to_cpu(m_file->link_count); |
3214 | if (i == 0xffff) { |
3215 | ntfs_log_error("Too many hardlinks present already.\n"); |
3216 | free(fn); |
3217 | return -EINVAL; |
3218 | } |
3219 | m_file->link_count = cpu_to_le16(i + 1); |
3220 | /* Add the file_name to @m_file. */ |
3221 | i = insert_resident_attr_in_mft_record(m_file, AT_FILE_NAME, NULL, 0, |
3222 | CASE_SENSITIVE, const_cpu_to_le16(0), |
3223 | RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); |
3224 | if (i < 0) { |
3225 | ntfs_log_error("create_hardlink failed adding file name " |
3226 | "attribute: %s\n", strerror(-i)); |
3227 | free(fn); |
3228 | /* Undo link count increment. */ |
3229 | m_file->link_count = cpu_to_le16( |
3230 | le16_to_cpu(m_file->link_count) - 1); |
3231 | return i; |
3232 | } |
3233 | /* Insert the index entry for file_name in @idx. */ |
3234 | idx_size = (fn_size + 7) & ~7; |
3235 | idx_entry_new = ntfs_calloc(idx_size + 0x10); |
3236 | if (!idx_entry_new) |
3237 | return -errno; |
3238 | idx_entry_new->indexed_file = ref_file; |
3239 | idx_entry_new->length = cpu_to_le16(idx_size + 0x10); |
3240 | idx_entry_new->key_length = cpu_to_le16(fn_size); |
3241 | memcpy((u8*)idx_entry_new + 0x10, (u8*)fn, fn_size); |
3242 | i = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size + 0x10, |
3243 | m_parent, NTFS_INDEX_I30, 4, AT_FILE_NAME); |
3244 | if (i < 0) { |
3245 | ntfs_log_error("create_hardlink failed inserting index entry: " |
3246 | "%s\n", strerror(-i)); |
3247 | /* FIXME: Remove the file name attribute from @m_file. */ |
3248 | free(idx_entry_new); |
3249 | free(fn); |
3250 | /* Undo link count increment. */ |
3251 | m_file->link_count = cpu_to_le16( |
3252 | le16_to_cpu(m_file->link_count) - 1); |
3253 | return i; |
3254 | } |
3255 | free(idx_entry_new); |
3256 | free(fn); |
3257 | return 0; |
3258 | } |
3259 | |
3260 | /** |
3261 | * create_hardlink |
3262 | * |
3263 | * Create a file_name_attribute in the mft record @m_file which points to the |
3264 | * parent directory with mft reference @ref_parent. |
3265 | * |
3266 | * Then, insert an index entry with this file_name_attribute in the index |
3267 | * block @idx of the index allocation attribute of the parent directory. |
3268 | * |
3269 | * @ref_file is the mft reference of @m_file. |
3270 | * |
3271 | * Return 0 on success or -errno on error. |
3272 | */ |
3273 | static int create_hardlink(INDEX_BLOCK *idx, const leMFT_REF ref_parent, |
3274 | MFT_RECORD *m_file, const leMFT_REF ref_file, |
3275 | const s64 allocated_size, const s64 data_size, |
3276 | const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, |
3277 | const u32 reparse_point_tag, const char *file_name, |
3278 | const FILE_NAME_TYPE_FLAGS file_name_type) |
3279 | { |
3280 | FILE_NAME_ATTR *fn; |
3281 | int i, fn_size; |
3282 | ntfschar *uname; |
3283 | |
3284 | /* Create the file_name attribute. */ |
3285 | i = (strlen(file_name) + 1) * sizeof(ntfschar); |
3286 | fn_size = sizeof(FILE_NAME_ATTR) + i; |
3287 | fn = ntfs_malloc(fn_size); |
3288 | if (!fn) |
3289 | return -errno; |
3290 | fn->parent_directory = ref_parent; |
3291 | fn->creation_time = stdinfo_time(m_file); |
3292 | fn->last_data_change_time = fn->creation_time; |
3293 | fn->last_mft_change_time = fn->creation_time; |
3294 | fn->last_access_time = fn->creation_time; |
3295 | /* allocated size depends on unnamed data being resident */ |
3296 | if (allocated_size && non_resident_unnamed_data(m_file)) |
3297 | fn->allocated_size = cpu_to_sle64(allocated_size); |
3298 | else |
3299 | fn->allocated_size = cpu_to_sle64((data_size + 7) & -8); |
3300 | fn->data_size = cpu_to_sle64(data_size); |
3301 | fn->file_attributes = flags; |
3302 | /* These are in a union so can't have both. */ |
3303 | if (packed_ea_size && reparse_point_tag) { |
3304 | free(fn); |
3305 | return -EINVAL; |
3306 | } |
3307 | if (packed_ea_size) { |
3308 | fn->packed_ea_size = cpu_to_le16(packed_ea_size); |
3309 | fn->reserved = cpu_to_le16(0); |
3310 | } else { |
3311 | fn->reparse_point_tag = cpu_to_le32(reparse_point_tag); |
3312 | } |
3313 | fn->file_name_type = file_name_type; |
3314 | uname = fn->file_name; |
3315 | i = ntfs_mbstoucs_libntfscompat(file_name, &uname, i); |
3316 | if (i < 1) { |
3317 | free(fn); |
3318 | return -EINVAL; |
3319 | } |
3320 | if (i > 0xff) { |
3321 | free(fn); |
3322 | return -ENAMETOOLONG; |
3323 | } |
3324 | /* No terminating null in file names. */ |
3325 | fn->file_name_length = i; |
3326 | fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); |
3327 | /* Increment the link count of @m_file. */ |
3328 | i = le16_to_cpu(m_file->link_count); |
3329 | if (i == 0xffff) { |
3330 | ntfs_log_error("Too many hardlinks present already.\n"); |
3331 | free(fn); |
3332 | return -EINVAL; |
3333 | } |
3334 | m_file->link_count = cpu_to_le16(i + 1); |
3335 | /* Add the file_name to @m_file. */ |
3336 | i = insert_resident_attr_in_mft_record(m_file, AT_FILE_NAME, NULL, 0, |
3337 | CASE_SENSITIVE, cpu_to_le16(0), |
3338 | RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); |
3339 | if (i < 0) { |
3340 | ntfs_log_error("create_hardlink failed adding file name attribute: " |
3341 | "%s\n", strerror(-i)); |
3342 | free(fn); |
3343 | /* Undo link count increment. */ |
3344 | m_file->link_count = cpu_to_le16( |
3345 | le16_to_cpu(m_file->link_count) - 1); |
3346 | return i; |
3347 | } |
3348 | /* Insert the index entry for file_name in @idx. */ |
3349 | i = insert_file_link_in_dir_index(idx, ref_file, fn, fn_size); |
3350 | if (i < 0) { |
3351 | ntfs_log_error("create_hardlink failed inserting index entry: %s\n", |
3352 | strerror(-i)); |
3353 | /* FIXME: Remove the file name attribute from @m_file. */ |
3354 | free(fn); |
3355 | /* Undo link count increment. */ |
3356 | m_file->link_count = cpu_to_le16( |
3357 | le16_to_cpu(m_file->link_count) - 1); |
3358 | return i; |
3359 | } |
3360 | free(fn); |
3361 | return 0; |
3362 | } |
3363 | |
3364 | /** |
3365 | * index_obj_id_insert |
3366 | * |
3367 | * Insert an index entry with the key @guid and data pointing to the mft record |
3368 | * @ref in the $O index root of the mft record @m (which must be the mft record |
3369 | * for $ObjId). |
3370 | * |
3371 | * Return 0 on success or -errno on error. |
3372 | */ |
3373 | static int index_obj_id_insert(MFT_RECORD *m, const GUID *guid, |
3374 | const leMFT_REF ref) |
3375 | { |
3376 | INDEX_ENTRY *idx_entry_new; |
3377 | int data_ofs, idx_size, err; |
3378 | OBJ_ID_INDEX_DATA *oi; |
3379 | |
3380 | /* |
3381 | * Insert the index entry for the object id in the index. |
3382 | * |
3383 | * First determine the size of the index entry to be inserted. This |
3384 | * consists of the index entry header, followed by the index key, i.e. |
3385 | * the GUID, followed by the index data, i.e. OBJ_ID_INDEX_DATA. |
3386 | */ |
3387 | data_ofs = (sizeof(INDEX_ENTRY_HEADER) + sizeof(GUID) + 7) & ~7; |
3388 | idx_size = (data_ofs + sizeof(OBJ_ID_INDEX_DATA) + 7) & ~7; |
3389 | idx_entry_new = ntfs_calloc(idx_size); |
3390 | if (!idx_entry_new) |
3391 | return -errno; |
3392 | idx_entry_new->data_offset = cpu_to_le16(data_ofs); |
3393 | idx_entry_new->data_length = cpu_to_le16(sizeof(OBJ_ID_INDEX_DATA)); |
3394 | idx_entry_new->length = cpu_to_le16(idx_size); |
3395 | idx_entry_new->key_length = cpu_to_le16(sizeof(GUID)); |
3396 | idx_entry_new->key.object_id = *guid; |
3397 | oi = (OBJ_ID_INDEX_DATA*)((u8*)idx_entry_new + data_ofs); |
3398 | oi->mft_reference = ref; |
3399 | err = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size, m, |
3400 | NTFS_INDEX_O, 2, AT_UNUSED); |
3401 | free(idx_entry_new); |
3402 | if (err < 0) { |
3403 | ntfs_log_error("index_obj_id_insert failed inserting index " |
3404 | "entry: %s\n", strerror(-err)); |
3405 | return err; |
3406 | } |
3407 | return 0; |
3408 | } |
3409 | |
3410 | /** |
3411 | * mkntfs_cleanup |
3412 | */ |
3413 | static void mkntfs_cleanup(void) |
3414 | { |
3415 | struct BITMAP_ALLOCATION *p, *q; |
3416 | |
3417 | /* Close the volume */ |
3418 | if (g_vol) { |
3419 | if (g_vol->dev) { |
3420 | if (NDevOpen(g_vol->dev) && g_vol->dev->d_ops->close(g_vol->dev)) |
3421 | ntfs_log_perror("Warning: Could not close %s", g_vol->dev->d_name); |
3422 | ntfs_device_free(g_vol->dev); |
3423 | } |
3424 | free(g_vol->vol_name); |
3425 | free(g_vol->attrdef); |
3426 | free(g_vol->upcase); |
3427 | free(g_vol); |
3428 | g_vol = NULL; |
3429 | } |
3430 | |
3431 | /* Free any memory we've used */ |
3432 | free(g_bad_blocks); g_bad_blocks = NULL; |
3433 | free(g_buf); g_buf = NULL; |
3434 | free(g_index_block); g_index_block = NULL; |
3435 | free(g_dynamic_buf); g_dynamic_buf = NULL; |
3436 | free(g_mft_bitmap); g_mft_bitmap = NULL; |
3437 | free(g_rl_bad); g_rl_bad = NULL; |
3438 | free(g_rl_boot); g_rl_boot = NULL; |
3439 | free(g_rl_logfile); g_rl_logfile = NULL; |
3440 | free(g_rl_mft); g_rl_mft = NULL; |
3441 | free(g_rl_mft_bmp); g_rl_mft_bmp = NULL; |
3442 | free(g_rl_mftmirr); g_rl_mftmirr = NULL; |
3443 | |
3444 | p = g_allocation; |
3445 | while (p) { |
3446 | q = p->next; |
3447 | free(p); |
3448 | p = q; |
3449 | } |
3450 | } |
3451 | |
3452 | |
3453 | /** |
3454 | * mkntfs_open_partition - |
3455 | */ |
3456 | static BOOL mkntfs_open_partition(ntfs_volume *vol) |
3457 | { |
3458 | BOOL result = FALSE; |
3459 | int i; |
3460 | struct stat sbuf; |
3461 | unsigned long mnt_flags; |
3462 | |
3463 | /* |
3464 | * Allocate and initialize an ntfs device structure and attach it to |
3465 | * the volume. |
3466 | */ |
3467 | vol->dev = ntfs_device_alloc(opts.dev_name, 0, &ntfs_device_default_io_ops, NULL); |
3468 | if (!vol->dev) { |
3469 | ntfs_log_perror("Could not create device"); |
3470 | goto done; |
3471 | } |
3472 | |
3473 | /* Open the device for reading or reading and writing. */ |
3474 | if (opts.no_action) { |
3475 | ntfs_log_quiet("Running in READ-ONLY mode!\n"); |
3476 | i = O_RDONLY; |
3477 | } else { |
3478 | i = O_RDWR; |
3479 | } |
3480 | if (vol->dev->d_ops->open(vol->dev, i)) { |
3481 | if (errno == ENOENT) |
3482 | ntfs_log_error("The device doesn't exist; did you specify it correctly?\n"); |
3483 | else |
3484 | ntfs_log_perror("Could not open %s", vol->dev->d_name); |
3485 | goto done; |
3486 | } |
3487 | /* Verify we are dealing with a block device. */ |
3488 | if (vol->dev->d_ops->stat(vol->dev, &sbuf)) { |
3489 | ntfs_log_perror("Error getting information about %s", vol->dev->d_name); |
3490 | goto done; |
3491 | } |
3492 | |
3493 | if (!S_ISBLK(sbuf.st_mode)) { |
3494 | ntfs_log_error("%s is not a block device.\n", vol->dev->d_name); |
3495 | if (!opts.force) { |
3496 | ntfs_log_error("Refusing to make a filesystem here!\n"); |
3497 | goto done; |
3498 | } |
3499 | if (!opts.num_sectors) { |
3500 | if (!sbuf.st_size && !sbuf.st_blocks) { |
3501 | ntfs_log_error("You must specify the number of sectors.\n"); |
3502 | goto done; |
3503 | } |
3504 | if (opts.sector_size) { |
3505 | if (sbuf.st_size) |
3506 | opts.num_sectors = sbuf.st_size / opts.sector_size; |
3507 | else |
3508 | opts.num_sectors = ((s64)sbuf.st_blocks << 9) / opts.sector_size; |
3509 | } else { |
3510 | if (sbuf.st_size) |
3511 | opts.num_sectors = sbuf.st_size / 512; |
3512 | else |
3513 | opts.num_sectors = sbuf.st_blocks; |
3514 | opts.sector_size = 512; |
3515 | } |
3516 | } |
3517 | ntfs_log_warning("mkntfs forced anyway.\n"); |
3518 | #ifdef HAVE_LINUX_MAJOR_H |
3519 | } else if ((IDE_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && |
3520 | MINOR(sbuf.st_rdev) % 64 == 0) || |
3521 | (SCSI_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && |
3522 | MINOR(sbuf.st_rdev) % 16 == 0)) { |
3523 | ntfs_log_error("%s is entire device, not just one partition.\n", vol->dev->d_name); |
3524 | if (!opts.force) { |
3525 | ntfs_log_error("Refusing to make a filesystem here!\n"); |
3526 | goto done; |
3527 | } |
3528 | ntfs_log_warning("mkntfs forced anyway.\n"); |
3529 | #endif |
3530 | } |
3531 | /* Make sure the file system is not mounted. */ |
3532 | if (ntfs_check_if_mounted(vol->dev->d_name, &mnt_flags)) { |
3533 | ntfs_log_perror("Failed to determine whether %s is mounted", vol->dev->d_name); |
3534 | } else if (mnt_flags & NTFS_MF_MOUNTED) { |
3535 | ntfs_log_error("%s is mounted.\n", vol->dev->d_name); |
3536 | if (!opts.force) { |
3537 | ntfs_log_error("Refusing to make a filesystem here!\n"); |
3538 | goto done; |
3539 | } |
3540 | ntfs_log_warning("mkntfs forced anyway. Hope /etc/mtab is incorrect.\n"); |
3541 | } |
3542 | result = TRUE; |
3543 | done: |
3544 | return result; |
3545 | } |
3546 | |
3547 | /** |
3548 | * mkntfs_get_page_size - detect the system's memory page size. |
3549 | */ |
3550 | static long mkntfs_get_page_size(void) |
3551 | { |
3552 | long page_size; |
3553 | #ifdef _SC_PAGESIZE |
3554 | page_size = sysconf(_SC_PAGESIZE); |
3555 | if (page_size < 0) |
3556 | #endif |
3557 | { |
3558 | ntfs_log_warning("Failed to determine system page size. " |
3559 | "Assuming safe default of 4096 bytes.\n"); |
3560 | return 4096; |
3561 | } |
3562 | ntfs_log_debug("System page size is %li bytes.\n", page_size); |
3563 | return page_size; |
3564 | } |
3565 | |
3566 | /** |
3567 | * mkntfs_override_vol_params - |
3568 | */ |
3569 | static BOOL mkntfs_override_vol_params(ntfs_volume *vol) |
3570 | { |
3571 | s64 volume_size; |
3572 | long page_size; |
3573 | int i; |
3574 | BOOL winboot = TRUE; |
3575 | |
3576 | /* If user didn't specify the sector size, determine it now. */ |
3577 | if (opts.sector_size < 0) { |
3578 | opts.sector_size = ntfs_device_sector_size_get(vol->dev); |
3579 | if (opts.sector_size < 0) { |
3580 | ntfs_log_warning("The sector size was not specified " |
3581 | "for %s and it could not be obtained " |
3582 | "automatically. It has been set to 512 " |
3583 | "bytes.\n", vol->dev->d_name); |
3584 | opts.sector_size = 512; |
3585 | } |
3586 | } |
3587 | /* Validate sector size. */ |
3588 | if ((opts.sector_size - 1) & opts.sector_size) { |
3589 | ntfs_log_error("The sector size is invalid. It must be a " |
3590 | "power of two, e.g. 512, 1024.\n"); |
3591 | return FALSE; |
3592 | } |
3593 | if (opts.sector_size < 256 || opts.sector_size > 4096) { |
3594 | ntfs_log_error("The sector size is invalid. The minimum size " |
3595 | "is 256 bytes and the maximum is 4096 bytes.\n"); |
3596 | return FALSE; |
3597 | } |
3598 | ntfs_log_debug("sector size = %ld bytes\n", opts.sector_size); |
3599 | /* Now set the device block size to the sector size. */ |
3600 | if (ntfs_device_block_size_set(vol->dev, opts.sector_size)) |
3601 | ntfs_log_debug("Failed to set the device block size to the " |
3602 | "sector size. This may cause problems when " |
3603 | "creating the backup boot sector and also may " |
3604 | "affect performance but should be harmless " |
3605 | "otherwise. Error: %s\n", strerror(errno)); |
3606 | /* If user didn't specify the number of sectors, determine it now. */ |
3607 | if (opts.num_sectors < 0) { |
3608 | opts.num_sectors = ntfs_device_size_get(vol->dev, |
3609 | opts.sector_size); |
3610 | if (opts.num_sectors <= 0) { |
3611 | ntfs_log_error("Couldn't determine the size of %s. " |
3612 | "Please specify the number of sectors " |
3613 | "manually.\n", vol->dev->d_name); |
3614 | return FALSE; |
3615 | } |
3616 | } |
3617 | ntfs_log_debug("number of sectors = %lld (0x%llx)\n", opts.num_sectors, |
3618 | opts.num_sectors); |
3619 | /* |
3620 | * Reserve the last sector for the backup boot sector unless the |
3621 | * sector size is less than 512 bytes in which case reserve 512 bytes |
3622 | * worth of sectors. |
3623 | */ |
3624 | i = 1; |
3625 | if (opts.sector_size < 512) |
3626 | i = 512 / opts.sector_size; |
3627 | opts.num_sectors -= i; |
3628 | /* If user didn't specify the partition start sector, determine it. */ |
3629 | if (opts.part_start_sect < 0) { |
3630 | opts.part_start_sect = ntfs_device_partition_start_sector_get( |
3631 | vol->dev); |
3632 | if (opts.part_start_sect < 0) { |
3633 | ntfs_log_warning("The partition start sector was not " |
3634 | "specified for %s and it could not be obtained " |
3635 | "automatically. It has been set to 0.\n", |
3636 | vol->dev->d_name); |
3637 | opts.part_start_sect = 0; |
3638 | winboot = FALSE; |
3639 | } else if (opts.part_start_sect >> 32) { |
3640 | ntfs_log_warning("The partition start sector specified " |
3641 | "for %s and the automatically determined value " |
3642 | "is too large. It has been set to 0.\n", |
3643 | vol->dev->d_name); |
3644 | opts.part_start_sect = 0; |
3645 | winboot = FALSE; |
3646 | } |
3647 | } else if (opts.part_start_sect >> 32) { |
3648 | ntfs_log_error("Invalid partition start sector. Maximum is " |
3649 | "4294967295 (2^32-1).\n"); |
3650 | return FALSE; |
3651 | } |
3652 | /* If user didn't specify the sectors per track, determine it now. */ |
3653 | if (opts.sectors_per_track < 0) { |
3654 | opts.sectors_per_track = ntfs_device_sectors_per_track_get( |
3655 | vol->dev); |
3656 | if (opts.sectors_per_track < 0) { |
3657 | ntfs_log_warning("The number of sectors per track was " |
3658 | "not specified for %s and it could not be " |
3659 | "obtained automatically. It has been set to " |
3660 | "0.\n", vol->dev->d_name); |
3661 | opts.sectors_per_track = 0; |
3662 | winboot = FALSE; |
3663 | } else if (opts.sectors_per_track > 65535) { |
3664 | ntfs_log_warning("The number of sectors per track was " |
3665 | "not specified for %s and the automatically " |
3666 | "determined value is too large. It has been " |
3667 | "set to 0.\n", vol->dev->d_name); |
3668 | opts.sectors_per_track = 0; |
3669 | winboot = FALSE; |
3670 | } |
3671 | } else if (opts.sectors_per_track > 65535) { |
3672 | ntfs_log_error("Invalid number of sectors per track. Maximum " |
3673 | "is 65535.\n"); |
3674 | return FALSE; |
3675 | } |
3676 | /* If user didn't specify the number of heads, determine it now. */ |
3677 | if (opts.heads < 0) { |
3678 | opts.heads = ntfs_device_heads_get(vol->dev); |
3679 | if (opts.heads < 0) { |
3680 | ntfs_log_warning("The number of heads was not " |
3681 | "specified for %s and it could not be obtained " |
3682 | "automatically. It has been set to 0.\n", |
3683 | vol->dev->d_name); |
3684 | opts.heads = 0; |
3685 | winboot = FALSE; |
3686 | } else if (opts.heads > 65535) { |
3687 | ntfs_log_warning("The number of heads was not " |
3688 | "specified for %s and the automatically " |
3689 | "determined value is too large. It has been " |
3690 | "set to 0.\n", vol->dev->d_name); |
3691 | opts.heads = 0; |
3692 | winboot = FALSE; |
3693 | } |
3694 | } else if (opts.heads > 65535) { |
3695 | ntfs_log_error("Invalid number of heads. Maximum is 65535.\n"); |
3696 | return FALSE; |
3697 | } |
3698 | volume_size = opts.num_sectors * opts.sector_size; |
3699 | /* Validate volume size. */ |
3700 | if (volume_size < (1 << 20)) { /* 1MiB */ |
3701 | ntfs_log_error("Device is too small (%llikiB). Minimum NTFS " |
3702 | "volume size is 1MiB.\n", |
3703 | (long long)(volume_size / 1024)); |
3704 | return FALSE; |
3705 | } |
3706 | ntfs_log_debug("volume size = %llikiB\n", volume_size / 1024); |
3707 | /* If user didn't specify the cluster size, determine it now. */ |
3708 | if (!vol->cluster_size) { |
3709 | /* |
3710 | * Windows Vista always uses 4096 bytes as the default cluster |
3711 | * size regardless of the volume size so we do it, too. |
3712 | */ |
3713 | vol->cluster_size = 4096; |
3714 | /* For small volumes on devices with large sector sizes. */ |
3715 | if (vol->cluster_size < (u32)opts.sector_size) |
3716 | vol->cluster_size = opts.sector_size; |
3717 | /* |
3718 | * For huge volumes, grow the cluster size until the number of |
3719 | * clusters fits into 32 bits or the cluster size exceeds the |
3720 | * maximum limit of 64kiB. |
3721 | */ |
3722 | while (volume_size >> (ffs(vol->cluster_size) - 1 + 32)) { |
3723 | vol->cluster_size <<= 1; |
3724 | if (vol->cluster_size > 65535) { |
3725 | ntfs_log_error("Device is too large to hold an " |
3726 | "NTFS volume (maximum size is " |
3727 | "256TiB).\n"); |
3728 | return FALSE; |
3729 | } |
3730 | } |
3731 | ntfs_log_quiet("Cluster size has been automatically set to %u " |
3732 | "bytes.\n", (unsigned)vol->cluster_size); |
3733 | } |
3734 | /* Validate cluster size. */ |
3735 | if (vol->cluster_size & (vol->cluster_size - 1)) { |
3736 | ntfs_log_error("The cluster size is invalid. It must be a " |
3737 | "power of two, e.g. 1024, 4096.\n"); |
3738 | return FALSE; |
3739 | } |
3740 | if (vol->cluster_size < (u32)opts.sector_size) { |
3741 | ntfs_log_error("The cluster size is invalid. It must be equal " |
3742 | "to, or larger than, the sector size.\n"); |
3743 | return FALSE; |
3744 | } |
3745 | if (vol->cluster_size > 128 * (u32)opts.sector_size) { |
3746 | ntfs_log_error("The cluster size is invalid. It cannot be " |
3747 | "more that 128 times the size of the sector " |
3748 | "size.\n"); |
3749 | return FALSE; |
3750 | } |
3751 | if (vol->cluster_size > 65536) { |
3752 | ntfs_log_error("The cluster size is invalid. The maximum " |
3753 | "cluster size is 65536 bytes (64kiB).\n"); |
3754 | return FALSE; |
3755 | } |
3756 | vol->cluster_size_bits = ffs(vol->cluster_size) - 1; |
3757 | ntfs_log_debug("cluster size = %u bytes\n", |
3758 | (unsigned int)vol->cluster_size); |
3759 | if (vol->cluster_size > 4096) { |
3760 | if (opts.enable_compression) { |
3761 | if (!opts.force) { |
3762 | ntfs_log_error("Windows cannot use compression " |
3763 | "when the cluster size is " |
3764 | "larger than 4096 bytes.\n"); |
3765 | return FALSE; |
3766 | } |
3767 | opts.enable_compression = 0; |
3768 | } |
3769 | ntfs_log_warning("Windows cannot use compression when the " |
3770 | "cluster size is larger than 4096 bytes. " |
3771 | "Compression has been disabled for this " |
3772 | "volume.\n"); |
3773 | } |
3774 | vol->nr_clusters = volume_size / vol->cluster_size; |
3775 | /* |
3776 | * Check the cluster_size and num_sectors for consistency with |
3777 | * sector_size and num_sectors. And check both of these for consistency |
3778 | * with volume_size. |
3779 | */ |
3780 | if ((vol->nr_clusters != ((opts.num_sectors * opts.sector_size) / |
3781 | vol->cluster_size) || |
3782 | (volume_size / opts.sector_size) != opts.num_sectors || |
3783 | (volume_size / vol->cluster_size) != |
3784 | vol->nr_clusters)) { |
3785 | /* XXX is this code reachable? */ |
3786 | ntfs_log_error("Illegal combination of volume/cluster/sector " |
3787 | "size and/or cluster/sector number.\n"); |
3788 | return FALSE; |
3789 | } |
3790 | ntfs_log_debug("number of clusters = %llu (0x%llx)\n", |
3791 | vol->nr_clusters, vol->nr_clusters); |
3792 | /* Number of clusters must fit within 32 bits (Win2k limitation). */ |
3793 | if (vol->nr_clusters >> 32) { |
3794 | if (vol->cluster_size >= 65536) { |
3795 | ntfs_log_error("Device is too large to hold an NTFS " |
3796 | "volume (maximum size is 256TiB).\n"); |
3797 | return FALSE; |
3798 | } |
3799 | ntfs_log_error("Number of clusters exceeds 32 bits. Please " |
3800 | "try again with a larger\ncluster size or " |
3801 | "leave the cluster size unspecified and the " |
3802 | "smallest possible cluster size for the size " |
3803 | "of the device will be used.\n"); |
3804 | return FALSE; |
3805 | } |
3806 | page_size = mkntfs_get_page_size(); |
3807 | /* |
3808 | * Set the mft record size. By default this is 1024 but it has to be |
3809 | * at least as big as a sector and not bigger than a page on the system |
3810 | * or the NTFS kernel driver will not be able to mount the volume. |
3811 | * TODO: The mft record size should be user specifiable just like the |
3812 | * "inode size" can be specified on other Linux/Unix file systems. |
3813 | */ |
3814 | vol->mft_record_size = 1024; |
3815 | if (vol->mft_record_size < (u32)opts.sector_size) |
3816 | vol->mft_record_size = opts.sector_size; |
3817 | if (vol->mft_record_size > (unsigned long)page_size) |
3818 | ntfs_log_warning("Mft record size (%u bytes) exceeds system " |
3819 | "page size (%li bytes). You will not be able " |
3820 | "to mount this volume using the NTFS kernel " |
3821 | "driver.\n", (unsigned)vol->mft_record_size, |
3822 | page_size); |
3823 | vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1; |
3824 | ntfs_log_debug("mft record size = %u bytes\n", |
3825 | (unsigned)vol->mft_record_size); |
3826 | /* |
3827 | * Set the index record size. By default this is 4096 but it has to be |
3828 | * at least as big as a sector and not bigger than a page on the system |
3829 | * or the NTFS kernel driver will not be able to mount the volume. |
3830 | * FIXME: Should we make the index record size to be user specifiable? |
3831 | */ |
3832 | vol->indx_record_size = 4096; |
3833 | if (vol->indx_record_size < (u32)opts.sector_size) |
3834 | vol->indx_record_size = opts.sector_size; |
3835 | if (vol->indx_record_size > (unsigned long)page_size) |
3836 | ntfs_log_warning("Index record size (%u bytes) exceeds system " |
3837 | "page size (%li bytes). You will not be able " |
3838 | "to mount this volume using the NTFS kernel " |
3839 | "driver.\n", (unsigned)vol->indx_record_size, |
3840 | page_size); |
3841 | vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1; |
3842 | ntfs_log_debug("index record size = %u bytes\n", |
3843 | (unsigned)vol->indx_record_size); |
3844 | if (!winboot) { |
3845 | ntfs_log_warning("To boot from a device, Windows needs the " |
3846 | "'partition start sector', the 'sectors per " |
3847 | "track' and the 'number of heads' to be " |
3848 | "set.\n"); |
3849 | ntfs_log_warning("Windows will not be able to boot from this " |
3850 | "device.\n"); |
3851 | } |
3852 | return TRUE; |
3853 | } |
3854 | |
3855 | /** |
3856 | * mkntfs_initialize_bitmaps - |
3857 | */ |
3858 | static BOOL mkntfs_initialize_bitmaps(void) |
3859 | { |
3860 | u64 i; |
3861 | int mft_bitmap_size; |
3862 | |
3863 | /* Determine lcn bitmap byte size and allocate it. */ |
3864 | g_lcn_bitmap_byte_size = (g_vol->nr_clusters + 7) >> 3; |
3865 | /* Needs to be multiple of 8 bytes. */ |
3866 | g_lcn_bitmap_byte_size = (g_lcn_bitmap_byte_size + 7) & ~7; |
3867 | i = (g_lcn_bitmap_byte_size + g_vol->cluster_size - 1) & |
3868 | ~(g_vol->cluster_size - 1); |
3869 | ntfs_log_debug("g_lcn_bitmap_byte_size = %i, allocated = %llu\n", |
3870 | g_lcn_bitmap_byte_size, i); |
3871 | g_dynamic_buf_size = mkntfs_get_page_size(); |
3872 | g_dynamic_buf = (u8*)ntfs_calloc(g_dynamic_buf_size); |
3873 | if (!g_dynamic_buf) |
3874 | return FALSE; |
3875 | /* |
3876 | * $Bitmap can overlap the end of the volume. Any bits in this region |
3877 | * must be set. This region also encompasses the backup boot sector. |
3878 | */ |
3879 | if (!bitmap_allocate(g_vol->nr_clusters, |
3880 | ((s64)g_lcn_bitmap_byte_size << 3) - g_vol->nr_clusters)) |
3881 | return (FALSE); |
3882 | /* |
3883 | * Mft size is 27 (NTFS 3.0+) mft records or one cluster, whichever is |
3884 | * bigger. |
3885 | */ |
3886 | g_mft_size = 27; |
3887 | g_mft_size *= g_vol->mft_record_size; |
3888 | if (g_mft_size < (s32)g_vol->cluster_size) |
3889 | g_mft_size = g_vol->cluster_size; |
3890 | ntfs_log_debug("MFT size = %i (0x%x) bytes\n", g_mft_size, g_mft_size); |
3891 | /* Determine mft bitmap size and allocate it. */ |
3892 | mft_bitmap_size = g_mft_size / g_vol->mft_record_size; |
3893 | /* Convert to bytes, at least one. */ |
3894 | g_mft_bitmap_byte_size = (mft_bitmap_size + 7) >> 3; |
3895 | /* Mft bitmap is allocated in multiples of 8 bytes. */ |
3896 | g_mft_bitmap_byte_size = (g_mft_bitmap_byte_size + 7) & ~7; |
3897 | ntfs_log_debug("mft_bitmap_size = %i, g_mft_bitmap_byte_size = %i\n", |
3898 | mft_bitmap_size, g_mft_bitmap_byte_size); |
3899 | g_mft_bitmap = ntfs_calloc(g_mft_bitmap_byte_size); |
3900 | if (!g_mft_bitmap) |
3901 | return FALSE; |
3902 | /* Create runlist for mft bitmap. */ |
3903 | g_rl_mft_bmp = ntfs_malloc(2 * sizeof(runlist)); |
3904 | if (!g_rl_mft_bmp) |
3905 | return FALSE; |
3906 | |
3907 | g_rl_mft_bmp[0].vcn = 0LL; |
3908 | /* Mft bitmap is right after $Boot's data. */ |
3909 | i = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size; |
3910 | g_rl_mft_bmp[0].lcn = i; |
3911 | /* |
3912 | * Size is always one cluster, even though valid data size and |
3913 | * initialized data size are only 8 bytes. |
3914 | */ |
3915 | g_rl_mft_bmp[1].vcn = 1LL; |
3916 | g_rl_mft_bmp[0].length = 1LL; |
3917 | g_rl_mft_bmp[1].lcn = -1LL; |
3918 | g_rl_mft_bmp[1].length = 0LL; |
3919 | /* Allocate cluster for mft bitmap. */ |
3920 | return (bitmap_allocate(i,1)); |
3921 | } |
3922 | |
3923 | /** |
3924 | * mkntfs_initialize_rl_mft - |
3925 | */ |
3926 | static BOOL mkntfs_initialize_rl_mft(void) |
3927 | { |
3928 | int j; |
3929 | BOOL done; |
3930 | |
3931 | /* If user didn't specify the mft lcn, determine it now. */ |
3932 | if (!g_mft_lcn) { |
3933 | /* |
3934 | * We start at the higher value out of 16kiB and just after the |
3935 | * mft bitmap. |
3936 | */ |
3937 | g_mft_lcn = g_rl_mft_bmp[0].lcn + g_rl_mft_bmp[0].length; |
3938 | if (g_mft_lcn * g_vol->cluster_size < 16 * 1024) |
3939 | g_mft_lcn = (16 * 1024 + g_vol->cluster_size - 1) / |
3940 | g_vol->cluster_size; |
3941 | } |
3942 | ntfs_log_debug("$MFT logical cluster number = 0x%llx\n", g_mft_lcn); |
3943 | /* Determine MFT zone size. */ |
3944 | g_mft_zone_end = g_vol->nr_clusters; |
3945 | switch (opts.mft_zone_multiplier) { /* % of volume size in clusters */ |
3946 | case 4: |
3947 | g_mft_zone_end = g_mft_zone_end >> 1; /* 50% */ |
3948 | break; |
3949 | case 3: |
3950 | g_mft_zone_end = g_mft_zone_end * 3 >> 3;/* 37.5% */ |
3951 | break; |
3952 | case 2: |
3953 | g_mft_zone_end = g_mft_zone_end >> 2; /* 25% */ |
3954 | break; |
3955 | case 1: |
3956 | default: |
3957 | g_mft_zone_end = g_mft_zone_end >> 3; /* 12.5% */ |
3958 | break; |
3959 | } |
3960 | ntfs_log_debug("MFT zone size = %lldkiB\n", g_mft_zone_end << |
3961 | g_vol->cluster_size_bits >> 10 /* >> 10 == / 1024 */); |
3962 | /* |
3963 | * The mft zone begins with the mft data attribute, not at the beginning |
3964 | * of the device. |
3965 | */ |
3966 | g_mft_zone_end += g_mft_lcn; |
3967 | /* Create runlist for mft. */ |
3968 | g_rl_mft = ntfs_malloc(2 * sizeof(runlist)); |
3969 | if (!g_rl_mft) |
3970 | return FALSE; |
3971 | |
3972 | g_rl_mft[0].vcn = 0LL; |
3973 | g_rl_mft[0].lcn = g_mft_lcn; |
3974 | /* rounded up division by cluster size */ |
3975 | j = (g_mft_size + g_vol->cluster_size - 1) / g_vol->cluster_size; |
3976 | g_rl_mft[1].vcn = j; |
3977 | g_rl_mft[0].length = j; |
3978 | g_rl_mft[1].lcn = -1LL; |
3979 | g_rl_mft[1].length = 0LL; |
3980 | /* Allocate clusters for mft. */ |
3981 | bitmap_allocate(g_mft_lcn,j); |
3982 | /* Determine mftmirr_lcn (middle of volume). */ |
3983 | g_mftmirr_lcn = (opts.num_sectors * opts.sector_size >> 1) |
3984 | / g_vol->cluster_size; |
3985 | ntfs_log_debug("$MFTMirr logical cluster number = 0x%llx\n", |
3986 | g_mftmirr_lcn); |
3987 | /* Create runlist for mft mirror. */ |
3988 | g_rl_mftmirr = ntfs_malloc(2 * sizeof(runlist)); |
3989 | if (!g_rl_mftmirr) |
3990 | return FALSE; |
3991 | |
3992 | g_rl_mftmirr[0].vcn = 0LL; |
3993 | g_rl_mftmirr[0].lcn = g_mftmirr_lcn; |
3994 | /* |
3995 | * The mft mirror is either 4kb (the first four records) or one cluster |
3996 | * in size, which ever is bigger. In either case, it contains a |
3997 | * byte-for-byte identical copy of the beginning of the mft (i.e. either |
3998 | * the first four records (4kb) or the first cluster worth of records, |
3999 | * whichever is bigger). |
4000 | */ |
4001 | j = (4 * g_vol->mft_record_size + g_vol->cluster_size - 1) / g_vol->cluster_size; |
4002 | g_rl_mftmirr[1].vcn = j; |
4003 | g_rl_mftmirr[0].length = j; |
4004 | g_rl_mftmirr[1].lcn = -1LL; |
4005 | g_rl_mftmirr[1].length = 0LL; |
4006 | /* Allocate clusters for mft mirror. */ |
4007 | done = bitmap_allocate(g_mftmirr_lcn,j); |
4008 | g_logfile_lcn = g_mftmirr_lcn + j; |
4009 | ntfs_log_debug("$LogFile logical cluster number = 0x%llx\n", |
4010 | g_logfile_lcn); |
4011 | return (done); |
4012 | } |
4013 | |
4014 | /** |
4015 | * mkntfs_initialize_rl_logfile - |
4016 | */ |
4017 | static BOOL mkntfs_initialize_rl_logfile(void) |
4018 | { |
4019 | int j; |
4020 | u64 volume_size; |
4021 | |
4022 | /* Create runlist for log file. */ |
4023 | g_rl_logfile = ntfs_malloc(2 * sizeof(runlist)); |
4024 | if (!g_rl_logfile) |
4025 | return FALSE; |
4026 | |
4027 | |
4028 | volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; |
4029 | |
4030 | g_rl_logfile[0].vcn = 0LL; |
4031 | g_rl_logfile[0].lcn = g_logfile_lcn; |
4032 | /* |
4033 | * Determine logfile_size from volume_size (rounded up to a cluster), |
4034 | * making sure it does not overflow the end of the volume. |
4035 | */ |
4036 | if (volume_size < 2048LL * 1024) /* < 2MiB */ |
4037 | g_logfile_size = 256LL * 1024; /* -> 256kiB */ |
4038 | else if (volume_size < 4000000LL) /* < 4MB */ |
4039 | g_logfile_size = 512LL * 1024; /* -> 512kiB */ |
4040 | else if (volume_size <= 200LL * 1024 * 1024) /* < 200MiB */ |
4041 | g_logfile_size = 2048LL * 1024; /* -> 2MiB */ |
4042 | else { |
4043 | /* |
4044 | * FIXME: The $LogFile size is 64 MiB upwards from 12GiB but |
4045 | * the "200" divider below apparently approximates "100" or |
4046 | * some other value as the volume size decreases. For example: |
4047 | * Volume size LogFile size Ratio |
4048 | * 8799808 46048 191.100 |
4049 | * 8603248 45072 190.877 |
4050 | * 7341704 38768 189.375 |
4051 | * 6144828 32784 187.433 |
4052 | * 4192932 23024 182.111 |
4053 | */ |
4054 | if (volume_size >= 12LL << 30) /* > 12GiB */ |
4055 | g_logfile_size = 64 << 20; /* -> 64MiB */ |
4056 | else |
4057 | g_logfile_size = (volume_size / 200) & |
4058 | ~(g_vol->cluster_size - 1); |
4059 | } |
4060 | j = g_logfile_size / g_vol->cluster_size; |
4061 | while (g_rl_logfile[0].lcn + j >= g_vol->nr_clusters) { |
4062 | /* |
4063 | * $Logfile would overflow volume. Need to make it smaller than |
4064 | * the standard size. It's ok as we are creating a non-standard |
4065 | * volume anyway if it is that small. |
4066 | */ |
4067 | g_logfile_size >>= 1; |
4068 | j = g_logfile_size / g_vol->cluster_size; |
4069 | } |
4070 | g_logfile_size = (g_logfile_size + g_vol->cluster_size - 1) & |
4071 | ~(g_vol->cluster_size - 1); |
4072 | ntfs_log_debug("$LogFile (journal) size = %ikiB\n", |
4073 | g_logfile_size / 1024); |
4074 | /* |
4075 | * FIXME: The 256kiB limit is arbitrary. Should find out what the real |
4076 | * minimum requirement for Windows is so it doesn't blue screen. |
4077 | */ |
4078 | if (g_logfile_size < 256 << 10) { |
4079 | ntfs_log_error("$LogFile would be created with invalid size. " |
4080 | "This is not allowed as it would cause Windows " |
4081 | "to blue screen and during boot.\n"); |
4082 | return FALSE; |
4083 | } |
4084 | g_rl_logfile[1].vcn = j; |
4085 | g_rl_logfile[0].length = j; |
4086 | g_rl_logfile[1].lcn = -1LL; |
4087 | g_rl_logfile[1].length = 0LL; |
4088 | /* Allocate clusters for log file. */ |
4089 | return (bitmap_allocate(g_logfile_lcn,j)); |
4090 | } |
4091 | |
4092 | /** |
4093 | * mkntfs_initialize_rl_boot - |
4094 | */ |
4095 | static BOOL mkntfs_initialize_rl_boot(void) |
4096 | { |
4097 | int j; |
4098 | /* Create runlist for $Boot. */ |
4099 | g_rl_boot = ntfs_malloc(2 * sizeof(runlist)); |
4100 | if (!g_rl_boot) |
4101 | return FALSE; |
4102 | |
4103 | g_rl_boot[0].vcn = 0LL; |
4104 | g_rl_boot[0].lcn = 0LL; |
4105 | /* |
4106 | * $Boot is always 8192 (0x2000) bytes or 1 cluster, whichever is |
4107 | * bigger. |
4108 | */ |
4109 | j = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size; |
4110 | g_rl_boot[1].vcn = j; |
4111 | g_rl_boot[0].length = j; |
4112 | g_rl_boot[1].lcn = -1LL; |
4113 | g_rl_boot[1].length = 0LL; |
4114 | /* Allocate clusters for $Boot. */ |
4115 | return (bitmap_allocate(0,j)); |
4116 | } |
4117 | |
4118 | /** |
4119 | * mkntfs_initialize_rl_bad - |
4120 | */ |
4121 | static BOOL mkntfs_initialize_rl_bad(void) |
4122 | { |
4123 | /* Create runlist for $BadClus, $DATA named stream $Bad. */ |
4124 | g_rl_bad = ntfs_malloc(2 * sizeof(runlist)); |
4125 | if (!g_rl_bad) |
4126 | return FALSE; |
4127 | |
4128 | g_rl_bad[0].vcn = 0LL; |
4129 | g_rl_bad[0].lcn = -1LL; |
4130 | /* |
4131 | * $BadClus named stream $Bad contains the whole volume as a single |
4132 | * sparse runlist entry. |
4133 | */ |
4134 | g_rl_bad[1].vcn = g_vol->nr_clusters; |
4135 | g_rl_bad[0].length = g_vol->nr_clusters; |
4136 | g_rl_bad[1].lcn = -1LL; |
4137 | g_rl_bad[1].length = 0LL; |
4138 | |
4139 | /* TODO: Mark bad blocks as such. */ |
4140 | return TRUE; |
4141 | } |
4142 | |
4143 | /** |
4144 | * mkntfs_fill_device_with_zeroes - |
4145 | */ |
4146 | static BOOL mkntfs_fill_device_with_zeroes(void) |
4147 | { |
4148 | /* |
4149 | * If not quick format, fill the device with 0s. |
4150 | * FIXME: Except bad blocks! (AIA) |
4151 | */ |
4152 | int i; |
4153 | ssize_t bw; |
4154 | unsigned long long position; |
4155 | float progress_inc = (float)g_vol->nr_clusters / 100; |
4156 | u64 volume_size; |
4157 | |
4158 | volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; |
4159 | |
4160 | ntfs_log_progress("Initializing device with zeroes: 0%%"); |
4161 | for (position = 0; position < (unsigned long long)g_vol->nr_clusters; |
4162 | position++) { |
4163 | if (!(position % (int)(progress_inc+1))) { |
4164 | ntfs_log_progress("\b\b\b\b%3.0f%%", position / |
4165 | progress_inc); |
4166 | } |
4167 | bw = mkntfs_write(g_vol->dev, g_buf, g_vol->cluster_size); |
4168 | if (bw != (ssize_t)g_vol->cluster_size) { |
4169 | if (bw != -1 || errno != EIO) { |
4170 | ntfs_log_error("This should not happen.\n"); |
4171 | return FALSE; |
4172 | } |
4173 | if (!position) { |
4174 | ntfs_log_error("Error: Cluster zero is bad. " |
4175 | "Cannot create NTFS file " |
4176 | "system.\n"); |
4177 | return FALSE; |
4178 | } |
4179 | /* Add the baddie to our bad blocks list. */ |
4180 | if (!append_to_bad_blocks(position)) |
4181 | return FALSE; |
4182 | ntfs_log_quiet("\nFound bad cluster (%lld). Adding to " |
4183 | "list of bad blocks.\nInitializing " |
4184 | "device with zeroes: %3.0f%%", position, |
4185 | position / progress_inc); |
4186 | /* Seek to next cluster. */ |
4187 | g_vol->dev->d_ops->seek(g_vol->dev, |
4188 | ((off_t)position + 1) * |
4189 | g_vol->cluster_size, SEEK_SET); |
4190 | } |
4191 | } |
4192 | ntfs_log_progress("\b\b\b\b100%%"); |
4193 | position = (volume_size & (g_vol->cluster_size - 1)) / |
4194 | opts.sector_size; |
4195 | for (i = 0; (unsigned long)i < position; i++) { |
4196 | bw = mkntfs_write(g_vol->dev, g_buf, opts.sector_size); |
4197 | if (bw != opts.sector_size) { |
4198 | if (bw != -1 || errno != EIO) { |
4199 | ntfs_log_error("This should not happen.\n"); |
4200 | return FALSE; |
4201 | } else if (i + 1ull == position) { |
4202 | ntfs_log_error("Error: Bad cluster found in " |
4203 | "location reserved for system " |
4204 | "file $Boot.\n"); |
4205 | return FALSE; |
4206 | } |
4207 | /* Seek to next sector. */ |
4208 | g_vol->dev->d_ops->seek(g_vol->dev, |
4209 | opts.sector_size, SEEK_CUR); |
4210 | } |
4211 | } |
4212 | ntfs_log_progress(" - Done.\n"); |
4213 | return TRUE; |
4214 | } |
4215 | |
4216 | /** |
4217 | * mkntfs_sync_index_record |
4218 | * |
4219 | * (ERSO) made a function out of this, but the reason for doing that |
4220 | * disappeared during coding.... |
4221 | */ |
4222 | static BOOL mkntfs_sync_index_record(INDEX_ALLOCATION* idx, MFT_RECORD* m, |
4223 | ntfschar* name, u32 name_len) |
4224 | { |
4225 | int i, err; |
4226 | ntfs_attr_search_ctx *ctx; |
4227 | ATTR_RECORD *a; |
4228 | long long lw; |
4229 | runlist *rl_index = NULL; |
4230 | |
4231 | i = 5 * sizeof(ntfschar); |
4232 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
4233 | if (!ctx) { |
4234 | ntfs_log_perror("Failed to allocate attribute search context"); |
4235 | return FALSE; |
4236 | } |
4237 | /* FIXME: This should be IGNORE_CASE! */ |
4238 | if (mkntfs_attr_lookup(AT_INDEX_ALLOCATION, name, name_len, |
4239 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
4240 | ntfs_attr_put_search_ctx(ctx); |
4241 | ntfs_log_error("BUG: $INDEX_ALLOCATION attribute not found.\n"); |
4242 | return FALSE; |
4243 | } |
4244 | a = ctx->attr; |
4245 | rl_index = ntfs_mapping_pairs_decompress(g_vol, a, NULL); |
4246 | if (!rl_index) { |
4247 | ntfs_attr_put_search_ctx(ctx); |
4248 | ntfs_log_error("Failed to decompress runlist of $INDEX_ALLOCATION " |
4249 | "attribute.\n"); |
4250 | return FALSE; |
4251 | } |
4252 | if (sle64_to_cpu(a->initialized_size) < i) { |
4253 | ntfs_attr_put_search_ctx(ctx); |
4254 | free(rl_index); |
4255 | ntfs_log_error("BUG: $INDEX_ALLOCATION attribute too short.\n"); |
4256 | return FALSE; |
4257 | } |
4258 | ntfs_attr_put_search_ctx(ctx); |
4259 | i = sizeof(INDEX_BLOCK) - sizeof(INDEX_HEADER) + |
4260 | le32_to_cpu(idx->index.allocated_size); |
4261 | err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)idx, i); |
4262 | if (err) { |
4263 | free(rl_index); |
4264 | ntfs_log_error("ntfs_mst_pre_write_fixup() failed while " |
4265 | "syncing index block.\n"); |
4266 | return FALSE; |
4267 | } |
4268 | lw = ntfs_rlwrite(g_vol->dev, rl_index, (u8*)idx, i, NULL, |
4269 | WRITE_STANDARD); |
4270 | free(rl_index); |
4271 | if (lw != i) { |
4272 | ntfs_log_error("Error writing $INDEX_ALLOCATION.\n"); |
4273 | return FALSE; |
4274 | } |
4275 | /* No more changes to @idx below here so no need for fixup: */ |
4276 | /* ntfs_mst_post_write_fixup((NTFS_RECORD*)idx); */ |
4277 | return TRUE; |
4278 | } |
4279 | |
4280 | /** |
4281 | * create_file_volume - |
4282 | */ |
4283 | static BOOL create_file_volume(MFT_RECORD *m, leMFT_REF root_ref, |
4284 | VOLUME_FLAGS fl, const GUID *volume_guid) |
4285 | { |
4286 | int i, err; |
4287 | u8 *sd; |
4288 | |
4289 | ntfs_log_verbose("Creating $Volume (mft record 3)\n"); |
4290 | m = (MFT_RECORD*)(g_buf + 3 * g_vol->mft_record_size); |
4291 | err = create_hardlink(g_index_block, root_ref, m, |
4292 | MK_LE_MREF(FILE_Volume, FILE_Volume), 0LL, 0LL, |
4293 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, |
4294 | "$Volume", FILE_NAME_WIN32_AND_DOS); |
4295 | if (!err) { |
4296 | init_system_file_sd(FILE_Volume, &sd, &i); |
4297 | err = add_attr_sd(m, sd, i); |
4298 | } |
4299 | if (!err) |
4300 | err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, |
4301 | const_cpu_to_le16(0), NULL, 0); |
4302 | if (!err) |
4303 | err = add_attr_vol_name(m, g_vol->vol_name, g_vol->vol_name ? |
4304 | strlen(g_vol->vol_name) : 0); |
4305 | if (!err) { |
4306 | if (fl & VOLUME_IS_DIRTY) |
4307 | ntfs_log_quiet("Setting the volume dirty so check " |
4308 | "disk runs on next reboot into " |
4309 | "Windows.\n"); |
4310 | err = add_attr_vol_info(m, fl, g_vol->major_ver, |
4311 | g_vol->minor_ver); |
4312 | } |
4313 | if (!err && opts.with_uuid) |
4314 | err = add_attr_object_id(m, volume_guid); |
4315 | if (err < 0) { |
4316 | ntfs_log_error("Couldn't create $Volume: %s\n", |
4317 | strerror(-err)); |
4318 | return FALSE; |
4319 | } |
4320 | return TRUE; |
4321 | } |
4322 | |
4323 | /** |
4324 | * create_backup_boot_sector |
4325 | * |
4326 | * Return 0 on success or -1 if it couldn't be created. |
4327 | */ |
4328 | static int create_backup_boot_sector(u8 *buff) |
4329 | { |
4330 | const char *s; |
4331 | ssize_t bw; |
4332 | int size, e; |
4333 | |
4334 | ntfs_log_verbose("Creating backup boot sector.\n"); |
4335 | /* |
4336 | * Write the first max(512, opts.sector_size) bytes from buf to the |
4337 | * last sector, but limit that to 8192 bytes of written data since that |
4338 | * is how big $Boot is (and how big our buffer is).. |
4339 | */ |
4340 | size = 512; |
4341 | if (size < opts.sector_size) |
4342 | size = opts.sector_size; |
4343 | if (g_vol->dev->d_ops->seek(g_vol->dev, (opts.num_sectors + 1) * |
4344 | opts.sector_size - size, SEEK_SET) == (off_t)-1) { |
4345 | ntfs_log_perror("Seek failed"); |
4346 | goto bb_err; |
4347 | } |
4348 | if (size > 8192) |
4349 | size = 8192; |
4350 | bw = mkntfs_write(g_vol->dev, buff, size); |
4351 | if (bw == size) |
4352 | return 0; |
4353 | e = errno; |
4354 | if (bw == -1LL) |
4355 | s = strerror(e); |
4356 | else |
4357 | s = "unknown error"; |
4358 | /* At least some 2.4 kernels return EIO instead of ENOSPC. */ |
4359 | if (bw != -1LL || (bw == -1LL && e != ENOSPC && e != EIO)) { |
4360 | ntfs_log_critical("Couldn't write backup boot sector: %s\n", s); |
4361 | return -1; |
4362 | } |
4363 | bb_err: |
4364 | ntfs_log_error("Couldn't write backup boot sector. This is due to a " |
4365 | "limitation in the\nLinux kernel. This is not a major " |
4366 | "problem as Windows check disk will create the\n" |
4367 | "backup boot sector when it is run on your next boot " |
4368 | "into Windows.\n"); |
4369 | return -1; |
4370 | } |
4371 | |
4372 | /** |
4373 | * mkntfs_create_root_structures - |
4374 | */ |
4375 | static BOOL mkntfs_create_root_structures(void) |
4376 | { |
4377 | NTFS_BOOT_SECTOR *bs; |
4378 | MFT_RECORD *m; |
4379 | leMFT_REF root_ref; |
4380 | leMFT_REF extend_ref; |
4381 | int i; |
4382 | int j; |
4383 | int err; |
4384 | u8 *sd; |
4385 | FILE_ATTR_FLAGS extend_flags; |
4386 | VOLUME_FLAGS volume_flags = const_cpu_to_le16(0); |
4387 | int nr_sysfiles; |
4388 | int buf_sds_first_size; |
4389 | char *buf_sds; |
4390 | GUID vol_guid; |
4391 | |
4392 | ntfs_log_quiet("Creating NTFS volume structures.\n"); |
4393 | nr_sysfiles = 27; |
4394 | /* |
4395 | * Setup an empty mft record. Note, we can just give 0 as the mft |
4396 | * reference as we are creating an NTFS 1.2 volume for which the mft |
4397 | * reference is ignored by ntfs_mft_record_layout(). |
4398 | * |
4399 | * Copy the mft record onto all 16 records in the buffer and setup the |
4400 | * sequence numbers of each system file to equal the mft record number |
4401 | * of that file (only for $MFT is the sequence number 1 rather than 0). |
4402 | */ |
4403 | for (i = 0; i < nr_sysfiles; i++) { |
4404 | if (ntfs_mft_record_layout(g_vol, 0, m = (MFT_RECORD *)(g_buf + |
4405 | i * g_vol->mft_record_size))) { |
4406 | ntfs_log_error("Failed to layout system mft records." |
4407 | "\n"); |
4408 | return FALSE; |
4409 | } |
4410 | if (i == 0 || i > 23) |
4411 | m->sequence_number = cpu_to_le16(1); |
4412 | else |
4413 | m->sequence_number = cpu_to_le16(i); |
4414 | } |
4415 | /* |
4416 | * If only one cluster contains all system files then |
4417 | * fill the rest of it with empty, formatted records. |
4418 | */ |
4419 | if (nr_sysfiles * (s32)g_vol->mft_record_size < g_mft_size) { |
4420 | for (i = nr_sysfiles; |
4421 | i * (s32)g_vol->mft_record_size < g_mft_size; i++) { |
4422 | m = (MFT_RECORD *)(g_buf + i * g_vol->mft_record_size); |
4423 | if (ntfs_mft_record_layout(g_vol, 0, m)) { |
4424 | ntfs_log_error("Failed to layout mft record." |
4425 | "\n"); |
4426 | return FALSE; |
4427 | } |
4428 | m->flags = cpu_to_le16(0); |
4429 | m->sequence_number = cpu_to_le16(i); |
4430 | } |
4431 | } |
4432 | /* |
4433 | * Create the 16 system files, adding the system information attribute |
4434 | * to each as well as marking them in use in the mft bitmap. |
4435 | */ |
4436 | for (i = 0; i < nr_sysfiles; i++) { |
4437 | le32 file_attrs; |
4438 | |
4439 | m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); |
4440 | if (i < 16 || i > 23) { |
4441 | m->mft_record_number = cpu_to_le32(i); |
4442 | m->flags |= MFT_RECORD_IN_USE; |
4443 | ntfs_bit_set(g_mft_bitmap, 0LL + i, 1); |
4444 | } |
4445 | file_attrs = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM; |
4446 | if (i == FILE_root) { |
4447 | file_attrs |= FILE_ATTR_ARCHIVE; |
4448 | if (opts.disable_indexing) |
4449 | file_attrs |= FILE_ATTR_NOT_CONTENT_INDEXED; |
4450 | if (opts.enable_compression) |
4451 | file_attrs |= FILE_ATTR_COMPRESSED; |
4452 | } |
4453 | /* setting specific security_id flag and */ |
4454 | /* file permissions for ntfs 3.x */ |
4455 | if (i == 0 || i == 1 || i == 2 || i == 6 || i == 8 || |
4456 | i == 10) { |
4457 | add_attr_std_info(m, file_attrs, |
4458 | cpu_to_le32(0x0100)); |
4459 | } else if (i == 9) { |
4460 | file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; |
4461 | add_attr_std_info(m, file_attrs, |
4462 | cpu_to_le32(0x0101)); |
4463 | } else if (i == 11) { |
4464 | add_attr_std_info(m, file_attrs, |
4465 | cpu_to_le32(0x0101)); |
4466 | } else if (i == 24 || i == 25 || i == 26) { |
4467 | file_attrs |= FILE_ATTR_ARCHIVE; |
4468 | file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; |
4469 | add_attr_std_info(m, file_attrs, |
4470 | cpu_to_le32(0x0101)); |
4471 | } else { |
4472 | add_attr_std_info(m, file_attrs, |
4473 | cpu_to_le32(0x00)); |
4474 | } |
4475 | } |
4476 | /* The root directory mft reference. */ |
4477 | root_ref = MK_LE_MREF(FILE_root, FILE_root); |
4478 | extend_ref = MK_LE_MREF(11,11); |
4479 | ntfs_log_verbose("Creating root directory (mft record 5)\n"); |
4480 | m = (MFT_RECORD*)(g_buf + 5 * g_vol->mft_record_size); |
4481 | m->flags |= MFT_RECORD_IS_DIRECTORY; |
4482 | m->link_count = cpu_to_le16(le16_to_cpu(m->link_count) + 1); |
4483 | err = add_attr_file_name(m, root_ref, 0LL, 0LL, |
4484 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | |
4485 | FILE_ATTR_I30_INDEX_PRESENT, 0, 0, ".", |
4486 | FILE_NAME_WIN32_AND_DOS); |
4487 | if (!err) { |
4488 | init_root_sd(&sd, &i); |
4489 | err = add_attr_sd(m, sd, i); |
4490 | } |
4491 | /* FIXME: This should be IGNORE_CASE */ |
4492 | if (!err) |
4493 | err = add_attr_index_root(m, "$I30", 4, CASE_SENSITIVE, |
4494 | AT_FILE_NAME, COLLATION_FILE_NAME, |
4495 | g_vol->indx_record_size); |
4496 | /* FIXME: This should be IGNORE_CASE */ |
4497 | if (!err) |
4498 | err = upgrade_to_large_index(m, "$I30", 4, CASE_SENSITIVE, |
4499 | &g_index_block); |
4500 | if (!err) { |
4501 | ntfs_attr_search_ctx *ctx; |
4502 | ATTR_RECORD *a; |
4503 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
4504 | if (!ctx) { |
4505 | ntfs_log_perror("Failed to allocate attribute search " |
4506 | "context"); |
4507 | return FALSE; |
4508 | } |
4509 | /* There is exactly one file name so this is ok. */ |
4510 | if (mkntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, |
4511 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
4512 | ntfs_attr_put_search_ctx(ctx); |
4513 | ntfs_log_error("BUG: $FILE_NAME attribute not found." |
4514 | "\n"); |
4515 | return FALSE; |
4516 | } |
4517 | a = ctx->attr; |
4518 | err = insert_file_link_in_dir_index(g_index_block, root_ref, |
4519 | (FILE_NAME_ATTR*)((char*)a + |
4520 | le16_to_cpu(a->value_offset)), |
4521 | le32_to_cpu(a->value_length)); |
4522 | ntfs_attr_put_search_ctx(ctx); |
4523 | } |
4524 | if (err) { |
4525 | ntfs_log_error("Couldn't create root directory: %s\n", |
4526 | strerror(-err)); |
4527 | return FALSE; |
4528 | } |
4529 | /* Add all other attributes, on a per-file basis for clarity. */ |
4530 | ntfs_log_verbose("Creating $MFT (mft record 0)\n"); |
4531 | m = (MFT_RECORD*)g_buf; |
4532 | err = add_attr_data_positioned(m, NULL, 0, CASE_SENSITIVE, |
4533 | const_cpu_to_le16(0), g_rl_mft, g_buf, g_mft_size); |
4534 | if (!err) |
4535 | err = create_hardlink(g_index_block, root_ref, m, |
4536 | MK_LE_MREF(FILE_MFT, 1), |
4537 | ((g_mft_size - 1) |
4538 | | (g_vol->cluster_size - 1)) + 1, |
4539 | g_mft_size, FILE_ATTR_HIDDEN | |
4540 | FILE_ATTR_SYSTEM, 0, 0, "$MFT", |
4541 | FILE_NAME_WIN32_AND_DOS); |
4542 | /* mft_bitmap is not modified in mkntfs; no need to sync it later. */ |
4543 | if (!err) |
4544 | err = add_attr_bitmap_positioned(m, NULL, 0, CASE_SENSITIVE, |
4545 | g_rl_mft_bmp, |
4546 | g_mft_bitmap, g_mft_bitmap_byte_size); |
4547 | if (err < 0) { |
4548 | ntfs_log_error("Couldn't create $MFT: %s\n", strerror(-err)); |
4549 | return FALSE; |
4550 | } |
4551 | ntfs_log_verbose("Creating $MFTMirr (mft record 1)\n"); |
4552 | m = (MFT_RECORD*)(g_buf + 1 * g_vol->mft_record_size); |
4553 | err = add_attr_data_positioned(m, NULL, 0, CASE_SENSITIVE, |
4554 | const_cpu_to_le16(0), g_rl_mftmirr, g_buf, |
4555 | g_rl_mftmirr[0].length * g_vol->cluster_size); |
4556 | if (!err) |
4557 | err = create_hardlink(g_index_block, root_ref, m, |
4558 | MK_LE_MREF(FILE_MFTMirr, FILE_MFTMirr), |
4559 | g_rl_mftmirr[0].length * g_vol->cluster_size, |
4560 | g_rl_mftmirr[0].length * g_vol->cluster_size, |
4561 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, |
4562 | "$MFTMirr", FILE_NAME_WIN32_AND_DOS); |
4563 | if (err < 0) { |
4564 | ntfs_log_error("Couldn't create $MFTMirr: %s\n", |
4565 | strerror(-err)); |
4566 | return FALSE; |
4567 | } |
4568 | ntfs_log_verbose("Creating $LogFile (mft record 2)\n"); |
4569 | m = (MFT_RECORD*)(g_buf + 2 * g_vol->mft_record_size); |
4570 | err = add_attr_data_positioned(m, NULL, 0, CASE_SENSITIVE, |
4571 | const_cpu_to_le16(0), g_rl_logfile, |
4572 | (const u8*)NULL, g_logfile_size); |
4573 | if (!err) |
4574 | err = create_hardlink(g_index_block, root_ref, m, |
4575 | MK_LE_MREF(FILE_LogFile, FILE_LogFile), |
4576 | g_logfile_size, g_logfile_size, |
4577 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, |
4578 | "$LogFile", FILE_NAME_WIN32_AND_DOS); |
4579 | if (err < 0) { |
4580 | ntfs_log_error("Couldn't create $LogFile: %s\n", |
4581 | strerror(-err)); |
4582 | return FALSE; |
4583 | } |
4584 | ntfs_log_verbose("Creating $AttrDef (mft record 4)\n"); |
4585 | m = (MFT_RECORD*)(g_buf + 4 * g_vol->mft_record_size); |
4586 | err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, const_cpu_to_le16(0), |
4587 | (u8*)g_vol->attrdef, g_vol->attrdef_len); |
4588 | if (!err) |
4589 | err = create_hardlink(g_index_block, root_ref, m, |
4590 | MK_LE_MREF(FILE_AttrDef, FILE_AttrDef), |
4591 | (g_vol->attrdef_len + g_vol->cluster_size - 1) & |
4592 | ~(g_vol->cluster_size - 1), g_vol->attrdef_len, |
4593 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, |
4594 | "$AttrDef", FILE_NAME_WIN32_AND_DOS); |
4595 | if (!err) { |
4596 | init_system_file_sd(FILE_AttrDef, &sd, &i); |
4597 | err = add_attr_sd(m, sd, i); |
4598 | } |
4599 | if (err < 0) { |
4600 | ntfs_log_error("Couldn't create $AttrDef: %s\n", |
4601 | strerror(-err)); |
4602 | return FALSE; |
4603 | } |
4604 | ntfs_log_verbose("Creating $Bitmap (mft record 6)\n"); |
4605 | m = (MFT_RECORD*)(g_buf + 6 * g_vol->mft_record_size); |
4606 | /* the data attribute of $Bitmap must be non-resident or otherwise */ |
4607 | /* windows 2003 will regard the volume as corrupt (ERSO) */ |
4608 | if (!err) |
4609 | err = insert_non_resident_attr_in_mft_record(m, |
4610 | AT_DATA, NULL, 0, CASE_SENSITIVE, |
4611 | const_cpu_to_le16(0), (const u8*)NULL, |
4612 | g_lcn_bitmap_byte_size, WRITE_BITMAP); |
4613 | |
4614 | |
4615 | if (!err) |
4616 | err = create_hardlink(g_index_block, root_ref, m, |
4617 | MK_LE_MREF(FILE_Bitmap, FILE_Bitmap), |
4618 | (g_lcn_bitmap_byte_size + g_vol->cluster_size - |
4619 | 1) & ~(g_vol->cluster_size - 1), |
4620 | g_lcn_bitmap_byte_size, |
4621 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, |
4622 | "$Bitmap", FILE_NAME_WIN32_AND_DOS); |
4623 | if (err < 0) { |
4624 | ntfs_log_error("Couldn't create $Bitmap: %s\n", strerror(-err)); |
4625 | return FALSE; |
4626 | } |
4627 | ntfs_log_verbose("Creating $Boot (mft record 7)\n"); |
4628 | m = (MFT_RECORD*)(g_buf + 7 * g_vol->mft_record_size); |
4629 | bs = ntfs_calloc(8192); |
4630 | if (!bs) |
4631 | return FALSE; |
4632 | memcpy(bs, boot_array, sizeof(boot_array)); |
4633 | /* |
4634 | * Create the boot sector in bs. Note, that bs is already zeroed |
4635 | * in the boot sector section and that it has the NTFS OEM id/magic |
4636 | * already inserted, so no need to worry about these things. |
4637 | */ |
4638 | bs->bpb.bytes_per_sector = cpu_to_le16(opts.sector_size); |
4639 | bs->bpb.sectors_per_cluster = (u8)(g_vol->cluster_size / |
4640 | opts.sector_size); |
4641 | bs->bpb.media_type = 0xf8; /* hard disk */ |
4642 | bs->bpb.sectors_per_track = cpu_to_le16(opts.sectors_per_track); |
4643 | ntfs_log_debug("sectors per track = %ld (0x%lx)\n", |
4644 | opts.sectors_per_track, opts.sectors_per_track); |
4645 | bs->bpb.heads = cpu_to_le16(opts.heads); |
4646 | ntfs_log_debug("heads = %ld (0x%lx)\n", opts.heads, opts.heads); |
4647 | bs->bpb.hidden_sectors = cpu_to_le32(opts.part_start_sect); |
4648 | ntfs_log_debug("hidden sectors = %llu (0x%llx)\n", opts.part_start_sect, |
4649 | opts.part_start_sect); |
4650 | bs->physical_drive = 0x80; /* boot from hard disk */ |
4651 | bs->extended_boot_signature = 0x80; /* everybody sets this, so we do */ |
4652 | bs->number_of_sectors = cpu_to_sle64(opts.num_sectors); |
4653 | bs->mft_lcn = cpu_to_sle64(g_mft_lcn); |
4654 | bs->mftmirr_lcn = cpu_to_sle64(g_mftmirr_lcn); |
4655 | if (g_vol->mft_record_size >= g_vol->cluster_size) { |
4656 | bs->clusters_per_mft_record = g_vol->mft_record_size / |
4657 | g_vol->cluster_size; |
4658 | } else { |
4659 | bs->clusters_per_mft_record = -(ffs(g_vol->mft_record_size) - |
4660 | 1); |
4661 | if ((u32)(1 << -bs->clusters_per_mft_record) != |
4662 | g_vol->mft_record_size) { |
4663 | free(bs); |
4664 | ntfs_log_error("BUG: calculated clusters_per_mft_record" |
4665 | " is wrong (= 0x%x)\n", |
4666 | bs->clusters_per_mft_record); |
4667 | return FALSE; |
4668 | } |
4669 | } |
4670 | ntfs_log_debug("clusters per mft record = %i (0x%x)\n", |
4671 | bs->clusters_per_mft_record, |
4672 | bs->clusters_per_mft_record); |
4673 | if (g_vol->indx_record_size >= g_vol->cluster_size) { |
4674 | bs->clusters_per_index_record = g_vol->indx_record_size / |
4675 | g_vol->cluster_size; |
4676 | } else { |
4677 | bs->clusters_per_index_record = -g_vol->indx_record_size_bits; |
4678 | if ((1 << -bs->clusters_per_index_record) != |
4679 | (s32)g_vol->indx_record_size) { |
4680 | free(bs); |
4681 | ntfs_log_error("BUG: calculated " |
4682 | "clusters_per_index_record is wrong " |
4683 | "(= 0x%x)\n", |
4684 | bs->clusters_per_index_record); |
4685 | return FALSE; |
4686 | } |
4687 | } |
4688 | ntfs_log_debug("clusters per index block = %i (0x%x)\n", |
4689 | bs->clusters_per_index_record, |
4690 | bs->clusters_per_index_record); |
4691 | /* Generate a 64-bit random number for the serial number. */ |
4692 | bs->volume_serial_number = cpu_to_le64(((u64)random() << 32) | |
4693 | ((u64)random() & 0xffffffff)); |
4694 | /* |
4695 | * Leave zero for now as NT4 leaves it zero, too. If want it later, see |
4696 | * ../libntfs/bootsect.c for how to calculate it. |
4697 | */ |
4698 | bs->checksum = cpu_to_le32(0); |
4699 | /* Make sure the bootsector is ok. */ |
4700 | if (!ntfs_boot_sector_is_ntfs(bs)) { |
4701 | free(bs); |
4702 | ntfs_log_error("FATAL: Generated boot sector is invalid!\n"); |
4703 | return FALSE; |
4704 | } |
4705 | err = add_attr_data_positioned(m, NULL, 0, CASE_SENSITIVE, |
4706 | const_cpu_to_le16(0), g_rl_boot, (u8*)bs, 8192); |
4707 | if (!err) |
4708 | err = create_hardlink(g_index_block, root_ref, m, |
4709 | MK_LE_MREF(FILE_Boot, FILE_Boot), |
4710 | (8192 + g_vol->cluster_size - 1) & |
4711 | ~(g_vol->cluster_size - 1), 8192, |
4712 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, |
4713 | "$Boot", FILE_NAME_WIN32_AND_DOS); |
4714 | if (!err) { |
4715 | init_system_file_sd(FILE_Boot, &sd, &i); |
4716 | err = add_attr_sd(m, sd, i); |
4717 | } |
4718 | if (err < 0) { |
4719 | free(bs); |
4720 | ntfs_log_error("Couldn't create $Boot: %s\n", strerror(-err)); |
4721 | return FALSE; |
4722 | } |
4723 | if (create_backup_boot_sector((u8*)bs)) { |
4724 | /* |
4725 | * Pre-2.6 kernels couldn't access the last sector if it was |
4726 | * odd and we failed to set the device block size to the sector |
4727 | * size, hence we schedule chkdsk to create it. |
4728 | */ |
4729 | volume_flags |= VOLUME_IS_DIRTY; |
4730 | } |
4731 | free(bs); |
4732 | /* |
4733 | * We cheat a little here and if the user has requested all times to be |
4734 | * set to zero then we set the GUID to zero as well. This options is |
4735 | * only used for development purposes so that should be fine. |
4736 | */ |
4737 | if (!opts.use_epoch_time) { |
4738 | /* Generate a GUID for the volume. */ |
4739 | #ifdef ENABLE_UUID |
4740 | uuid_generate((void*)&vol_guid); |
4741 | #else |
4742 | ntfs_generate_guid(&vol_guid); |
4743 | #endif |
4744 | } else |
4745 | memset(&vol_guid, 0, sizeof(vol_guid)); |
4746 | if (!create_file_volume(m, root_ref, volume_flags, &vol_guid)) |
4747 | return FALSE; |
4748 | ntfs_log_verbose("Creating $BadClus (mft record 8)\n"); |
4749 | m = (MFT_RECORD*)(g_buf + 8 * g_vol->mft_record_size); |
4750 | /* FIXME: This should be IGNORE_CASE */ |
4751 | /* Create a sparse named stream of size equal to the volume size. */ |
4752 | err = add_attr_data_positioned(m, "$Bad", 4, CASE_SENSITIVE, |
4753 | const_cpu_to_le16(0), g_rl_bad, NULL, |
4754 | g_vol->nr_clusters * g_vol->cluster_size); |
4755 | if (!err) { |
4756 | err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, |
4757 | const_cpu_to_le16(0), NULL, 0); |
4758 | } |
4759 | if (!err) { |
4760 | err = create_hardlink(g_index_block, root_ref, m, |
4761 | MK_LE_MREF(FILE_BadClus, FILE_BadClus), |
4762 | 0LL, 0LL, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, |
4763 | 0, 0, "$BadClus", FILE_NAME_WIN32_AND_DOS); |
4764 | } |
4765 | if (err < 0) { |
4766 | ntfs_log_error("Couldn't create $BadClus: %s\n", |
4767 | strerror(-err)); |
4768 | return FALSE; |
4769 | } |
4770 | /* create $Secure (NTFS 3.0+) */ |
4771 | ntfs_log_verbose("Creating $Secure (mft record 9)\n"); |
4772 | m = (MFT_RECORD*)(g_buf + 9 * g_vol->mft_record_size); |
4773 | m->flags |= MFT_RECORD_IS_VIEW_INDEX; |
4774 | if (!err) |
4775 | err = create_hardlink(g_index_block, root_ref, m, |
4776 | MK_LE_MREF(9, 9), 0LL, 0LL, |
4777 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | |
4778 | FILE_ATTR_VIEW_INDEX_PRESENT, 0, 0, |
4779 | "$Secure", FILE_NAME_WIN32_AND_DOS); |
4780 | buf_sds = NULL; |
4781 | buf_sds_first_size = 0; |
4782 | if (!err) { |
4783 | int buf_sds_size; |
4784 | |
4785 | buf_sds_first_size = 0xfc; |
4786 | buf_sds_size = 0x40000 + buf_sds_first_size; |
4787 | buf_sds = ntfs_calloc(buf_sds_size); |
4788 | if (!buf_sds) |
4789 | return FALSE; |
4790 | init_secure_sds(buf_sds); |
4791 | memcpy(buf_sds + 0x40000, buf_sds, buf_sds_first_size); |
4792 | err = add_attr_data(m, "$SDS", 4, CASE_SENSITIVE, |
4793 | const_cpu_to_le16(0), (u8*)buf_sds, |
4794 | buf_sds_size); |
4795 | } |
4796 | /* FIXME: This should be IGNORE_CASE */ |
4797 | if (!err) |
4798 | err = add_attr_index_root(m, "$SDH", 4, CASE_SENSITIVE, |
4799 | AT_UNUSED, COLLATION_NTOFS_SECURITY_HASH, |
4800 | g_vol->indx_record_size); |
4801 | /* FIXME: This should be IGNORE_CASE */ |
4802 | if (!err) |
4803 | err = add_attr_index_root(m, "$SII", 4, CASE_SENSITIVE, |
4804 | AT_UNUSED, COLLATION_NTOFS_ULONG, |
4805 | g_vol->indx_record_size); |
4806 | if (!err) |
4807 | err = initialize_secure(buf_sds, buf_sds_first_size, m); |
4808 | free(buf_sds); |
4809 | if (err < 0) { |
4810 | ntfs_log_error("Couldn't create $Secure: %s\n", |
4811 | strerror(-err)); |
4812 | return FALSE; |
4813 | } |
4814 | ntfs_log_verbose("Creating $UpCase (mft record 0xa)\n"); |
4815 | m = (MFT_RECORD*)(g_buf + 0xa * g_vol->mft_record_size); |
4816 | err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, const_cpu_to_le16(0), |
4817 | (u8*)g_vol->upcase, g_vol->upcase_len << 1); |
4818 | /* |
4819 | * The $Info only exists since Windows 8, but it apparently |
4820 | * does not disturb chkdsk from earlier versions. |
4821 | */ |
4822 | if (!err) |
4823 | err = add_attr_data(m, "$Info", 5, CASE_SENSITIVE, |
4824 | const_cpu_to_le16(0), |
4825 | (u8*)g_upcaseinfo, sizeof(struct UPCASEINFO)); |
4826 | if (!err) |
4827 | err = create_hardlink(g_index_block, root_ref, m, |
4828 | MK_LE_MREF(FILE_UpCase, FILE_UpCase), |
4829 | ((g_vol->upcase_len << 1) + |
4830 | g_vol->cluster_size - 1) & |
4831 | ~(g_vol->cluster_size - 1), |
4832 | g_vol->upcase_len << 1, |
4833 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, |
4834 | "$UpCase", FILE_NAME_WIN32_AND_DOS); |
4835 | if (err < 0) { |
4836 | ntfs_log_error("Couldn't create $UpCase: %s\n", strerror(-err)); |
4837 | return FALSE; |
4838 | } |
4839 | ntfs_log_verbose("Creating $Extend (mft record 11)\n"); |
4840 | /* |
4841 | * $Extend index must be resident. Otherwise, w2k3 will regard the |
4842 | * volume as corrupt. (ERSO) |
4843 | */ |
4844 | m = (MFT_RECORD*)(g_buf + 11 * g_vol->mft_record_size); |
4845 | m->flags |= MFT_RECORD_IS_DIRECTORY; |
4846 | if (!err) |
4847 | err = create_hardlink(g_index_block, root_ref, m, |
4848 | MK_LE_MREF(11, 11), 0LL, 0LL, |
4849 | FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | |
4850 | FILE_ATTR_I30_INDEX_PRESENT, 0, 0, |
4851 | "$Extend", FILE_NAME_WIN32_AND_DOS); |
4852 | /* FIXME: This should be IGNORE_CASE */ |
4853 | if (!err) |
4854 | err = add_attr_index_root(m, "$I30", 4, CASE_SENSITIVE, |
4855 | AT_FILE_NAME, COLLATION_FILE_NAME, |
4856 | g_vol->indx_record_size); |
4857 | if (err < 0) { |
4858 | ntfs_log_error("Couldn't create $Extend: %s\n", |
4859 | strerror(-err)); |
4860 | return FALSE; |
4861 | } |
4862 | /* NTFS reserved system files (mft records 0xc-0xf) */ |
4863 | for (i = 0xc; i < 0x10; i++) { |
4864 | ntfs_log_verbose("Creating system file (mft record 0x%x)\n", i); |
4865 | m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); |
4866 | err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, |
4867 | const_cpu_to_le16(0), NULL, 0); |
4868 | if (!err) { |
4869 | init_system_file_sd(i, &sd, &j); |
4870 | err = add_attr_sd(m, sd, j); |
4871 | } |
4872 | if (err < 0) { |
4873 | ntfs_log_error("Couldn't create system file %i (0x%x): " |
4874 | "%s\n", i, i, strerror(-err)); |
4875 | return FALSE; |
4876 | } |
4877 | } |
4878 | /* create systemfiles for ntfs volumes (3.1) */ |
4879 | /* starting with file 24 (ignoring file 16-23) */ |
4880 | extend_flags = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | |
4881 | FILE_ATTR_ARCHIVE | FILE_ATTR_VIEW_INDEX_PRESENT; |
4882 | ntfs_log_verbose("Creating $Quota (mft record 24)\n"); |
4883 | m = (MFT_RECORD*)(g_buf + 24 * g_vol->mft_record_size); |
4884 | m->flags |= MFT_RECORD_IS_4; |
4885 | m->flags |= MFT_RECORD_IS_VIEW_INDEX; |
4886 | if (!err) |
4887 | err = create_hardlink_res((MFT_RECORD*)(g_buf + |
4888 | 11 * g_vol->mft_record_size), extend_ref, m, |
4889 | MK_LE_MREF(24, 1), 0LL, 0LL, extend_flags, |
4890 | 0, 0, "$Quota", FILE_NAME_WIN32_AND_DOS); |
4891 | /* FIXME: This should be IGNORE_CASE */ |
4892 | if (!err) |
4893 | err = add_attr_index_root(m, "$Q", 2, CASE_SENSITIVE, AT_UNUSED, |
4894 | COLLATION_NTOFS_ULONG, g_vol->indx_record_size); |
4895 | /* FIXME: This should be IGNORE_CASE */ |
4896 | if (!err) |
4897 | err = add_attr_index_root(m, "$O", 2, CASE_SENSITIVE, AT_UNUSED, |
4898 | COLLATION_NTOFS_SID, g_vol->indx_record_size); |
4899 | if (!err) |
4900 | err = initialize_quota(m); |
4901 | if (err < 0) { |
4902 | ntfs_log_error("Couldn't create $Quota: %s\n", strerror(-err)); |
4903 | return FALSE; |
4904 | } |
4905 | ntfs_log_verbose("Creating $ObjId (mft record 25)\n"); |
4906 | m = (MFT_RECORD*)(g_buf + 25 * g_vol->mft_record_size); |
4907 | m->flags |= MFT_RECORD_IS_4; |
4908 | m->flags |= MFT_RECORD_IS_VIEW_INDEX; |
4909 | if (!err) |
4910 | err = create_hardlink_res((MFT_RECORD*)(g_buf + |
4911 | 11 * g_vol->mft_record_size), extend_ref, |
4912 | m, MK_LE_MREF(25, 1), 0LL, 0LL, |
4913 | extend_flags, 0, 0, "$ObjId", |
4914 | FILE_NAME_WIN32_AND_DOS); |
4915 | |
4916 | /* FIXME: This should be IGNORE_CASE */ |
4917 | if (!err) |
4918 | err = add_attr_index_root(m, "$O", 2, CASE_SENSITIVE, AT_UNUSED, |
4919 | COLLATION_NTOFS_ULONGS, |
4920 | g_vol->indx_record_size); |
4921 | if (!err && opts.with_uuid) |
4922 | err = index_obj_id_insert(m, &vol_guid, |
4923 | MK_LE_MREF(FILE_Volume, FILE_Volume)); |
4924 | if (err < 0) { |
4925 | ntfs_log_error("Couldn't create $ObjId: %s\n", |
4926 | strerror(-err)); |
4927 | return FALSE; |
4928 | } |
4929 | ntfs_log_verbose("Creating $Reparse (mft record 26)\n"); |
4930 | m = (MFT_RECORD*)(g_buf + 26 * g_vol->mft_record_size); |
4931 | m->flags |= MFT_RECORD_IS_4; |
4932 | m->flags |= MFT_RECORD_IS_VIEW_INDEX; |
4933 | if (!err) |
4934 | err = create_hardlink_res((MFT_RECORD*)(g_buf + |
4935 | 11 * g_vol->mft_record_size), |
4936 | extend_ref, m, MK_LE_MREF(26, 1), |
4937 | 0LL, 0LL, extend_flags, 0, 0, |
4938 | "$Reparse", FILE_NAME_WIN32_AND_DOS); |
4939 | /* FIXME: This should be IGNORE_CASE */ |
4940 | if (!err) |
4941 | err = add_attr_index_root(m, "$R", 2, CASE_SENSITIVE, AT_UNUSED, |
4942 | COLLATION_NTOFS_ULONGS, g_vol->indx_record_size); |
4943 | if (err < 0) { |
4944 | ntfs_log_error("Couldn't create $Reparse: %s\n", |
4945 | strerror(-err)); |
4946 | return FALSE; |
4947 | } |
4948 | return TRUE; |
4949 | } |
4950 | |
4951 | /** |
4952 | * mkntfs_redirect |
4953 | */ |
4954 | static int mkntfs_redirect(struct mkntfs_options *opts2) |
4955 | { |
4956 | u64 upcase_crc; |
4957 | int result = 1; |
4958 | ntfs_attr_search_ctx *ctx = NULL; |
4959 | long long lw, pos; |
4960 | ATTR_RECORD *a; |
4961 | MFT_RECORD *m; |
4962 | int i, err; |
4963 | |
4964 | if (!opts2) { |
4965 | ntfs_log_error("Internal error: invalid parameters to mkntfs_options.\n"); |
4966 | goto done; |
4967 | } |
4968 | /* Initialize the random number generator with the current time. */ |
4969 | srandom(le64_to_cpu(mkntfs_time())/10000000); |
4970 | /* Allocate and initialize ntfs_volume structure g_vol. */ |
4971 | g_vol = ntfs_volume_alloc(); |
4972 | if (!g_vol) { |
4973 | ntfs_log_perror("Could not create volume"); |
4974 | goto done; |
4975 | } |
4976 | /* Create NTFS 3.1 (Windows XP/Vista) volumes. */ |
4977 | g_vol->major_ver = 3; |
4978 | g_vol->minor_ver = 1; |
4979 | /* Transfer some options to the volume. */ |
4980 | if (opts.label) { |
4981 | g_vol->vol_name = strdup(opts.label); |
4982 | if (!g_vol->vol_name) { |
4983 | ntfs_log_perror("Could not copy volume name"); |
4984 | goto done; |
4985 | } |
4986 | } |
4987 | if (opts.cluster_size >= 0) |
4988 | g_vol->cluster_size = opts.cluster_size; |
4989 | /* Length is in unicode characters. */ |
4990 | g_vol->upcase_len = ntfs_upcase_build_default(&g_vol->upcase); |
4991 | /* Since Windows 8, there is a $Info stream in $UpCase */ |
4992 | g_upcaseinfo = |
4993 | (struct UPCASEINFO*)ntfs_malloc(sizeof(struct UPCASEINFO)); |
4994 | if (!g_vol->upcase_len || !g_upcaseinfo) |
4995 | goto done; |
4996 | /* If the CRC is correct, chkdsk does not warn about obsolete table */ |
4997 | crc64(0,(byte*)NULL,0); /* initialize the crc computation */ |
4998 | upcase_crc = crc64(0,(byte*)g_vol->upcase, |
4999 | g_vol->upcase_len * sizeof(ntfschar)); |
5000 | /* keep the version fields as zero */ |
5001 | memset(g_upcaseinfo, 0, sizeof(struct UPCASEINFO)); |
5002 | g_upcaseinfo->len = cpu_to_le32(sizeof(struct UPCASEINFO)); |
5003 | g_upcaseinfo->crc = cpu_to_le64(upcase_crc); |
5004 | g_vol->attrdef = ntfs_malloc(sizeof(attrdef_ntfs3x_array)); |
5005 | if (!g_vol->attrdef) { |
5006 | ntfs_log_perror("Could not create attrdef structure"); |
5007 | goto done; |
5008 | } |
5009 | memcpy(g_vol->attrdef, attrdef_ntfs3x_array, |
5010 | sizeof(attrdef_ntfs3x_array)); |
5011 | g_vol->attrdef_len = sizeof(attrdef_ntfs3x_array); |
5012 | /* Open the partition. */ |
5013 | if (!mkntfs_open_partition(g_vol)) |
5014 | goto done; |
5015 | /* |
5016 | * Decide on the sector size, cluster size, mft record and index record |
5017 | * sizes as well as the number of sectors/tracks/heads/size, etc. |
5018 | */ |
5019 | if (!mkntfs_override_vol_params(g_vol)) |
5020 | goto done; |
5021 | /* Initialize $Bitmap and $MFT/$BITMAP related stuff. */ |
5022 | if (!mkntfs_initialize_bitmaps()) |
5023 | goto done; |
5024 | /* Initialize MFT & set g_logfile_lcn. */ |
5025 | if (!mkntfs_initialize_rl_mft()) |
5026 | goto done; |
5027 | /* Initialize $LogFile. */ |
5028 | if (!mkntfs_initialize_rl_logfile()) |
5029 | goto done; |
5030 | /* Initialize $Boot. */ |
5031 | if (!mkntfs_initialize_rl_boot()) |
5032 | goto done; |
5033 | /* Allocate a buffer large enough to hold the mft. */ |
5034 | g_buf = ntfs_calloc(g_mft_size); |
5035 | if (!g_buf) |
5036 | goto done; |
5037 | /* Create runlist for $BadClus, $DATA named stream $Bad. */ |
5038 | if (!mkntfs_initialize_rl_bad()) |
5039 | goto done; |
5040 | /* If not quick format, fill the device with 0s. */ |
5041 | if (!opts.quick_format) { |
5042 | if (!mkntfs_fill_device_with_zeroes()) |
5043 | goto done; |
5044 | } |
5045 | /* Create NTFS volume structures. */ |
5046 | if (!mkntfs_create_root_structures()) |
5047 | goto done; |
5048 | /* |
5049 | * - Do not step onto bad blocks!!! |
5050 | * - If any bad blocks were specified or found, modify $BadClus, |
5051 | * allocating the bad clusters in $Bitmap. |
5052 | * - C&w bootsector backup bootsector (backup in last sector of the |
5053 | * partition). |
5054 | * - If NTFS 3.0+, c&w $Secure file and $Extend directory with the |
5055 | * corresponding special files in it, i.e. $ObjId, $Quota, $Reparse, |
5056 | * and $UsnJrnl. And others? Or not all necessary? |
5057 | * - RE: Populate $root with the system files (and $Extend directory if |
5058 | * applicable). Possibly should move this as far to the top as |
5059 | * possible and update during each subsequent c&w of each system file. |
5060 | */ |
5061 | ntfs_log_verbose("Syncing root directory index record.\n"); |
5062 | if (!mkntfs_sync_index_record(g_index_block, (MFT_RECORD*)(g_buf + 5 * |
5063 | g_vol->mft_record_size), NTFS_INDEX_I30, 4)) |
5064 | goto done; |
5065 | |
5066 | ntfs_log_verbose("Syncing $Bitmap.\n"); |
5067 | m = (MFT_RECORD*)(g_buf + 6 * g_vol->mft_record_size); |
5068 | |
5069 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
5070 | if (!ctx) { |
5071 | ntfs_log_perror("Could not create an attribute search context"); |
5072 | goto done; |
5073 | } |
5074 | |
5075 | if (mkntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, CASE_SENSITIVE, |
5076 | 0, NULL, 0, ctx)) { |
5077 | ntfs_log_error("BUG: $DATA attribute not found.\n"); |
5078 | goto done; |
5079 | } |
5080 | |
5081 | a = ctx->attr; |
5082 | if (a->non_resident) { |
5083 | runlist *rl = ntfs_mapping_pairs_decompress(g_vol, a, NULL); |
5084 | if (!rl) { |
5085 | ntfs_log_error("ntfs_mapping_pairs_decompress() failed\n"); |
5086 | goto done; |
5087 | } |
5088 | lw = ntfs_rlwrite(g_vol->dev, rl, (const u8*)NULL, |
5089 | g_lcn_bitmap_byte_size, NULL, WRITE_BITMAP); |
5090 | err = errno; |
5091 | free(rl); |
5092 | if (lw != g_lcn_bitmap_byte_size) { |
5093 | ntfs_log_error("ntfs_rlwrite: %s\n", lw == -1 ? |
5094 | strerror(err) : "unknown error"); |
5095 | goto done; |
5096 | } |
5097 | } else { |
5098 | /* Error : the bitmap must be created non resident */ |
5099 | ntfs_log_error("Error : the global bitmap is resident\n"); |
5100 | goto done; |
5101 | } |
5102 | |
5103 | /* |
5104 | * No need to sync $MFT/$BITMAP as that has never been modified since |
5105 | * its creation. |
5106 | */ |
5107 | ntfs_log_verbose("Syncing $MFT.\n"); |
5108 | pos = g_mft_lcn * g_vol->cluster_size; |
5109 | lw = 1; |
5110 | for (i = 0; i < g_mft_size / (s32)g_vol->mft_record_size; i++) { |
5111 | if (!opts.no_action) |
5112 | lw = ntfs_mst_pwrite(g_vol->dev, pos, 1, g_vol->mft_record_size, g_buf + i * g_vol->mft_record_size); |
5113 | if (lw != 1) { |
5114 | ntfs_log_error("ntfs_mst_pwrite: %s\n", lw == -1 ? |
5115 | strerror(errno) : "unknown error"); |
5116 | goto done; |
5117 | } |
5118 | pos += g_vol->mft_record_size; |
5119 | } |
5120 | ntfs_log_verbose("Updating $MFTMirr.\n"); |
5121 | pos = g_mftmirr_lcn * g_vol->cluster_size; |
5122 | lw = 1; |
5123 | for (i = 0; i < g_rl_mftmirr[0].length * g_vol->cluster_size / g_vol->mft_record_size; i++) { |
5124 | m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); |
5125 | /* |
5126 | * Decrement the usn by one, so it becomes the same as the one |
5127 | * in $MFT once it is mst protected. - This is as we need the |
5128 | * $MFTMirr to have the exact same byte by byte content as |
5129 | * $MFT, rather than just equivalent meaning content. |
5130 | */ |
5131 | if (ntfs_mft_usn_dec(m)) { |
5132 | ntfs_log_error("ntfs_mft_usn_dec"); |
5133 | goto done; |
5134 | } |
5135 | if (!opts.no_action) |
5136 | lw = ntfs_mst_pwrite(g_vol->dev, pos, 1, g_vol->mft_record_size, g_buf + i * g_vol->mft_record_size); |
5137 | if (lw != 1) { |
5138 | ntfs_log_error("ntfs_mst_pwrite: %s\n", lw == -1 ? |
5139 | strerror(errno) : "unknown error"); |
5140 | goto done; |
5141 | } |
5142 | pos += g_vol->mft_record_size; |
5143 | } |
5144 | ntfs_log_verbose("Syncing device.\n"); |
5145 | if (g_vol->dev->d_ops->sync(g_vol->dev)) { |
5146 | ntfs_log_error("Syncing device. FAILED"); |
5147 | goto done; |
5148 | } |
5149 | ntfs_log_quiet("mkntfs completed successfully. Have a nice day.\n"); |
5150 | result = 0; |
5151 | done: |
5152 | ntfs_attr_put_search_ctx(ctx); |
5153 | mkntfs_cleanup(); /* Device is unlocked and closed here */ |
5154 | return result; |
5155 | } |
5156 | |
5157 | |
5158 | /** |
5159 | * main - Begin here |
5160 | * |
5161 | * Start from here. |
5162 | * |
5163 | * Return: 0 Success, the program worked |
5164 | * 1 Error, something went wrong |
5165 | */ |
5166 | int main(int argc, char *argv[]) |
5167 | { |
5168 | int result = 1; |
5169 | |
5170 | ntfs_log_set_handler(ntfs_log_handler_outerr); |
5171 | utils_set_locale(); |
5172 | |
5173 | mkntfs_init_options(&opts); /* Set up the options */ |
5174 | |
5175 | if (!mkntfs_parse_options(argc, argv, &opts)) /* Read the command line options */ |
5176 | goto done; |
5177 | |
5178 | result = mkntfs_redirect(&opts); |
5179 | done: |
5180 | return result; |
5181 | } |
5182 |