Fix inverted usage of endian conversion macros.
[ntfs-3g.git] / ntfsprogs / ntfstruncate.c
blob9cd44c76a9fdfb877e7d18ca6c4bd22a724e3601
1 /**
2 * ntfstruncate - Part of the Linux-NTFS project.
4 * Copyright (c) 2002-2005 Anton Altaparmakov
6 * This utility will truncate a specified attribute belonging to a
7 * specified inode, i.e. file or directory, to a specified length.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (in the main directory of the Linux-NTFS source
21 * in the file COPYING); if not, write to the Free Software Foundation,
22 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_STDLIB_H
31 # include <stdlib.h>
32 #endif
33 #ifdef HAVE_STDIO_H
34 # include <stdio.h>
35 #endif
36 #ifdef HAVE_STDARG_H
37 # include <stdarg.h>
38 #endif
39 #ifdef HAVE_STRING_H
40 # include <string.h>
41 #endif
42 #ifdef HAVE_ERRNO_H
43 # include <errno.h>
44 #endif
45 #ifdef HAVE_TIME_H
46 #include <time.h>
47 #endif
48 #ifdef HAVE_GETOPT_H
49 # include <getopt.h>
50 #else
51 extern char *optarg;
52 extern int optind;
53 #endif
54 #ifdef HAVE_LIMITS_H
55 #include <limits.h>
56 #endif
57 #ifndef LLONG_MAX
58 # define LLONG_MAX 9223372036854775807LL
59 #endif
61 #include "types.h"
62 #include "attrib.h"
63 #include "inode.h"
64 #include "layout.h"
65 #include "volume.h"
66 #include "utils.h"
67 #include "attrdef.h"
68 /* #include "version.h" */
69 #include "logging.h"
71 const char *EXEC_NAME = "ntfstruncate";
73 /* Need these global so ntfstruncate_exit can access them. */
74 BOOL success = FALSE;
76 char *dev_name;
77 s64 inode;
78 u32 attr_type;
79 ntfschar *attr_name = NULL;
80 u32 attr_name_len;
81 s64 new_len;
83 ntfs_volume *vol;
84 ntfs_inode *ni;
85 ntfs_attr *na = NULL;
87 ATTR_DEF *attr_defs;
89 struct {
90 /* -h, print usage and exit. */
91 int no_action; /* -n, do not write to device, only display
92 what would be done. */
93 int quiet; /* -q, quiet execution. */
94 int verbose; /* -v, verbose execution, given twice, really
95 verbose execution (debug mode). */
96 int force; /* -f, force truncation. */
97 /* -V, print version and exit. */
98 } opts;
101 * err_exit - error output and terminate; ignores quiet (-q)
103 __attribute__((noreturn))
104 __attribute__((format(printf, 1, 2)))
105 static void err_exit(const char *fmt, ...)
107 va_list ap;
109 fprintf(stderr, "ERROR: ");
110 va_start(ap, fmt);
111 vfprintf(stderr, fmt, ap);
112 va_end(ap);
113 fprintf(stderr, "Aborting...\n");
114 exit(1);
118 * copyright - print copyright statements
120 static void copyright(void)
122 fprintf(stderr, "Copyright (c) 2002-2005 Anton Altaparmakov\n"
123 "Copyright (c) 2003 Richard Russon\n"
124 "Truncate a specified attribute of a specified "
125 "inode.\n");
129 * license - print license statement
131 static void license(void)
133 fprintf(stderr, "%s", ntfs_gpl);
137 * usage - print a list of the parameters to the program
139 __attribute__((noreturn))
140 static void usage(int ret)
142 copyright();
143 fprintf(stderr, "Usage: %s [options] device inode [attr-type "
144 "[attr-name]] new-length\n"
145 " If attr-type is not specified, 0x80 (i.e. $DATA) "
146 "is assumed.\n"
147 " If attr-name is not specified, an unnamed "
148 "attribute is assumed.\n"
149 " -n Do not write to disk\n"
150 " -f Force execution despite errors\n"
151 " -q Quiet execution\n"
152 " -v Verbose execution\n"
153 " -vv Very verbose execution\n"
154 " -V Display version information\n"
155 " -l Display licensing information\n"
156 " -h Display this help\n", EXEC_NAME);
157 fprintf(stderr, "%s%s", ntfs_bugs, ntfs_home);
158 exit(ret);
162 * parse_options
164 static void parse_options(int argc, char *argv[])
166 long long ll;
167 char *s, *s2;
168 int c;
170 if (argc && *argv)
171 EXEC_NAME = *argv;
172 fprintf(stderr, "%s v%s (libntfs-3g)\n", EXEC_NAME, VERSION);
173 while ((c = getopt(argc, argv, "fh?nqvVl")) != EOF)
174 switch (c) {
175 case 'f':
176 opts.force = 1;
177 break;
178 case 'n':
179 opts.no_action = 1;
180 break;
181 case 'q':
182 opts.quiet = 1;
183 ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
184 break;
185 case 'v':
186 opts.verbose++;
187 ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
188 break;
189 case 'V':
190 /* Version number already printed, so just exit. */
191 exit(0);
192 case 'l':
193 copyright();
194 license();
195 exit(0);
196 case 'h':
197 usage(0);
198 case '?':
199 default:
200 usage(1);
202 if (optind == argc)
203 usage(1);
205 if (opts.verbose > 1)
206 ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE |
207 NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_QUIET);
209 /* Get the device. */
210 dev_name = argv[optind++];
211 ntfs_log_verbose("device name = %s\n", dev_name);
213 if (optind == argc)
214 usage(1);
216 /* Get the inode. */
217 ll = strtoll(argv[optind++], &s, 0);
218 if (*s || !ll || (ll >= LLONG_MAX && errno == ERANGE))
219 err_exit("Invalid inode number: %s\n", argv[optind - 1]);
220 inode = ll;
221 ntfs_log_verbose("inode = %lli\n", (long long)inode);
223 if (optind == argc)
224 usage(1);
226 /* Get the attribute type, if specified. */
227 s = argv[optind++];
228 if (optind == argc) {
229 attr_type = AT_DATA;
230 attr_name = AT_UNNAMED;
231 attr_name_len = 0;
232 } else {
233 unsigned long ul;
235 ul = strtoul(s, &s2, 0);
236 if (*s2 || !ul || (ul >= ULONG_MAX && errno == ERANGE))
237 err_exit("Invalid attribute type %s: %s\n", s,
238 strerror(errno));
239 attr_type = ul;
241 /* Get the attribute name, if specified. */
242 s = argv[optind++];
243 if (optind != argc) {
244 /* Convert the string to little endian Unicode. */
245 attr_name_len = ntfs_mbstoucs(s, &attr_name);
246 if ((int)attr_name_len < 0)
247 err_exit("Invalid attribute name \"%s\": %s\n",
248 s, strerror(errno));
250 /* Keep hold of the original string. */
251 s2 = s;
253 s = argv[optind++];
254 if (optind != argc)
255 usage(1);
256 } else {
257 attr_name = AT_UNNAMED;
258 attr_name_len = 0;
261 ntfs_log_verbose("attribute type = 0x%x\n", (unsigned int)attr_type);
262 if (attr_name == AT_UNNAMED)
263 ntfs_log_verbose("attribute name = \"\" (UNNAMED)\n");
264 else
265 ntfs_log_verbose("attribute name = \"%s\" (length %u Unicode "
266 "characters)\n", s2,
267 (unsigned int)attr_name_len);
269 /* Get the new length. */
270 ll = strtoll(s, &s2, 0);
271 if (*s2 || ll < 0 || (ll >= LLONG_MAX && errno == ERANGE))
272 err_exit("Invalid new length: %s\n", s);
273 new_len = ll;
274 ntfs_log_verbose("new length = %lli\n", (long long)new_len);
278 * ucstos - convert unicode-character string to ASCII
279 * @dest: points to buffer to receive the converted string
280 * @src: points to string to convert
281 * @maxlen: size of @dest buffer in bytes
283 * Return the number of characters written to @dest, not including the
284 * terminating null byte. If a unicode character was encountered which could
285 * not be converted -1 is returned.
287 static int ucstos(char *dest, const ntfschar *src, int maxlen)
289 ntfschar u;
290 int i;
292 /* Need one byte for null terminator. */
293 maxlen--;
294 for (i = 0; i < maxlen; i++) {
295 u = le16_to_cpu(src[i]);
296 if (!u)
297 break;
298 if (u & 0xff00)
299 return -1;
300 dest[i] = u & 0xff;
302 dest[i] = 0;
303 return i;
307 * dump_resident_attr_val
309 static void dump_resident_attr_val(ATTR_TYPES type, char *val, u32 val_len)
311 const char *don_t_know = "Don't know what to do with this attribute "
312 "type yet.";
313 const char *skip = "Skipping display of $%s attribute value.\n";
314 const char *todo = "This is still work in progress.";
315 char *buf;
316 int i, j;
317 u32 u;
319 switch (type) {
320 case AT_STANDARD_INFORMATION:
321 // TODO
322 printf("%s\n", todo);
323 return;
324 case AT_ATTRIBUTE_LIST:
325 // TODO
326 printf("%s\n", todo);
327 return;
328 case AT_FILE_NAME:
329 // TODO
330 printf("%s\n", todo);
331 return;
332 case AT_OBJECT_ID:
333 // TODO
334 printf("%s\n", todo);
335 return;
336 case AT_SECURITY_DESCRIPTOR:
337 // TODO
338 printf("%s\n", todo);
339 return;
340 case AT_VOLUME_NAME:
341 printf("Volume name length = %u\n", (unsigned int)val_len);
342 if (val_len) {
343 buf = calloc(1, val_len);
344 if (!buf)
345 err_exit("Failed to allocate internal buffer: "
346 "%s\n", strerror(errno));
347 i = ucstos(buf, (ntfschar*)val, val_len);
348 if (i == -1)
349 printf("Volume name contains non-displayable "
350 "Unicode characters.\n");
351 printf("Volume name = %s\n", buf);
352 free(buf);
354 return;
355 case AT_VOLUME_INFORMATION:
356 #define VOL_INF(x) ((VOLUME_INFORMATION *)(x))
357 printf("NTFS version %i.%i\n", VOL_INF(val)->major_ver,
358 VOL_INF(val)->minor_ver);
359 i = VOL_INF(val)->flags;
360 #undef VOL_INF
361 printf("Volume flags = 0x%x: ", le16_to_cpu(i));
362 if (!i) {
363 printf("NONE\n");
364 return;
366 j = 0;
367 if (i & VOLUME_MODIFIED_BY_CHKDSK) {
368 j = 1;
369 printf("VOLUME_MODIFIED_BY_CHKDSK");
371 if (i & VOLUME_REPAIR_OBJECT_ID) {
372 if (j)
373 printf(" | ");
374 else
375 j = 0;
376 printf("VOLUME_REPAIR_OBJECT_ID");
378 if (i & VOLUME_DELETE_USN_UNDERWAY) {
379 if (j)
380 printf(" | ");
381 else
382 j = 0;
383 printf("VOLUME_DELETE_USN_UNDERWAY");
385 if (i & VOLUME_MOUNTED_ON_NT4) {
386 if (j)
387 printf(" | ");
388 else
389 j = 0;
390 printf("VOLUME_MOUNTED_ON_NT4");
392 if (i & VOLUME_UPGRADE_ON_MOUNT) {
393 if (j)
394 printf(" | ");
395 else
396 j = 0;
397 printf("VOLUME_UPGRADE_ON_MOUNT");
399 if (i & VOLUME_RESIZE_LOG_FILE) {
400 if (j)
401 printf(" | ");
402 else
403 j = 0;
404 printf("VOLUME_RESIZE_LOG_FILE");
406 if (i & VOLUME_IS_DIRTY) {
407 if (j)
408 printf(" | ");
409 else
410 j = 0;
411 printf("VOLUME_IS_DIRTY");
413 printf("\n");
414 return;
415 case AT_DATA:
416 printf(skip, "DATA");
417 return;
418 case AT_INDEX_ROOT:
419 // TODO
420 printf("%s\n", todo);
421 return;
422 case AT_INDEX_ALLOCATION:
423 // TODO
424 printf("%s\n", todo);
425 return;
426 case AT_BITMAP:
427 printf(skip, "BITMAP");
428 return;
429 case AT_REPARSE_POINT:
430 // TODO
431 printf("%s\n", todo);
432 return;
433 case AT_EA_INFORMATION:
434 // TODO
435 printf("%s\n", don_t_know);
436 return;
437 case AT_EA:
438 // TODO
439 printf("%s\n", don_t_know);
440 return;
441 case AT_LOGGED_UTILITY_STREAM:
442 // TODO
443 printf("%s\n", don_t_know);
444 return;
445 default:
446 u = le32_to_cpu(type);
447 printf("Cannot display unknown %s defined attribute type 0x%x"
448 ".\n", u >=
449 le32_to_cpu(AT_FIRST_USER_DEFINED_ATTRIBUTE) ?
450 "user" : "system", (unsigned int)u);
455 * dump_resident_attr
457 static void dump_resident_attr(ATTR_RECORD *a)
459 int i;
461 i = le32_to_cpu(a->value_length);
462 printf("Attribute value length = %u (0x%x)\n", i, i);
463 i = le16_to_cpu(a->value_offset);
464 printf("Attribute value offset = %u (0x%x)\n", i, i);
465 i = a->resident_flags;
466 printf("Resident flags = 0x%x: ", i);
467 if (!i)
468 printf("NONE\n");
469 else if (i & ~RESIDENT_ATTR_IS_INDEXED)
470 printf("UNKNOWN FLAG(S)\n");
471 else
472 printf("RESIDENT_ATTR_IS_INDEXED\n");
473 dump_resident_attr_val(a->type, (char*)a + le16_to_cpu(a->value_offset),
474 le32_to_cpu(a->value_length));
478 * dump_mapping_pairs_array
480 static void dump_mapping_pairs_array(char *b __attribute__((unused)),
481 unsigned int max_len __attribute__((unused)))
483 // TODO
484 return;
488 * dump_non_resident_attr
490 static void dump_non_resident_attr(ATTR_RECORD *a)
492 s64 l;
493 int i;
495 l = sle64_to_cpu(a->lowest_vcn);
496 printf("Lowest VCN = %lli (0x%llx)\n", (long long)l,
497 (unsigned long long)l);
498 l = sle64_to_cpu(a->highest_vcn);
499 printf("Highest VCN = %lli (0x%llx)\n", (long long)l,
500 (unsigned long long)l);
501 printf("Mapping pairs array offset = 0x%x\n",
502 le16_to_cpu(a->mapping_pairs_offset));
503 printf("Compression unit = 0x%x: %sCOMPRESSED\n", a->compression_unit,
504 a->compression_unit ? "" : "NOT ");
505 if (sle64_to_cpu(a->lowest_vcn))
506 printf("Attribute is not the first extent. The following "
507 "sizes are meaningless:\n");
508 l = sle64_to_cpu(a->allocated_size);
509 printf("Allocated size = %lli (0x%llx)\n", (long long)l,
510 (unsigned long long)l);
511 l = sle64_to_cpu(a->data_size);
512 printf("Data size = %lli (0x%llx)\n", (long long)l,
513 (unsigned long long)l);
514 l = sle64_to_cpu(a->initialized_size);
515 printf("Initialized size = %lli (0x%llx)\n", (long long)l,
516 (unsigned long long)l);
517 if (a->flags & ATTR_COMPRESSION_MASK) {
518 l = sle64_to_cpu(a->compressed_size);
519 printf("Compressed size = %lli (0x%llx)\n", (long long)l,
520 (unsigned long long)l);
522 i = le16_to_cpu(a->mapping_pairs_offset);
523 dump_mapping_pairs_array((char*)a + i, le32_to_cpu(a->length) - i);
527 * dump_attr_record
529 static void dump_attr_record(MFT_RECORD *m, ATTR_RECORD *a)
531 unsigned int u;
532 char s[0x200];
533 int i;
535 printf("-- Beginning dump of attribute record at offset 0x%x. --\n",
536 (unsigned)((u8*)a - (u8*)m));
537 if (a->type == AT_END) {
538 printf("Attribute type = 0x%x ($END)\n",
539 (unsigned int)le32_to_cpu(AT_END));
540 u = le32_to_cpu(a->length);
541 printf("Length of resident part = %u (0x%x)\n", u, u);
542 return;
544 u = le32_to_cpu(a->type);
545 for (i = 0; attr_defs[i].type; i++)
546 if (le32_to_cpu(attr_defs[i].type) >= u)
547 break;
548 if (attr_defs[i].type) {
549 // printf("type = 0x%x\n", le32_to_cpu(attr_defs[i].type));
550 // { char *p = (char*)attr_defs[i].name;
551 // printf("name = %c%c%c%c%c\n", *p, p[1], p[2], p[3], p[4]);
552 // }
553 if (ucstos(s, attr_defs[i].name, sizeof(s)) == -1) {
554 ntfs_log_error("Could not convert Unicode string to single "
555 "byte string in current locale.\n");
556 strncpy(s, "Error converting Unicode string",
557 sizeof(s));
559 } else
560 strncpy(s, "UNKNOWN_TYPE", sizeof(s));
561 printf("Attribute type = 0x%x (%s)\n", u, s);
562 u = le32_to_cpu(a->length);
563 printf("Length of resident part = %u (0x%x)\n", u, u);
564 printf("Attribute is %sresident\n", a->non_resident ? "non-" : "");
565 printf("Name length = %u unicode characters\n", a->name_length);
566 printf("Name offset = %u (0x%x)\n", le16_to_cpu(a->name_offset),
567 le16_to_cpu(a->name_offset));
568 u = a->flags;
569 if (a->name_length) {
570 if (ucstos(s, (ntfschar*)((char*)a +
571 le16_to_cpu(a->name_offset)),
572 min((int)sizeof(s),
573 a->name_length + 1)) == -1) {
574 ntfs_log_error("Could not convert Unicode string to single "
575 "byte string in current locale.\n");
576 strncpy(s, "Error converting Unicode string",
577 sizeof(s));
580 printf("Name = %s\n", s);
582 printf("Attribute flags = 0x%x: ", le16_to_cpu(u));
583 if (!u)
584 printf("NONE");
585 else {
586 int first = TRUE;
587 if (u & ATTR_COMPRESSION_MASK) {
588 if (u & ATTR_IS_COMPRESSED) {
589 printf("ATTR_IS_COMPRESSED");
590 first = FALSE;
592 if ((u & ATTR_COMPRESSION_MASK) & ~ATTR_IS_COMPRESSED) {
593 if (!first)
594 printf(" | ");
595 else
596 first = FALSE;
597 printf("ATTR_UNKNOWN_COMPRESSION");
600 if (u & ATTR_IS_ENCRYPTED) {
601 if (!first)
602 printf(" | ");
603 else
604 first = FALSE;
605 printf("ATTR_IS_ENCRYPTED");
607 if (u & ATTR_IS_SPARSE) {
608 if (!first)
609 printf(" | ");
610 else
611 first = FALSE;
612 printf("ATTR_IS_SPARSE");
615 printf("\n");
616 printf("Attribute instance = %u\n", le16_to_cpu(a->instance));
617 if (a->non_resident) {
618 dump_non_resident_attr(a);
619 } else {
620 dump_resident_attr(a);
625 * dump_mft_record
627 static void dump_mft_record(MFT_RECORD *m)
629 ATTR_RECORD *a;
630 unsigned int u;
631 MFT_REF r;
633 printf("-- Beginning dump of mft record. --\n");
634 u = le32_to_cpu(m->magic);
635 printf("Mft record signature (magic) = %c%c%c%c\n", u & 0xff,
636 u >> 8 & 0xff, u >> 16 & 0xff, u >> 24 & 0xff);
637 u = le16_to_cpu(m->usa_ofs);
638 printf("Update sequence array offset = %u (0x%x)\n", u, u);
639 printf("Update sequence array size = %u\n", le16_to_cpu(m->usa_count));
640 printf("$LogFile sequence number (lsn) = %llu\n",
641 (unsigned long long)sle64_to_cpu(m->lsn));
642 printf("Sequence number = %u\n", le16_to_cpu(m->sequence_number));
643 printf("Reference (hard link) count = %u\n",
644 le16_to_cpu(m->link_count));
645 u = le16_to_cpu(m->attrs_offset);
646 printf("First attribute offset = %u (0x%x)\n", u, u);
647 printf("Flags = %u: ", le16_to_cpu(m->flags));
648 if (m->flags & MFT_RECORD_IN_USE)
649 printf("MFT_RECORD_IN_USE");
650 else
651 printf("MFT_RECORD_NOT_IN_USE");
652 if (m->flags & MFT_RECORD_IS_DIRECTORY)
653 printf(" | MFT_RECORD_IS_DIRECTORY");
654 printf("\n");
655 u = le32_to_cpu(m->bytes_in_use);
656 printf("Bytes in use = %u (0x%x)\n", u, u);
657 u = le32_to_cpu(m->bytes_allocated);
658 printf("Bytes allocated = %u (0x%x)\n", u, u);
659 r = le64_to_cpu(m->base_mft_record);
660 printf("Base mft record reference:\n\tMft record number = %llu\n\t"
661 "Sequence number = %u\n",
662 (unsigned long long)MREF(r), MSEQNO(r));
663 printf("Next attribute instance = %u\n",
664 le16_to_cpu(m->next_attr_instance));
665 a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
666 printf("-- Beginning dump of attributes within mft record. --\n");
667 while ((char*)a < (char*)m + le32_to_cpu(m->bytes_in_use)) {
668 if (a->type == cpu_to_le32(attr_type))
669 dump_attr_record(m, a);
670 if (a->type == AT_END)
671 break;
672 a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
674 printf("-- End of attributes. --\n");
678 * ntfstruncate_exit
680 static void ntfstruncate_exit(void)
682 int err;
684 if (success)
685 return;
686 /* Close the attribute. */
687 if (na)
688 ntfs_attr_close(na);
689 /* Close the inode. */
690 if (ni && ntfs_inode_close(ni)) {
691 ntfs_log_perror("Warning: Failed to close inode %lli",
692 (long long)inode);
694 /* Unmount the volume. */
695 err = ntfs_umount(vol, 0);
696 if (err == -1)
697 ntfs_log_perror("Warning: Could not umount %s", dev_name);
698 /* Free the attribute name if it exists. */
699 ntfs_ucsfree(attr_name);
703 * main
705 int main(int argc, char **argv)
707 unsigned long mnt_flags, ul;
708 int err;
710 ntfs_log_set_handler(ntfs_log_handler_outerr);
712 /* Initialize opts to zero / required values. */
713 memset(&opts, 0, sizeof(opts));
716 * Setup a default $AttrDef. FIXME: Should be reading this from the
717 * volume itself, at ntfs_mount() time.
719 attr_defs = (ATTR_DEF*)&attrdef_ntfs3x_array;
721 /* Parse command line options. */
722 parse_options(argc, argv);
724 utils_set_locale();
726 /* Make sure the file system is not mounted. */
727 if (ntfs_check_if_mounted(dev_name, &mnt_flags))
728 ntfs_log_perror("Failed to determine whether %s is mounted",
729 dev_name);
730 else if (mnt_flags & NTFS_MF_MOUNTED) {
731 ntfs_log_error("%s is mounted.\n", dev_name);
732 if (!opts.force)
733 err_exit("Refusing to run!\n");
734 fprintf(stderr, "ntfstruncate forced anyway. Hope /etc/mtab "
735 "is incorrect.\n");
738 /* Mount the device. */
739 if (opts.no_action) {
740 ntfs_log_quiet("Running in READ-ONLY mode!\n");
741 ul = NTFS_MNT_RDONLY;
742 } else
743 ul = 0;
744 vol = ntfs_mount(dev_name, ul);
745 if (!vol)
746 err_exit("Failed to mount %s: %s\n", dev_name, strerror(errno));
748 /* Register our exit function which will unlock and close the device. */
749 err = atexit(&ntfstruncate_exit);
750 if (err == -1) {
751 ntfs_log_error("Could not set up exit() function because atexit() "
752 "failed: %s Aborting...\n", strerror(errno));
753 ntfstruncate_exit();
754 exit(1);
757 /* Open the specified inode. */
758 ni = ntfs_inode_open(vol, inode);
759 if (!ni)
760 err_exit("Failed to open inode %lli: %s\n", (long long)inode,
761 strerror(errno));
763 /* Open the specified attribute. */
764 na = ntfs_attr_open(ni, attr_type, attr_name, attr_name_len);
765 if (!na)
766 err_exit("Failed to open attribute 0x%x: %s\n",
767 (unsigned int)attr_type, strerror(errno));
769 if (!opts.quiet && opts.verbose > 1) {
770 ntfs_log_verbose("Dumping mft record before calling "
771 "ntfs_attr_truncate():\n");
772 dump_mft_record(ni->mrec);
775 /* Truncate the attribute. */
776 err = ntfs_attr_truncate(na, new_len);
777 if (err)
778 err_exit("Failed to truncate attribute 0x%x: %s\n",
779 (unsigned int)le32_to_cpu(attr_type), strerror(errno));
781 if (!opts.quiet && opts.verbose > 1) {
782 ntfs_log_verbose("Dumping mft record after calling "
783 "ntfs_attr_truncate():\n");
784 dump_mft_record(ni->mrec);
787 /* Close the attribute. */
788 ntfs_attr_close(na);
789 na = NULL;
791 /* Close the inode. */
792 err = ntfs_inode_close(ni);
793 if (err)
794 err_exit("Failed to close inode %lli: %s\n", (long long)inode,
795 strerror(errno));
797 /* Unmount the volume. */
798 err = ntfs_umount(vol, 0);
799 if (err == -1)
800 ntfs_log_perror("Warning: Failed to umount %s", dev_name);
802 /* Free the attribute name if it exists. */
803 ntfs_ucsfree(attr_name);
805 /* Finally, disable our ntfstruncate_exit() handler. */
806 success = TRUE;
808 ntfs_log_quiet("ntfstruncate completed successfully. Have a nice day.\n");
809 return 0;