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\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");
209 } else if (opts.range_begin > opts.range_end) {
210 Eprintf ("The range must be in ascending order.\n");
220 return (!err && !help && !ver);
226 int cluster_find (ntfs_volume *vol, LCN s_begin, LCN s_end)
229 int in_use = 0, result = 1;
235 buffer = malloc (vol->mft_record_size);
237 Eprintf ("Couldn't allocate memory.\n");
241 for (i = s_begin; i < s_end; i++) {
242 if (utils_cluster_in_use (vol, i) == 1) {
249 if (s_begin == s_end)
250 printf ("clusters isn't in use\n");
252 printf ("clusters aren't in use\n");
256 // first, is the cluster in use in $Bitmap?
258 for (i = 0; i < vol->nr_mft_records; i++) {
260 ntfs_attr_search_ctx *ctx;
262 if (!utils_mftrec_in_use (vol, i)) {
263 //printf ("%d skipped\n", i);
267 inode = ntfs_inode_open (vol, i);
269 Eprintf ("Can't read inode %lld\n", i);
273 if (inode->nr_extents == -1) {
274 printf ("inode %lld is an extent record\n", i);
278 Vprintf ("Inode: %lld\n", i);
279 ctx = ntfs_attr_get_search_ctx (inode, NULL);
281 if (ntfs_attr_lookup (AT_STANDARD_INFORMATION, NULL, 0, IGNORE_CASE, 0, NULL, 0, ctx) < 0) {
282 //printf ("extent inode\n");
285 ntfs_attr_reinit_search_ctx (ctx);
287 //printf ("Searching for cluster range %lld-%lld\n", s_begin, s_end);
288 while (ntfs_attr_lookup (AT_UNUSED, NULL, 0, IGNORE_CASE, 0, NULL, 0, ctx) >= 0) {
289 runlist_element *runs;
292 if (!ctx->attr->non_resident) {
293 //printf ("0x%02X ", ctx->attr->type);
297 runs = ntfs_mapping_pairs_decompress (vol, ctx->attr, NULL);
299 Eprintf ("Couldn't read the data runs.\n");
300 ntfs_inode_close (inode);
304 Vprintf ("\t[0x%02X]\n", ctx->attr->type);
306 Vprintf ("\t\tVCN\tLCN\tLength\n");
307 for (j = 0; runs[j].length > 0; j++) {
308 LCN a_begin = runs[j].lcn;
309 LCN a_end = a_begin + runs[j].length - 1;
312 continue; // sparse, discontiguous, etc
314 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);
315 //Vprintf ("\t\t%lld\t%lld\t%lld\n", runs[j].vcn, runs[j].lcn, runs[j].length);
318 if ((a_begin > s_end) || (a_end < s_begin))
319 continue; // before or after search range
323 utils_inode_get_name (inode, buffer, sizeof (buffer));
324 //XXX distinguish between file/dir
325 printf ("inode %lld %s", i, buffer);
326 utils_attr_get_name (vol, ctx->attr, buffer, sizeof (buffer));
327 printf ("%c%s\n", PATH_SEP, buffer);
334 ntfs_attr_put_search_ctx (ctx);
338 ntfs_inode_close (inode);
351 * Return: 0 Success, the program worked
352 * 1 Error, something went wrong
354 int main (int argc, char *argv[])
359 if (!parse_options (argc, argv))
364 vol = utils_mount_volume (opts.device, MS_RDONLY, opts.force);
368 switch (opts.action) {
370 if (opts.range_begin == opts.range_end)
371 Qprintf ("Searching for sector %lld\n", opts.range_begin);
373 Qprintf ("Searching for sector range %lld-%lld\n", opts.range_begin, opts.range_end);
374 /* Convert to clusters */
375 opts.range_begin <<= (vol->cluster_size_bits - vol->sector_size_bits);
376 opts.range_end <<= (vol->cluster_size_bits - vol->sector_size_bits);
377 result = cluster_find (vol, opts.range_begin, opts.range_end);
380 if (opts.range_begin == opts.range_end)
381 Qprintf ("Searching for cluster %lld\n", opts.range_begin);
383 Qprintf ("Searching for cluster range %lld-%lld\n", opts.range_begin, opts.range_end);
384 result = cluster_find (vol, opts.range_begin, opts.range_end);
397 ntfs_umount (vol, FALSE);