"Fossies" - the Fresh Open Source Software Archive

Member "ntfs-3g_ntfsprogs-2017.3.23/ntfsprogs/ntfscluster.c" (23 Mar 2017, 14891 Bytes) of package /linux/misc/ntfs-3g_ntfsprogs-2017.3.23.tgz:


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 "ntfscluster.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3g_ntfsprogs-2016.2.22_vs_3g_ntfsprogs-2017.3.23.

    1 /**
    2  * ntfscluster - Part of the Linux-NTFS project.
    3  *
    4  * Copyright (c) 2002-2003 Richard Russon
    5  * Copyright (c) 2005 Anton Altaparmakov
    6  * Copyright (c) 2005-2006 Szabolcs Szakacsits
    7  *
    8  * This utility will locate the owner of any given sector or cluster.
    9  *
   10  * This program is free software; you can redistribute it and/or modify
   11  * it under the terms of the GNU General Public License as published by
   12  * the Free Software Foundation; either version 2 of the License, or
   13  * (at your option) any later version.
   14  *
   15  * This program is distributed in the hope that it will be useful,
   16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  * GNU General Public License for more details.
   19  *
   20  * You should have received a copy of the GNU General Public License
   21  * along with this program (in the main directory of the Linux-NTFS
   22  * distribution in the file COPYING); if not, write to the Free Software
   23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   24  */
   25 
   26 #include "config.h"
   27 
   28 #ifdef HAVE_STDIO_H
   29 #include <stdio.h>
   30 #endif
   31 #ifdef HAVE_GETOPT_H
   32 #include <getopt.h>
   33 #endif
   34 #ifdef HAVE_STDLIB_H
   35 #include <stdlib.h>
   36 #endif
   37 #ifdef HAVE_STRING_H
   38 #include <string.h>
   39 #endif
   40 #ifdef HAVE_LIMITS_H
   41 #include <limits.h>
   42 #endif
   43 
   44 #include "ntfscluster.h"
   45 #include "types.h"
   46 #include "attrib.h"
   47 #include "utils.h"
   48 #include "volume.h"
   49 #include "debug.h"
   50 #include "dir.h"
   51 #include "cluster.h"
   52 /* #include "version.h" */
   53 #include "logging.h"
   54 
   55 static const char *EXEC_NAME = "ntfscluster";
   56 static struct options opts;
   57 
   58 /**
   59  * version - Print version information about the program
   60  *
   61  * Print a copyright statement and a brief description of the program.
   62  *
   63  * Return:  none
   64  */
   65 static void version(void)
   66 {
   67     ntfs_log_info("\n%s v%s (libntfs-3g) - Find the owner of any given sector or "
   68             "cluster.\n\n", EXEC_NAME, VERSION);
   69     ntfs_log_info("Copyright (c) 2002-2003 Richard Russon\n");
   70     ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n");
   71     ntfs_log_info("Copyright (c) 2005-2006 Szabolcs Szakacsits\n");
   72     ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
   73 }
   74 
   75 /**
   76  * usage - Print a list of the parameters to the program
   77  *
   78  * Print a list of the parameters and options for the program.
   79  *
   80  * Return:  none
   81  */
   82 static void usage(void)
   83 {
   84     ntfs_log_info("\nUsage: %s [options] device\n"
   85         "    -i, --info           Print information about the volume (default)\n"
   86         "\n"
   87         "    -c, --cluster RANGE  Look for objects in this range of clusters\n"
   88         "    -s, --sector RANGE   Look for objects in this range of sectors\n"
   89         "    -I, --inode NUM      Show information about this inode\n"
   90         "    -F, --filename NAME  Show information about this file\n"
   91     /*  "    -l, --last           Find the last file on the volume\n" */
   92         "\n"
   93         "    -f, --force          Use less caution\n"
   94         "    -q, --quiet          Less output\n"
   95         "    -v, --verbose        More output\n"
   96         "    -V, --version        Version information\n"
   97         "    -h, --help           Print this help\n\n",
   98         EXEC_NAME);
   99     ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
  100 }
  101 
  102 /**
  103  * parse_options - Read and validate the programs command line
  104  *
  105  * Read the command line, verify the syntax and parse the options.
  106  * This function is very long, but quite simple.
  107  *
  108  * Return:  1 Success
  109  *      0 Error, one or more problems
  110  */
  111 static int parse_options(int argc, char **argv)
  112 {
  113     static const char *sopt = "-c:F:fh?I:ilqs:vV";
  114     static const struct option lopt[] = {
  115         { "cluster",    required_argument,  NULL, 'c' },
  116         { "filename",   required_argument,  NULL, 'F' },
  117         { "force",  no_argument,        NULL, 'f' },
  118         { "help",   no_argument,        NULL, 'h' },
  119         { "info",   no_argument,        NULL, 'i' },
  120         { "inode",  required_argument,  NULL, 'I' },
  121         { "last",   no_argument,        NULL, 'l' },
  122         { "quiet",  no_argument,        NULL, 'q' },
  123         { "sector", required_argument,  NULL, 's' },
  124         { "verbose",    no_argument,        NULL, 'v' },
  125         { "version",    no_argument,        NULL, 'V' },
  126         { NULL,     0,          NULL, 0   }
  127     };
  128 
  129     int c = -1;
  130     int err  = 0;
  131     int ver  = 0;
  132     int help = 0;
  133     int levels = 0;
  134     char *end = NULL;
  135 
  136     opterr = 0; /* We'll handle the errors, thank you. */
  137 
  138     opts.action      = act_none;
  139     opts.range_begin = -1;
  140     opts.range_end   = -1;
  141 
  142     while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
  143         switch (c) {
  144         case 1: /* A non-option argument */
  145             if (!opts.device) {
  146                 opts.device = argv[optind-1];
  147             } else {
  148                 opts.device = NULL;
  149                 err++;
  150             }
  151             break;
  152 
  153         case 'c':
  154             if ((opts.action == act_none) &&
  155                 (utils_parse_range(optarg, &opts.range_begin, &opts.range_end, FALSE)))
  156                 opts.action = act_cluster;
  157             else
  158                 opts.action = act_error;
  159             break;
  160         case 'F':
  161             if (opts.action == act_none) {
  162                 opts.action = act_file;
  163                 opts.filename = optarg;
  164             } else {
  165                 opts.action = act_error;
  166             }
  167             break;
  168         case 'f':
  169             opts.force++;
  170             break;
  171         case 'h':
  172             help++;
  173             break;
  174         case 'I':
  175             if (opts.action == act_none) {
  176                 opts.action = act_inode;
  177                 opts.inode = strtol(optarg, &end, 0);
  178                 if (end && *end)
  179                     err++;
  180             } else {
  181                 opts.action = act_error;
  182             }
  183             break;
  184         case 'i':
  185             if (opts.action == act_none)
  186                 opts.action = act_info;
  187             else
  188                 opts.action = act_error;
  189             break;
  190         case 'l':
  191             if (opts.action == act_none)
  192                 opts.action = act_last;
  193             else
  194                 opts.action = act_error;
  195             break;
  196         case 'q':
  197             opts.quiet++;
  198             ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
  199             break;
  200         case 's':
  201             if ((opts.action == act_none) &&
  202                 (utils_parse_range(optarg, &opts.range_begin, &opts.range_end, FALSE)))
  203                 opts.action = act_sector;
  204             else
  205                 opts.action = act_error;
  206             break;
  207         case 'v':
  208             opts.verbose++;
  209             ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
  210             break;
  211         case 'V':
  212             ver++;
  213             break;
  214         case '?':
  215             if (strncmp (argv[optind-1], "--log-", 6) == 0) {
  216                 if (!ntfs_log_parse_option (argv[optind-1]))
  217                     err++;
  218                 break;
  219             }
  220             /* fall through */
  221         default:
  222             if ((optopt == 'c') || (optopt == 's'))
  223                 ntfs_log_error("Option '%s' requires an argument.\n", argv[optind-1]);
  224             else
  225                 ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
  226             err++;
  227             break;
  228         }
  229     }
  230 
  231     /* Make sure we're in sync with the log levels */
  232     levels = ntfs_log_get_levels();
  233     if (levels & NTFS_LOG_LEVEL_VERBOSE)
  234         opts.verbose++;
  235     if (!(levels & NTFS_LOG_LEVEL_QUIET))
  236         opts.quiet++;
  237 
  238     if (help || ver) {
  239         opts.quiet = 0;
  240     } else {
  241         if (opts.action == act_none)
  242             opts.action = act_info;
  243         if (opts.action == act_info)
  244             opts.quiet = 0;
  245 
  246         if (opts.device == NULL) {
  247             if (argc > 1)
  248                 ntfs_log_error("You must specify exactly one device.\n");
  249             err++;
  250         }
  251 
  252         if (opts.quiet && opts.verbose) {
  253             ntfs_log_error("You may not use --quiet and --verbose at the same time.\n");
  254             err++;
  255         }
  256 
  257         if (opts.action == act_error) {
  258             ntfs_log_error("You may only specify one action: --info, --cluster, --sector or --last.\n");
  259             err++;
  260         } else if (opts.range_begin > opts.range_end) {
  261             ntfs_log_error("The range must be in ascending order.\n");
  262             err++;
  263         }
  264     }
  265 
  266     if (ver)
  267         version();
  268     if (help || err)
  269         usage();
  270 
  271         /* tri-state 0 : done, 1 : error, -1 : proceed */
  272     return (err ? 1 : (help || ver ? 0 : -1));
  273 }
  274 
  275 
  276 /**
  277  * info
  278  */
  279 static int info(ntfs_volume *vol)
  280 {
  281     u64 a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u;
  282     int cb, sb, cps;
  283     u64 uc = 0, mc = 0, fc = 0;
  284 
  285     struct mft_search_ctx *m_ctx;
  286     ntfs_attr_search_ctx *a_ctx;
  287     runlist_element *rl;
  288     ATTR_RECORD *rec;
  289     int z;
  290     int inuse = 0;
  291 
  292     m_ctx = mft_get_search_ctx(vol);
  293     m_ctx->flags_search = FEMR_IN_USE | FEMR_METADATA | FEMR_BASE_RECORD | FEMR_NOT_BASE_RECORD;
  294     while (mft_next_record(m_ctx) == 0) {
  295 
  296         if (!(m_ctx->flags_match & FEMR_IN_USE))
  297             continue;
  298 
  299         inuse++;
  300 
  301         a_ctx = ntfs_attr_get_search_ctx(m_ctx->inode, NULL);
  302 
  303         while ((rec = find_attribute(AT_UNUSED, a_ctx))) {
  304 
  305             if (!rec->non_resident)
  306                 continue;
  307 
  308             rl = ntfs_mapping_pairs_decompress(vol, rec, NULL);
  309 
  310             for (z = 0; rl[z].length > 0; z++)
  311             {
  312                 if (rl[z].lcn >= 0) {
  313                     if (m_ctx->flags_match & FEMR_METADATA)
  314                         mc += rl[z].length;
  315                     else
  316                         uc += rl[z].length;
  317                 }
  318 
  319             }
  320 
  321             free(rl);
  322         }
  323 
  324         ntfs_attr_put_search_ctx(a_ctx);
  325     }
  326     mft_put_search_ctx(m_ctx);
  327 
  328     cb  = vol->cluster_size_bits;
  329     sb  = vol->sector_size_bits;
  330     cps = cb - sb;
  331 
  332     fc  = vol->nr_clusters-mc-uc;
  333     fc  <<= cb;
  334     mc  <<= cb;
  335     uc  <<= cb;
  336 
  337     a = vol->sector_size;
  338     b = vol->cluster_size;
  339     c = 1 << cps;
  340     d = vol->nr_clusters << cb;
  341     e = vol->nr_clusters;
  342     f = vol->nr_clusters >> cps;
  343     g = vol->mft_na->initialized_size >> vol->mft_record_size_bits;
  344     h = inuse;
  345     i = h * 100 / g;
  346     j = fc;
  347     k = fc >> sb;
  348     l = fc >> cb;
  349     m = fc * 100 / b / e;
  350     n = uc;
  351     o = uc >> sb;
  352     p = uc >> cb;
  353     q = uc * 100 / b / e;
  354     r = mc;
  355     s = mc >> sb;
  356     t = mc >> cb;
  357     u = mc * 100 / b / e;
  358 
  359     ntfs_log_info("bytes per sector        : %llu\n", (unsigned long long)a);
  360     ntfs_log_info("bytes per cluster       : %llu\n", (unsigned long long)b);
  361     ntfs_log_info("sectors per cluster     : %llu\n", (unsigned long long)c);
  362     ntfs_log_info("bytes per volume        : %llu\n", (unsigned long long)d);
  363     ntfs_log_info("sectors per volume      : %llu\n", (unsigned long long)e);
  364     ntfs_log_info("clusters per volume     : %llu\n", (unsigned long long)f);
  365     ntfs_log_info("initialized mft records : %llu\n", (unsigned long long)g);
  366     ntfs_log_info("mft records in use      : %llu\n", (unsigned long long)h);
  367     ntfs_log_info("mft records percentage  : %llu\n", (unsigned long long)i);
  368     ntfs_log_info("bytes of free space     : %llu\n", (unsigned long long)j);
  369     ntfs_log_info("sectors of free space   : %llu\n", (unsigned long long)k);
  370     ntfs_log_info("clusters of free space  : %llu\n", (unsigned long long)l);
  371     ntfs_log_info("percentage free space   : %llu\n", (unsigned long long)m);
  372     ntfs_log_info("bytes of user data      : %llu\n", (unsigned long long)n);
  373     ntfs_log_info("sectors of user data    : %llu\n", (unsigned long long)o);
  374     ntfs_log_info("clusters of user data   : %llu\n", (unsigned long long)p);
  375     ntfs_log_info("percentage user data    : %llu\n", (unsigned long long)q);
  376     ntfs_log_info("bytes of metadata       : %llu\n", (unsigned long long)r);
  377     ntfs_log_info("sectors of metadata     : %llu\n", (unsigned long long)s);
  378     ntfs_log_info("clusters of metadata    : %llu\n", (unsigned long long)t);
  379     ntfs_log_info("percentage metadata     : %llu\n", (unsigned long long)u);
  380 
  381     return 0;
  382 }
  383 
  384 /**
  385  * dump_file
  386  */
  387 static int dump_file(ntfs_volume *vol, ntfs_inode *ino)
  388 {
  389     char buffer[1024];
  390     ntfs_attr_search_ctx *ctx;
  391     ATTR_RECORD *rec;
  392     int i;
  393     runlist *runs;
  394 
  395     utils_inode_get_name(ino, buffer, sizeof(buffer));
  396 
  397     ntfs_log_info("Dump: %s\n", buffer);
  398 
  399     ctx = ntfs_attr_get_search_ctx(ino, NULL);
  400 
  401     while ((rec = find_attribute(AT_UNUSED, ctx))) {
  402         ntfs_log_info("    0x%02x - ", (int)le32_to_cpu(rec->type));
  403         if (rec->non_resident) {
  404             ntfs_log_info("non-resident\n");
  405             runs = ntfs_mapping_pairs_decompress(vol, rec, NULL);
  406             if (runs) {
  407                 ntfs_log_info("             VCN     LCN     Length\n");
  408                 for (i = 0; runs[i].length > 0; i++) {
  409                     ntfs_log_info("        %8lld %8lld %8lld\n",
  410                             (long long)runs[i].vcn,
  411                             (long long)runs[i].lcn,
  412                             (long long)
  413                             runs[i].length);
  414                 }
  415                 free(runs);
  416             }
  417         } else {
  418             ntfs_log_info("resident\n");
  419         }
  420     }
  421 
  422     ntfs_attr_put_search_ctx(ctx);
  423     return 0;
  424 }
  425 
  426 /**
  427  * print_match
  428  */
  429 static int print_match(ntfs_inode *ino, ATTR_RECORD *attr,
  430     runlist_element *run, void *data __attribute__((unused)))
  431 {
  432     char *buffer;
  433 
  434     if (!ino || !attr || !run)
  435         return 1;
  436 
  437     buffer = malloc(MAX_PATH);
  438     if (!buffer) {
  439         ntfs_log_error("!buffer\n");
  440         return 1;
  441     }
  442 
  443     utils_inode_get_name(ino, buffer, MAX_PATH);
  444     ntfs_log_info("Inode %llu %s", (unsigned long long)ino->mft_no, buffer);
  445 
  446     utils_attr_get_name(ino->vol, attr, buffer, MAX_PATH);
  447     ntfs_log_info("/%s\n", buffer);
  448 
  449     free(buffer);
  450     return 0;
  451 }
  452 
  453 /**
  454  * find_last
  455  */
  456 static int find_last(ntfs_inode *ino, ATTR_RECORD *attr, runlist_element *run,
  457     void *data)
  458 {
  459     struct match *m;
  460 
  461     if (!ino || !attr || !run || !data)
  462         return 1;
  463 
  464     m = data;
  465 
  466     if ((run->lcn + run->length) > m->lcn) {
  467         m->inum = ino->mft_no;
  468         m->lcn  = run->lcn + run->length;
  469     }
  470 
  471     return 0;
  472 }
  473 
  474 /**
  475  * main - Begin here
  476  *
  477  * Start from here.
  478  *
  479  * Return:  0  Success, the program worked
  480  *      1  Error, something went wrong
  481  */
  482 int main(int argc, char *argv[])
  483 {
  484     ntfs_volume *vol;
  485     ntfs_inode *ino = NULL;
  486     struct match m;
  487     int res;
  488     int result = 1;
  489 #ifdef HAVE_WINDOWS_H
  490     char *unix_name;
  491 #endif
  492 
  493     ntfs_log_set_handler(ntfs_log_handler_outerr);
  494 
  495     res = parse_options(argc, argv);
  496     if (res >= 0)
  497         return (res);
  498 
  499     utils_set_locale();
  500 
  501     vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY |
  502             (opts.force ? NTFS_MNT_RECOVER : 0));
  503     if (!vol)
  504         return 1;
  505 
  506     switch (opts.action) {
  507         case act_sector:
  508             if (opts.range_begin == opts.range_end)
  509                 ntfs_log_quiet("Searching for sector %llu\n",
  510                         (unsigned long long)opts.range_begin);
  511             else
  512                 ntfs_log_quiet("Searching for sector range %llu-%llu\n", (unsigned long long)opts.range_begin, (unsigned long long)opts.range_end);
  513             /* Convert to clusters */
  514             opts.range_begin >>= (vol->cluster_size_bits - vol->sector_size_bits);
  515             opts.range_end   >>= (vol->cluster_size_bits - vol->sector_size_bits);
  516             result = cluster_find(vol, opts.range_begin, opts.range_end, (cluster_cb*)&print_match, NULL);
  517             break;
  518         case act_cluster:
  519             if (opts.range_begin == opts.range_end)
  520                 ntfs_log_quiet("Searching for cluster %llu\n",
  521                         (unsigned long long)opts.range_begin);
  522             else
  523                 ntfs_log_quiet("Searching for cluster range %llu-%llu\n", (unsigned long long)opts.range_begin, (unsigned long long)opts.range_end);
  524             result = cluster_find(vol, opts.range_begin, opts.range_end, (cluster_cb*)&print_match, NULL);
  525             break;
  526         case act_file:
  527 #ifdef HAVE_WINDOWS_H
  528             unix_name = ntfs_utils_unix_path(opts.filename);
  529             ino = 0;
  530             if (unix_name) {
  531                 ino = ntfs_pathname_to_inode(vol, NULL,
  532                                 unix_name);
  533                 free(unix_name);
  534             }
  535 #else
  536             ino = ntfs_pathname_to_inode(vol, NULL, opts.filename);
  537 #endif
  538             if (ino)
  539                 result = dump_file(vol, ino);
  540             break;
  541         case act_inode:
  542             ino = ntfs_inode_open(vol, opts.inode);
  543             if (ino) {
  544                 result = dump_file(vol, ino);
  545                 ntfs_inode_close(ino);
  546             } else {
  547                 ntfs_log_error("Cannot open inode %llu\n",
  548                         (unsigned long long)opts.inode);
  549             }
  550             break;
  551         case act_last:
  552             memset(&m, 0, sizeof(m));
  553             m.lcn = -1;
  554             result = cluster_find(vol, 0, LONG_MAX, (cluster_cb*)&find_last, &m);
  555             if (m.lcn >= 0) {
  556                 ino = ntfs_inode_open(vol, m.inum);
  557                 if (ino) {
  558                     result = dump_file(vol, ino);
  559                     ntfs_inode_close(ino);
  560                 } else {
  561                     ntfs_log_error("Cannot open inode %llu\n",
  562                             (unsigned long long)
  563                             opts.inode);
  564                 }
  565                 result = 0;
  566             } else {
  567                 result = 1;
  568             }
  569             break;
  570         case act_info:
  571         default:
  572             result = info(vol);
  573             break;
  574     }
  575 
  576     ntfs_umount(vol, FALSE);
  577     return result;
  578 }
  579 
  580