2 * ntfscluster - Part of the Linux-NTFS project.
4 * Copyright (c) 2002-2003 Richard Russon
6 * This utility will locate the owner of any given sector or cluster.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program (in the main directory of the Linux-NTFS
20 * distribution in the file COPYING); if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "ntfscluster.h"
37 static const char *EXEC_NAME = "ntfscluster";
38 static struct options opts;
40 GEN_PRINTF (Eprintf, stderr, NULL, FALSE)
41 GEN_PRINTF (Vprintf, stdout, &opts.verbose, TRUE)
42 GEN_PRINTF (Qprintf, stdout, &opts.quiet, FALSE)
45 * version - Print version information about the program
47 * Print a copyright statement and a brief description of the program.
53 printf ("\n%s v%s - Find the owner of any given sector or cluster.\n\n",
55 printf ("Copyright (c)\n");
56 printf (" 2002-2003 Richard Russon\n");
57 printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
61 * usage - Print a list of the parameters to the program
63 * Print a list of the parameters and options for the program.
69 printf ("\nUsage: %s [options] device\n"
70 " -i --info Print information about the volume (default)\n"
71 " -c range --cluster range Look for objects in this range of clusters\n"
72 " -s range --sector range Look for objects in this range of sectors\n"
73 /* " -l --last Find the last file on the volume\n" */
75 " -f --force Use less caution\n"
76 " -q --quiet Less output\n"
77 " -v --verbose More output\n"
78 " -V --version Version information\n"
79 " -h --help Print this help\n\n",
81 printf ("%s%s\n", ntfs_bugs, ntfs_home);
85 * parse_options - Read and validate the programs command line
87 * Read the command line, verify the syntax and parse the options.
88 * This function is very long, but quite simple.
91 * 0 Error, one or more problems
93 int parse_options (int argc, char **argv)
95 static const char *sopt = "-c:fh?iqs:vV"; // l
96 static const struct option lopt[] = {
97 { "cluster", required_argument, NULL, 'c' },
98 { "force", no_argument, NULL, 'f' },
99 { "help", no_argument, NULL, 'h' },
100 { "info", no_argument, NULL, 'i' },
101 //{ "last", no_argument, NULL, 'l' },
102 { "quiet", no_argument, NULL, 'q' },
103 { "sector", required_argument, NULL, 's' },
104 { "verbose", no_argument, NULL, 'v' },
105 { "version", no_argument, NULL, 'V' },
114 opterr = 0; /* We'll handle the errors, thank you. */
116 opts.action = act_none;
117 opts.range_begin = -1;
120 while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
122 case 1: /* A non-option argument */
124 opts.device = argv[optind-1];
132 if ((opts.action == act_none) &&
133 (utils_parse_range (optarg, &opts.range_begin, &opts.range_end, FALSE)))
134 opts.action = act_cluster;
136 opts.action = act_error;
146 if (opts.action == act_none) {
147 opts.action = act_info;
149 opts.action = act_error;
155 if (opts.action == act_none)
156 opts.action = act_last;
158 opts.action = act_error;
165 if ((opts.action == act_none) &&
166 (utils_parse_range (optarg, &opts.range_begin, &opts.range_end, FALSE)))
167 opts.action = act_sector;
169 opts.action = act_error;
178 if ((optopt == 'c') || (optopt == 's'))
179 Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]);
181 Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
190 if (opts.action == act_none)
191 opts.action = act_info;
192 if (opts.action == act_info)
195 if (opts.device == NULL) {
197 Eprintf ("You must specify exactly one device.\n");
201 if (opts.quiet && opts.verbose) {
202 Eprintf ("You may not use --quiet and --verbose at the same time.\n");
206 if (opts.action == act_error) {
207 //Eprintf ("You may only specify one action: --info, --cluster, --sector or --last.\n");
208 Eprintf ("You may only specify one action: --info, --cluster or --sector.\n");
210 } else if (opts.range_begin > opts.range_end) {
211 Eprintf ("The range must be in ascending order.\n");
221 return (!err && !help && !ver);
226 * free_space - Calculate the amount of space which isn't in use
228 u64 free_space (ntfs_volume *vol)
234 * user_space - Calculate the amount of space of the user's files
236 u64 user_space (ntfs_volume *vol)
242 * meta_space - Calculate the amount of space used by the filesystem structures
244 u64 meta_space (ntfs_volume *vol)
250 * info - Display information about the volume
252 int info (ntfs_volume *vol)
254 u64 a, b, c, d, e, f, g, h, i, j, k, l, m, n;
258 cps = vol->cluster_size_bits - vol->sector_size_bits;
259 fs = free_space (vol);
260 ms = meta_space (vol);
261 us = user_space (vol);
263 a = vol->sector_size;
264 b = vol->cluster_size;
266 d = vol->nr_clusters >> cps;
267 e = vol->nr_clusters;
270 h = fs * 100 / a / d;
273 k = us * 100 / a / d;
276 n = ms * 100 / a / d;
278 printf ("bytes per sector : %lld\n", a);
279 printf ("bytes per cluster : %lld\n", b);
280 printf ("sectors per cluster : %lld\n", c);
281 printf ("sectors per volume : %lld\n", d);
282 printf ("clusters per volume : %lld\n", e);
283 printf ("sectors of free space : %lld\n", f);
284 printf ("clusters of free space : %lld\n", g);
285 printf ("percentage free space : %lld\n", h);
286 printf ("sectors of user data : %lld\n", i);
287 printf ("clusters of user data : %lld\n", j);
288 printf ("percentage user data : %lld\n", k);
289 printf ("sectors of metadata : %lld\n", l);
290 printf ("clusters of metadata : %lld\n", m);
291 printf ("percentage metadata : %lld\n", n);
300 int cluster_find (ntfs_volume *vol, LCN s_begin, LCN s_end)
303 int in_use = 0, result = 1;
309 buffer = malloc (vol->mft_record_size);
311 Eprintf ("Couldn't allocate memory.\n");
315 for (i = s_begin; i < s_end; i++) {
316 if (utils_cluster_in_use (vol, i) == 1) {
323 if (s_begin == s_end)
324 printf ("cluster isn't in use\n");
326 printf ("clusters aren't in use\n");
331 // first, is the cluster in use in $Bitmap?
333 for (i = 0; i < vol->nr_mft_records; i++) {
335 ntfs_attr_search_ctx *ctx;
337 if (!utils_mftrec_in_use (vol, i)) {
338 //printf ("%lld skipped\n", i);
342 inode = ntfs_inode_open (vol, i);
344 Eprintf ("Can't read inode %lld\n", i);
348 if (inode->nr_extents == -1) {
349 printf ("inode %lld is an extent record\n", i);
353 Vprintf ("Inode: %lld\n", i);
354 ctx = ntfs_attr_get_search_ctx (inode, NULL);
356 if (ntfs_attr_lookup (AT_STANDARD_INFORMATION, NULL, 0, IGNORE_CASE, 0, NULL, 0, ctx) < 0) {
357 //printf ("extent inode\n");
360 ntfs_attr_reinit_search_ctx (ctx);
362 //printf ("Searching for cluster range %lld-%lld\n", s_begin, s_end);
363 while (ntfs_attr_lookup (AT_UNUSED, NULL, 0, IGNORE_CASE, 0, NULL, 0, ctx) >= 0) {
364 runlist_element *runs;
367 if (!ctx->attr->non_resident) {
368 //printf ("0x%02X ", ctx->attr->type);
372 runs = ntfs_mapping_pairs_decompress (vol, ctx->attr, NULL);
374 Eprintf ("Couldn't read the data runs.\n");
375 ntfs_inode_close (inode);
379 Vprintf ("\t[0x%02X]\n", ctx->attr->type);
381 Vprintf ("\t\tVCN\tLCN\tLength\n");
382 for (j = 0; runs[j].length > 0; j++) {
383 LCN a_begin = runs[j].lcn;
384 LCN a_end = a_begin + runs[j].length - 1;
387 continue; // sparse, discontiguous, etc
389 Vprintf ("\t\t%lld\t%lld-%lld (%lld)\n", runs[j].vcn, runs[j].lcn, runs[j].lcn + runs[j].length - 1, runs[j].length);
390 //Vprintf ("\t\t%lld\t%lld\t%lld\n", runs[j].vcn, runs[j].lcn, runs[j].length);
393 if ((a_begin > s_end) || (a_end < s_begin))
394 continue; // before or after search range
398 utils_inode_get_name (inode, buffer, sizeof (buffer));
399 //XXX distinguish between file/dir
400 printf ("inode %lld %s", i, buffer);
401 utils_attr_get_name (vol, ctx->attr, buffer, sizeof (buffer));
402 printf ("%c%s\n", PATH_SEP, buffer);
404 break; // XXX if verbose, we should list all matching runs
408 ntfs_attr_put_search_ctx (ctx);
412 ntfs_inode_close (inode);
426 * Return: 0 Success, the program worked
427 * 1 Error, something went wrong
429 int main (int argc, char *argv[])
434 if (!parse_options (argc, argv))
439 vol = utils_mount_volume (opts.device, MS_RDONLY, opts.force);
443 switch (opts.action) {
445 if (opts.range_begin == opts.range_end)
446 Qprintf ("Searching for sector %lld\n", opts.range_begin);
448 Qprintf ("Searching for sector range %lld-%lld\n", opts.range_begin, opts.range_end);
449 /* Convert to clusters */
450 opts.range_begin >>= (vol->cluster_size_bits - vol->sector_size_bits);
451 opts.range_end >>= (vol->cluster_size_bits - vol->sector_size_bits);
452 result = cluster_find (vol, opts.range_begin, opts.range_end);
455 if (opts.range_begin == opts.range_end)
456 Qprintf ("Searching for cluster %lld\n", opts.range_begin);
458 Qprintf ("Searching for cluster range %lld-%lld\n", opts.range_begin, opts.range_end);
459 result = cluster_find (vol, opts.range_begin, opts.range_end);
472 ntfs_umount (vol, FALSE);