"Fossies" - the Fresh Open Source Software Archive

Member "ntfsprogs-1.12.1/ntfsprogs/ntfstruncate.c" (7 Oct 2005, 21026 Bytes) of package /linux/misc/old/ntfsprogs-1.12.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ntfstruncate.c" see the Fossies "Dox" file reference documentation.

    1 /**
    2  * ntfstruncate - Part of the Linux-NTFS project.
    3  *
    4  * Copyright (c) 2002-2005 Anton Altaparmakov
    5  *
    6  * This utility will truncate a specified attribute belonging to a
    7  * specified inode, i.e. file or directory, to a specified length.
    8  *
    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.
   13  *
   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.
   18  *
   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
   23  */
   24 
   25 #include "config.h"
   26 
   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
   60 
   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 "version.h"
   68 
   69 extern const unsigned char attrdef_ntfs12_array[2400];
   70 
   71 const char *EXEC_NAME = "ntfstruncate";
   72 
   73 /* Need these global so ntfstruncate_exit can access them. */
   74 BOOL success = FALSE;
   75 
   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;
   82 
   83 ntfs_volume *vol;
   84 ntfs_inode *ni;
   85 ntfs_attr *na = NULL;
   86 
   87 ATTR_DEF *attr_defs;
   88 
   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;
   99 
  100 /**
  101  * mkDprintf - debugging output (-vv); overridden by quiet (-q)
  102  */
  103 static void mkDprintf(const char *fmt, ...)
  104         __attribute__((format(printf, 1, 2)));
  105 static void mkDprintf(const char *fmt, ...)
  106 {
  107     va_list ap;
  108 
  109     if (!opts.quiet && opts.verbose > 1) {
  110         printf("DEBUG: ");
  111         va_start(ap, fmt);
  112         vprintf(fmt, ap);
  113         va_end(ap);
  114     }
  115 }
  116 
  117 /**
  118  * Eprintf - error output; ignores quiet (-q)
  119  */
  120 int Eprintf(const char *fmt, ...)
  121 {
  122     va_list ap;
  123 
  124     fprintf(stderr, "ERROR: ");
  125     va_start(ap, fmt);
  126     vfprintf(stderr, fmt, ap);
  127     va_end(ap);
  128     return 0;
  129 }
  130 
  131 /* Generate code for Vprintf() function: Verbose output (-v). */
  132 GEN_PRINTF(Vprintf, stdout, &opts.verbose, TRUE)
  133 
  134 /* Generate code for Qprintf() function: Quietable output (if not -q). */
  135 GEN_PRINTF(Qprintf, stdout, &opts.quiet,   FALSE)
  136 
  137 /**
  138  * err_exit - error output and terminate; ignores quiet (-q)
  139  */
  140 static void err_exit(const char *fmt, ...)
  141         __attribute__((noreturn))
  142         __attribute__((format(printf, 1, 2)));
  143 static void err_exit(const char *fmt, ...)
  144 {
  145     va_list ap;
  146 
  147     fprintf(stderr, "ERROR: ");
  148     va_start(ap, fmt);
  149     vfprintf(stderr, fmt, ap);
  150     va_end(ap);
  151     fprintf(stderr, "Aborting...\n");
  152     exit(1);
  153 }
  154 
  155 /**
  156  * copyright - print copyright statements
  157  */
  158 static void copyright(void)
  159 {
  160     fprintf(stderr, "Copyright (c) 2002-2005 Anton Altaparmakov\n"
  161             "Copyright (c) 2003 Richard Russon\n"
  162             "Truncate a specified attribute of a specified "
  163             "inode.\n");
  164 }
  165 
  166 /**
  167  * license - print license statement
  168  */
  169 static void license(void)
  170 {
  171     fprintf(stderr, "%s", ntfs_gpl);
  172 }
  173 
  174 /**
  175  * usage - print a list of the parameters to the program
  176  */
  177 void usage(void) __attribute__ ((noreturn));
  178 void usage (void)
  179 {
  180     copyright();
  181     fprintf(stderr, "Usage: %s [options] device inode [attr-type "
  182             "[attr-name]] new-length\n"
  183             "    If attr-type is not specified, 0x80 (i.e. $DATA) "
  184             "is assumed.\n"
  185             "    If attr-name is not specified, an unnamed "
  186             "attribute is assumed.\n"
  187             "    -n    Do not write to disk\n"
  188             "    -f    Force execution despite errors\n"
  189             "    -q    Quiet execution\n"
  190             "    -v    Verbose execution\n"
  191             "    -vv   Very verbose execution\n"
  192             "    -V    Display version information\n"
  193             "    -l    Display licensing information\n"
  194             "    -h    Display this help\n", EXEC_NAME);
  195     fprintf(stderr, "%s%s", ntfs_bugs, ntfs_home);
  196     exit(1);
  197 }
  198 
  199 /**
  200  * parse_options
  201  */
  202 static void parse_options(int argc, char *argv[])
  203 {
  204     long long ll;
  205     char *s, *s2;
  206     int c;
  207 
  208     if (argc && *argv)
  209         EXEC_NAME = *argv;
  210     fprintf(stderr, "%s v%s (libntfs %s)\n", EXEC_NAME, VERSION,
  211             ntfs_libntfs_version());
  212     while ((c = getopt(argc, argv, "fh?nqvVl")) != EOF)
  213         switch (c) {
  214         case 'f':
  215             opts.force = 1;
  216             break;
  217         case 'n':
  218             opts.no_action = 1;
  219             break;
  220         case 'q':
  221             opts.quiet = 1;
  222             break;
  223         case 'v':
  224             opts.verbose++;
  225             break;
  226         case 'V':
  227             /* Version number already printed, so just exit. */
  228             exit(0);
  229         case 'l':
  230             copyright();
  231             license();
  232             exit(0);
  233         case 'h':
  234         case '?':
  235         default:
  236             usage();
  237         }
  238     if (optind == argc)
  239         usage();
  240 
  241     /* Get the device. */
  242     dev_name = argv[optind++];
  243     mkDprintf("device name = %s\n", dev_name);
  244 
  245     if (optind == argc)
  246         usage();
  247 
  248     /* Get the inode. */
  249     ll = strtoll(argv[optind++], &s, 0);
  250     if (*s || !ll || (ll >= LLONG_MAX && errno == ERANGE))
  251         err_exit("Invalid inode number: %s\n", argv[optind - 1]);
  252     inode = ll;
  253     mkDprintf("inode = %lli\n", (long long)inode);
  254 
  255     if (optind == argc)
  256         usage();
  257 
  258     /* Get the attribute type, if specified. */
  259     s = argv[optind++];
  260     if (optind == argc) {
  261         attr_type = AT_DATA;
  262         attr_name = AT_UNNAMED;
  263         attr_name_len = 0;
  264     } else {
  265         unsigned long ul;
  266 
  267         ul = strtoul(s, &s2, 0);
  268         if (*s2 || !ul || (ul >= ULONG_MAX && errno == ERANGE))
  269             err_exit("Invalid attribute type %s: %s\n", s,
  270                     strerror(errno));
  271         attr_type = ul;
  272 
  273         /* Get the attribute name, if specified. */
  274         s = argv[optind++];
  275         if (optind != argc) {
  276             /* Convert the string to little endian Unicode. */
  277             attr_name_len = ntfs_mbstoucs(s, &attr_name, 0);
  278             if ((int)attr_name_len < 0)
  279                 err_exit("Invalid attribute name \"%s\": %s\n",
  280                         s, strerror(errno));
  281 
  282             /* Keep hold of the original string. */
  283             s2 = s;
  284 
  285             s = argv[optind++];
  286             if (optind != argc)
  287                 usage();
  288         } else {
  289             attr_name = AT_UNNAMED;
  290             attr_name_len = 0;
  291         }
  292     }
  293     mkDprintf("attribute type = 0x%x\n", (unsigned int)attr_type);
  294     if (attr_name == AT_UNNAMED)
  295         mkDprintf("attribute name = \"\" (UNNAMED)\n");
  296     else
  297         mkDprintf("attribute name = \"%s\" (length %u Unicode "
  298                 "characters)\n", s2,
  299                 (unsigned int)attr_name_len);
  300 
  301     /* Get the new length. */
  302     ll = strtoll(s, &s2, 0);
  303     if (*s2 || ll < 0 || (ll >= LLONG_MAX && errno == ERANGE))
  304         err_exit("Invalid new length: %s\n", s);
  305     new_len = ll;
  306     mkDprintf("new length = %lli\n", new_len);
  307 }
  308 
  309 /**
  310  * ucstos - convert unicode-character string to ASCII
  311  * @dest:   points to buffer to receive the converted string
  312  * @src:    points to string to convert
  313  * @maxlen: size of @dest buffer in bytes
  314  *
  315  * Return the number of characters written to @dest, not including the
  316  * terminating null byte. If a unicode character was encountered which could
  317  * not be converted -1 is returned.
  318  */
  319 static int ucstos(char *dest, const ntfschar *src, int maxlen)
  320 {
  321     ntfschar u;
  322     int i;
  323 
  324     /* Need one byte for null terminator. */
  325     maxlen--;
  326     for (i = 0; i < maxlen; i++) {
  327         u = le16_to_cpu(src[i]);
  328         if (!u)
  329             break;
  330         if (u & 0xff00)
  331             return -1;
  332         dest[i] = u & 0xff;
  333     }
  334     dest[i] = 0;
  335     return i;
  336 }
  337 
  338 /**
  339  * dump_resident_attr_val
  340  */
  341 static void dump_resident_attr_val(ATTR_TYPES type, char *val, u32 val_len)
  342 {
  343     const char *don_t_know = "Don't know what to do with this attribute "
  344             "type yet.";
  345     const char *skip = "Skipping display of $%s attribute value.\n";
  346     const char *todo = "This is still work in progress.";
  347     char *buf;
  348     int i, j;
  349     u32 u;
  350 
  351     switch (type) {
  352     case AT_STANDARD_INFORMATION:
  353         // TODO
  354         printf("%s\n", todo);
  355         return;
  356     case AT_ATTRIBUTE_LIST:
  357         // TODO
  358         printf("%s\n", todo);
  359         return;
  360     case AT_FILE_NAME:
  361         // TODO
  362         printf("%s\n", todo);
  363         return;
  364     case AT_OBJECT_ID:
  365         // TODO
  366         printf("%s\n", todo);
  367         return;
  368     case AT_SECURITY_DESCRIPTOR:
  369         // TODO
  370         printf("%s\n", todo);
  371         return;
  372     case AT_VOLUME_NAME:
  373         printf("Volume name length = %u\n", (unsigned int)val_len);
  374         if (val_len) {
  375             buf = calloc(1, val_len);
  376             if (!buf)
  377                 err_exit("Failed to allocate internal buffer: "
  378                         "%s\n", strerror(errno));
  379             i = ucstos(buf, (ntfschar*)val, val_len);
  380             if (i == -1)
  381                 printf("Volume name contains non-displayable "
  382                         "Unicode characters.\n");
  383             printf("Volume name = %s\n", buf);
  384             free(buf);
  385         }
  386         return;
  387     case AT_VOLUME_INFORMATION:
  388 #define VOL_INF(x) ((VOLUME_INFORMATION *)(x))
  389         printf("NTFS version %i.%i\n", VOL_INF(val)->major_ver,
  390                 VOL_INF(val)->minor_ver);
  391         i = VOL_INF(val)->flags;
  392 #undef VOL_INF
  393         printf("Volume flags = 0x%x: ", i);
  394         if (!i) {
  395             printf("NONE\n");
  396             return;
  397         }
  398         j = 0;
  399         if (i & VOLUME_MODIFIED_BY_CHKDSK) {
  400             j = 1;
  401             printf("VOLUME_MODIFIED_BY_CHKDSK");
  402         }
  403         if (i & VOLUME_REPAIR_OBJECT_ID) {
  404             if (j)
  405                 printf(" | ");
  406             else
  407                 j = 0;
  408             printf("VOLUME_REPAIR_OBJECT_ID");
  409         }
  410         if (i & VOLUME_DELETE_USN_UNDERWAY) {
  411             if (j)
  412                 printf(" | ");
  413             else
  414                 j = 0;
  415             printf("VOLUME_DELETE_USN_UNDERWAY");
  416         }
  417         if (i & VOLUME_MOUNTED_ON_NT4) {
  418             if (j)
  419                 printf(" | ");
  420             else
  421                 j = 0;
  422             printf("VOLUME_MOUNTED_ON_NT4");
  423         }
  424         if (i & VOLUME_UPGRADE_ON_MOUNT) {
  425             if (j)
  426                 printf(" | ");
  427             else
  428                 j = 0;
  429             printf("VOLUME_UPGRADE_ON_MOUNT");
  430         }
  431         if (i & VOLUME_RESIZE_LOG_FILE) {
  432             if (j)
  433                 printf(" | ");
  434             else
  435                 j = 0;
  436             printf("VOLUME_RESIZE_LOG_FILE");
  437         }
  438         if (i & VOLUME_IS_DIRTY) {
  439             if (j)
  440                 printf(" | ");
  441             else
  442                 j = 0;
  443             printf("VOLUME_IS_DIRTY");
  444         }
  445         printf("\n");
  446         return;
  447     case AT_DATA:
  448         printf(skip, "DATA");
  449         return;
  450     case AT_INDEX_ROOT:
  451         // TODO
  452         printf("%s\n", todo);
  453         return;
  454     case AT_INDEX_ALLOCATION:
  455         // TODO
  456         printf("%s\n", todo);
  457         return;
  458     case AT_BITMAP:
  459         printf(skip, "BITMAP");
  460         return;
  461     case AT_REPARSE_POINT:
  462         // TODO
  463         printf("%s\n", todo);
  464         return;
  465     case AT_EA_INFORMATION:
  466         // TODO
  467         printf("%s\n", don_t_know);
  468         return;
  469     case AT_EA:
  470         // TODO
  471         printf("%s\n", don_t_know);
  472         return;
  473     case AT_LOGGED_UTILITY_STREAM:
  474         // TODO
  475         printf("%s\n", don_t_know);
  476         return;
  477     default:
  478         u = le32_to_cpu(type);
  479         printf("Cannot display unknown %s defined attribute type 0x%x"
  480                 ".\n", u >=
  481                 le32_to_cpu(AT_FIRST_USER_DEFINED_ATTRIBUTE) ?
  482                 "user" : "system", (unsigned int)u);
  483     }
  484 }
  485 
  486 /**
  487  * dump_resident_attr
  488  */
  489 static void dump_resident_attr(ATTR_RECORD *a)
  490 {
  491     int i;
  492 
  493     i = le32_to_cpu(a->value_length);
  494     printf("Attribute value length = %u (0x%x)\n", i, i);
  495     i = le16_to_cpu(a->value_offset);
  496     printf("Attribute value offset = %u (0x%x)\n", i, i);
  497     i = a->resident_flags;
  498     printf("Resident flags = 0x%x: ", i);
  499     if (!i)
  500         printf("NONE\n");
  501     else if (i & ~RESIDENT_ATTR_IS_INDEXED)
  502         printf("UNKNOWN FLAG(S)\n");
  503     else
  504         printf("RESIDENT_ATTR_IS_INDEXED\n");
  505     dump_resident_attr_val(a->type, (char*)a + le16_to_cpu(a->value_offset),
  506             le32_to_cpu(a->value_length));
  507 }
  508 
  509 /**
  510  * dump_mapping_pairs_array
  511  */
  512 static void dump_mapping_pairs_array(char *b __attribute__((unused)),
  513     unsigned int max_len __attribute__((unused)))
  514 {
  515     // TODO
  516     return;
  517 }
  518 
  519 /**
  520  * dump_non_resident_attr
  521  */
  522 static void dump_non_resident_attr(ATTR_RECORD *a)
  523 {
  524     s64 l;
  525     int i;
  526 
  527     l = sle64_to_cpu(a->lowest_vcn);
  528     printf("Lowest VCN = %lli (0x%llx)\n", (long long)l,
  529             (unsigned long long)l);
  530     l = sle64_to_cpu(a->highest_vcn);
  531     printf("Highest VCN = %lli (0x%llx)\n", (long long)l,
  532             (unsigned long long)l);
  533     printf("Mapping pairs array offset = 0x%x\n",
  534             le16_to_cpu(a->mapping_pairs_offset));
  535     printf("Compression unit = 0x%x: %sCOMPRESSED\n", a->compression_unit,
  536             a->compression_unit ? "" : "NOT ");
  537     if (sle64_to_cpu(a->lowest_vcn))
  538         printf("Attribute is not the first extent. The following "
  539                 "sizes are meaningless:\n");
  540     l = sle64_to_cpu(a->allocated_size);
  541     printf("Allocated size = %lli (0x%llx)\n", (long long)l,
  542             (unsigned long long)l);
  543     l = sle64_to_cpu(a->data_size);
  544     printf("Data size = %lli (0x%llx)\n", (long long)l,
  545             (unsigned long long)l);
  546     l = sle64_to_cpu(a->initialized_size);
  547     printf("Initialized size = %lli (0x%llx)\n", (long long)l,
  548             (unsigned long long)l);
  549     if (a->flags & ATTR_COMPRESSION_MASK) {
  550         l = sle64_to_cpu(a->compressed_size);
  551         printf("Compressed size = %lli (0x%llx)\n", (long long)l,
  552                 (unsigned long long)l);
  553     }
  554     i = le16_to_cpu(a->mapping_pairs_offset);
  555     dump_mapping_pairs_array((char*)a + i, le32_to_cpu(a->length) - i);
  556 }
  557 
  558 /**
  559  * dump_attr_record
  560  */
  561 static void dump_attr_record(MFT_RECORD *m, ATTR_RECORD *a)
  562 {
  563     unsigned int u;
  564     char s[0x200];
  565     int i;
  566 
  567     printf("-- Beginning dump of attribute record at offset 0x%x. --\n",
  568             (unsigned)((u8*)a - (u8*)m));
  569     if (a->type == AT_END) {
  570         printf("Attribute type = 0x%x ($END)\n",
  571                 (unsigned int)le32_to_cpu(AT_END));
  572         u = le32_to_cpu(a->length);
  573         printf("Length of resident part = %u (0x%x)\n", u, u);
  574         return;
  575     }
  576     u = le32_to_cpu(a->type);
  577     for (i = 0; attr_defs[i].type; i++)
  578         if (le32_to_cpu(attr_defs[i].type) >= u)
  579             break;
  580     if (attr_defs[i].type) {
  581 //      printf("type = 0x%x\n", le32_to_cpu(attr_defs[i].type));
  582 //      { char *p = (char*)attr_defs[i].name;
  583 //      printf("name = %c%c%c%c%c\n", *p, p[1], p[2], p[3], p[4]);
  584 //      }
  585         if (ucstos(s, attr_defs[i].name, sizeof(s)) == -1) {
  586             Eprintf("Could not convert Unicode string to single "
  587                 "byte string in current locale.\n");
  588             strncpy(s, "Error converting Unicode string",
  589                     sizeof(s));
  590         }
  591     } else
  592         strncpy(s, "UNKNOWN_TYPE", sizeof(s));
  593     printf("Attribute type = 0x%x (%s)\n", u, s);
  594     u = le32_to_cpu(a->length);
  595     printf("Length of resident part = %u (0x%x)\n", u, u);
  596     printf("Attribute is %sresident\n", a->non_resident ? "non-" : "");
  597     printf("Name length = %u unicode characters\n", a->name_length);
  598     printf("Name offset = %u (0x%x)\n", cpu_to_le16(a->name_offset),
  599             cpu_to_le16(a->name_offset));
  600     u = a->flags;
  601     if (a->name_length) {
  602         if (ucstos(s, (ntfschar*)((char*)a +
  603                 cpu_to_le16(a->name_offset)),
  604                 min((int)sizeof(s),
  605                         a->name_length + 1)) == -1) {
  606             Eprintf("Could not convert Unicode string to single "
  607                 "byte string in current locale.\n");
  608             strncpy(s, "Error converting Unicode string",
  609                     sizeof(s));
  610 
  611         }
  612         printf("Name = %s\n", s);
  613     }
  614     printf("Attribute flags = 0x%x: ", le16_to_cpu(u));
  615     if (!u)
  616         printf("NONE");
  617     else {
  618         int first = TRUE;
  619         if (u & ATTR_COMPRESSION_MASK) {
  620             if (u & ATTR_IS_COMPRESSED) {
  621                 printf("ATTR_IS_COMPRESSED");
  622                 first = FALSE;
  623             }
  624             if ((u & ATTR_COMPRESSION_MASK) & ~ATTR_IS_COMPRESSED) {
  625                 if (!first)
  626                     printf(" | ");
  627                 else
  628                     first = FALSE;
  629                 printf("ATTR_UNKNOWN_COMPRESSION");
  630             }
  631         }
  632         if (u & ATTR_IS_ENCRYPTED) {
  633             if (!first)
  634                 printf(" | ");
  635             else
  636                 first = FALSE;
  637             printf("ATTR_IS_ENCRYPTED");
  638         }
  639         if (u & ATTR_IS_SPARSE) {
  640             if (!first)
  641                 printf(" | ");
  642             else
  643                 first = FALSE;
  644             printf("ATTR_IS_SPARSE");
  645         }
  646     }
  647     printf("\n");
  648     printf("Attribute instance = %u\n", le16_to_cpu(a->instance));
  649     if (a->non_resident) {
  650         dump_non_resident_attr(a);
  651     } else {
  652         dump_resident_attr(a);
  653     }
  654 }
  655 
  656 /**
  657  * dump_mft_record
  658  */
  659 static void dump_mft_record(MFT_RECORD *m)
  660 {
  661     ATTR_RECORD *a;
  662     unsigned int u;
  663     MFT_REF r;
  664 
  665     printf("-- Beginning dump of mft record. --\n");
  666     u = le32_to_cpu(m->magic);
  667     printf("Mft record signature (magic) = %c%c%c%c\n", u & 0xff,
  668             u >> 8 & 0xff, u >> 16 & 0xff, u >> 24 & 0xff);
  669     u = le16_to_cpu(m->usa_ofs);
  670     printf("Update sequence array offset = %u (0x%x)\n", u, u);
  671     printf("Update sequence array size = %u\n", le16_to_cpu(m->usa_count));
  672     printf("$LogFile sequence number (lsn) = %llu\n",
  673             (unsigned long long)le64_to_cpu(m->lsn));
  674     printf("Sequence number = %u\n", le16_to_cpu(m->sequence_number));
  675     printf("Reference (hard link) count = %u\n",
  676                         le16_to_cpu(m->link_count));
  677     u = le16_to_cpu(m->attrs_offset);
  678     printf("First attribute offset = %u (0x%x)\n", u, u);
  679     printf("Flags = %u: ", le16_to_cpu(m->flags));
  680     if (m->flags & MFT_RECORD_IN_USE)
  681         printf("MFT_RECORD_IN_USE");
  682     else
  683         printf("MFT_RECORD_NOT_IN_USE");
  684     if (m->flags & MFT_RECORD_IS_DIRECTORY)
  685         printf(" | MFT_RECORD_IS_DIRECTORY");
  686     printf("\n");
  687     u = le32_to_cpu(m->bytes_in_use);
  688     printf("Bytes in use = %u (0x%x)\n", u, u);
  689     u = le32_to_cpu(m->bytes_allocated);
  690     printf("Bytes allocated = %u (0x%x)\n", u, u);
  691     r = le64_to_cpu(m->base_mft_record);
  692     printf("Base mft record reference:\n\tMft record number = %llu\n\t"
  693             "Sequence number = %u\n",
  694             (unsigned long long)MREF(r), MSEQNO(r));
  695     printf("Next attribute instance = %u\n",
  696             le16_to_cpu(m->next_attr_instance));
  697     a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
  698     printf("-- Beginning dump of attributes within mft record. --\n");
  699     while ((char*)a < (char*)m + le32_to_cpu(m->bytes_in_use)) {
  700         if (a->type == cpu_to_le32(attr_type))
  701             dump_attr_record(m, a);
  702         if (a->type == AT_END)
  703             break;
  704         a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
  705     };
  706     printf("-- End of attributes. --\n");
  707 }
  708 
  709 /**
  710  * ntfstruncate_exit
  711  */
  712 static void ntfstruncate_exit(void)
  713 {
  714     int err;
  715 
  716     if (success)
  717         return;
  718     /* Close the attribute. */
  719     if (na)
  720         ntfs_attr_close(na);
  721     /* Close the inode. */
  722     if (ni && ntfs_inode_close(ni)) {
  723         fprintf(stderr, "Warning: Failed to close inode %lli: %s\n",
  724                 (long long)inode, strerror(errno));
  725     }
  726     /* Unmount the volume. */
  727     err = ntfs_umount(vol, 0);
  728     if (err == -1)
  729         fprintf(stderr, "Warning: Could not umount %s: %s\n", dev_name,
  730                 strerror(errno));
  731     /* Free the attribute name if it exists. */
  732     if (attr_name && attr_name != AT_UNNAMED)
  733         free(attr_name);
  734 }
  735 
  736 /**
  737  * main
  738  */
  739 int main(int argc, char **argv)
  740 {
  741     unsigned long mnt_flags, ul;
  742     int err;
  743 
  744     /* Initialize opts to zero / required values. */
  745     memset(&opts, 0, sizeof(opts));
  746 
  747     /*
  748      * Setup a default $AttrDef. FIXME: Should be reading this from the
  749      * volume itself, at ntfs_mount() time.
  750      */
  751     attr_defs = (ATTR_DEF*)&attrdef_ntfs12_array;
  752 
  753     /* Parse command line options. */
  754     parse_options(argc, argv);
  755 
  756     utils_set_locale();
  757 
  758     /* Make sure the file system is not mounted. */
  759     if (ntfs_check_if_mounted(dev_name, &mnt_flags))
  760         Eprintf("Failed to determine whether %s is mounted: %s\n",
  761                 dev_name, strerror(errno));
  762     else if (mnt_flags & NTFS_MF_MOUNTED) {
  763         Eprintf("%s is mounted.\n", dev_name);
  764         if (!opts.force)
  765             err_exit("Refusing to run!\n");
  766         fprintf(stderr, "ntfstruncate forced anyway. Hope /etc/mtab "
  767                 "is incorrect.\n");
  768     }
  769 
  770     /* Mount the device. */
  771     if (opts.no_action) {
  772         Qprintf("Running in READ-ONLY mode!\n");
  773         ul = MS_RDONLY;
  774     } else
  775         ul = 0;
  776     vol = ntfs_mount(dev_name, ul);
  777     if (!vol)
  778         err_exit("Failed to mount %s: %s\n", dev_name, strerror(errno));
  779 
  780     /* Register our exit function which will unlock and close the device. */
  781     err = atexit(&ntfstruncate_exit);
  782     if (err == -1) {
  783         Eprintf("Could not set up exit() function because atexit() "
  784                 "failed: %s Aborting...\n", strerror(errno));
  785         ntfstruncate_exit();
  786         exit(1);
  787     }
  788 
  789     /* Open the specified inode. */
  790     ni = ntfs_inode_open(vol, inode);
  791     if (!ni)
  792         err_exit("Failed to open inode %lli: %s\n", (long long)inode,
  793                 strerror(errno));
  794 
  795     /* Open the specified attribute. */
  796     na = ntfs_attr_open(ni, attr_type, attr_name, attr_name_len);
  797     if (!na)
  798         err_exit("Failed to open attribute 0x%x: %s\n",
  799                 (unsigned int)attr_type, strerror(errno));
  800 
  801     if (!opts.quiet && opts.verbose > 1) {
  802         mkDprintf("Dumping mft record before calling "
  803                 "ntfs_attr_truncate():\n");
  804         dump_mft_record(ni->mrec);
  805     }
  806 
  807     /* Truncate the attribute. */
  808     err = ntfs_attr_truncate(na, new_len);
  809     if (err)
  810         err_exit("Failed to truncate attribute 0x%x: %s\n",
  811                 (unsigned int)attr_type, strerror(errno));
  812 
  813     if (!opts.quiet && opts.verbose > 1) {
  814         mkDprintf("Dumping mft record after calling "
  815                 "ntfs_attr_truncate():\n");
  816         dump_mft_record(ni->mrec);
  817     }
  818 
  819     /* Close the attribute. */
  820     ntfs_attr_close(na);
  821     na = NULL;
  822 
  823     /* Close the inode. */
  824     err = ntfs_inode_close(ni);
  825     if (err)
  826         err_exit("Failed to close inode %lli: %s\n", (long long)inode,
  827                 strerror(errno));
  828 
  829     /* Unmount the volume. */
  830     err = ntfs_umount(vol, 0);
  831     if (err == -1)
  832         fprintf(stderr, "Warning: Failed to umount %s: %s\n", dev_name,
  833                 strerror(errno));
  834 
  835     /* Free the attribute name if it exists. */
  836     if (attr_name && attr_name != AT_UNNAMED)
  837         free(attr_name);
  838 
  839     /* Finally, disable our ntfstruncate_exit() handler. */
  840     success = TRUE;
  841 
  842     Qprintf("ntfstruncate completed successfully. Have a nice day.\n");
  843     return 0;
  844 }
  845