http://linux-ntfs.sourceforge.net/snapshots/ntfsprogs-200309071734.tar.bz2
[ntfsprogs.git] / ntfsprogs / ntfsinfo.c
1 /**
2  * ntfsinfo - Part of the Linux-NTFS project.
3  *
4  * Copyright (c) 2002 Matthew J. Fanto
5  * Copyright (c) 2002 Anton Altaparmakov
6  * Copyright (c) 2002-2003 Richard Russon
7  *
8  * This utility will dump a file's attributes.
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 #include "config.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <time.h>
30 #include <getopt.h>
31
32 #include "types.h"
33 #include "mft.h"
34 #include "attrib.h"
35 #include "layout.h"
36 #include "inode.h"
37 #include "utils.h"
38
39 static const char *EXEC_NAME = "ntfsinfo";
40
41 static struct options {
42         char    *device;        /* Device/File to work with */
43         s64      inode;         /* Info for this inode */
44         int      quiet;         /* Less output */
45         int      verbose;       /* Extra output */
46         int      force;         /* Override common sense */
47 } opts;
48
49 GEN_PRINTF (Eprintf, stderr, NULL,          FALSE)
50 GEN_PRINTF (Vprintf, stdout, &opts.verbose, TRUE)
51 GEN_PRINTF (Qprintf, stdout, &opts.quiet,   FALSE)
52
53 /**
54  * version - Print version information about the program
55  *
56  * Print a copyright statement and a brief description of the program.
57  *
58  * Return:  none
59  */
60 void version (void)
61 {
62         printf ("\n%s v%s - Display information about an NTFS Volume.\n\n",
63                 EXEC_NAME, VERSION);
64         printf ("Copyright (c)\n");
65         printf ("    2002      Matthew J. Fanto\n");
66         printf ("    2002      Anton Altaparmakov\n");
67         printf ("    2002-2003 Richard Russon\n");
68         printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
69 }
70
71 /**
72  * usage - Print a list of the parameters to the program
73  *
74  * Print a list of the parameters and options for the program.
75  *
76  * Return:  none
77  */
78 void usage (void)
79 {
80         printf ("\nUsage: %s [options] device\n"
81                 "    -i num  --inode num  Display information about this inode\n"
82                 "\n"
83                 "    -f      --force      Use less caution\n"
84                 "    -q      --quiet      Less output\n"
85                 "    -v      --verbose    More output\n"
86                 "    -V      --version    Display version information\n"
87                 "    -h      --help       Display this help\n\n",
88                 EXEC_NAME);
89         printf ("%s%s\n", ntfs_bugs, ntfs_home);
90 }
91
92 /**
93  * parse_options - Read and validate the programs command line
94  *
95  * Read the command line, verify the syntax and parse the options.
96  * This function is very long, but quite simple.
97  *
98  * Return:  1 Success
99  *          0 Error, one or more problems
100  */
101 int parse_options (int argc, char *argv[])
102 {
103         static const char *sopt = "-fh?i:qvV";
104         static const struct option lopt[] = {
105                 { "force",       no_argument,           NULL, 'f' },
106                 { "help",        no_argument,           NULL, 'h' },
107                 { "inode",       required_argument,     NULL, 'i' },
108                 { "quiet",       no_argument,           NULL, 'q' },
109                 { "verbose",     no_argument,           NULL, 'v' },
110                 { "version",     no_argument,           NULL, 'V' },
111                 { NULL, 0, NULL, 0 },
112         };
113
114         char c = -1;
115         int err  = 0;
116         int ver  = 0;
117         int help = 0;
118
119         opterr = 0; /* We'll handle the errors, thank you. */
120
121         opts.inode = -1;
122
123         while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
124                 switch (c) {
125                 case 1: /* A non-option argument */
126                         if (!opts.device) {
127                                 opts.device = argv[optind-1];
128                         } else {
129                                 opts.device = NULL;
130                                 err++;
131                         }
132                         break;
133                 case 'i':
134                         if ((opts.inode != -1) ||
135                             (!utils_parse_size (argv[optind-1], &opts.inode, FALSE))) {
136                                 err++;
137                         }
138                         break;
139                 case 'f':
140                         opts.force++;
141                         break;
142                 case 'h':
143                 case '?':
144                         help++;
145                         break;
146                 case 'q':
147                         opts.quiet++;
148                         break;
149                 case 'v':
150                         opts.verbose++;
151                         break;
152                 case 'V':
153                         ver++;
154                         break;
155                 default:
156                         if ((optopt == 'i') && (!optarg)) {
157                                 Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]);
158                         } else {
159                                 Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
160                         }
161                         err++;
162                         break;
163                 }
164         }
165
166         if (help || ver) {
167                 opts.quiet = 0;
168         } else {
169                 if (opts.device == NULL) {
170                         if (argc > 1)
171                                 Eprintf ("You must specify exactly one device.\n");
172                         err++;
173                 }
174
175                 if (opts.inode == -1) {
176                         if (argc > 1)
177                                 Eprintf ("You much specify an inode to learn about.\n");
178                         err++;
179                 }
180
181                 if (opts.quiet && opts.verbose) {
182                         Eprintf ("You may not use --quiet and --verbose at the same time.\n");
183                         err++;
184                 }
185         }
186
187         if (ver)
188                 version();
189         if (help || err)
190                 usage();
191
192         return (!err && !help && !ver);
193 }
194
195
196 /**
197  * ntfs_dump_file_name_attribute
198  */
199 void ntfs_dump_file_name_attribute(ntfs_inode *inode, MFT_RECORD *mrec)
200 {
201         FILE_NAME_ATTR *file_name_attr = NULL;
202         ATTR_RECORD *attr = NULL;
203         ntfs_attr_search_ctx *ctx = NULL;
204         char *file_name = NULL;
205         time_t ntfs_time;
206
207         ctx = ntfs_attr_get_search_ctx(inode, mrec);
208
209         if(ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
210                 fprintf(stderr, "ntfsinfo error: cannot lookup attribute AT_FILE_NAME!\n");
211                 return;
212         }
213
214         attr = ctx->attr;
215
216         file_name_attr = (FILE_NAME_ATTR*)((char *)attr + le16_to_cpu(attr->value_offset));
217
218         //need to convert the little endian unicode string to a multibyte string
219         ntfs_ucstombs(file_name_attr->file_name, file_name_attr->file_name_length,
220                         &file_name, file_name_attr->file_name_length);
221
222         printf("Dumping $FILE_NAME (0x30)\n");
223
224         //basic stuff about the file
225         printf("File Name: \t\t %s\n",file_name);
226         printf("File Name Length: \t %d\n",file_name_attr->file_name_length);
227         printf("Allocated File Size: \t %lld\n", sle64_to_cpu(file_name_attr->allocated_size));
228         printf("Real File Size: \t %lld\n", sle64_to_cpu(file_name_attr->data_size));
229
230         //time conversion stuff
231         ntfs_time = ntfs2utc (sle64_to_cpu (file_name_attr->creation_time));
232         printf("File Creation Time: \t %s",ctime(&ntfs_time));
233
234         ntfs_time = ntfs2utc (sle64_to_cpu (file_name_attr->last_data_change_time));
235         printf("File Altered Time: \t %s",ctime(&ntfs_time));
236
237         ntfs_time = ntfs2utc (sle64_to_cpu (file_name_attr->last_mft_change_time));
238         printf("MFT Changed Time: \t %s",ctime(&ntfs_time));
239
240         ntfs_time = ntfs2utc (sle64_to_cpu (file_name_attr->last_access_time));
241         printf("Last Acced Time: \t %s",ctime(&ntfs_time));
242
243         free(file_name);
244
245 }
246
247 /**
248  * ntfs_dump_standard_information
249  */
250 void ntfs_dump_standard_information(ntfs_inode *inode, MFT_RECORD *mrec)
251 {
252
253         STANDARD_INFORMATION *standard_attr = NULL;
254         ATTR_RECORD *attr = NULL;
255         ntfs_attr_search_ctx *ctx = NULL;
256
257         ctx = ntfs_attr_get_search_ctx(inode, mrec);
258
259         if(ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
260                 fprintf(stderr, "ntfsinfo error: cannot look up attribute AT_STANDARD_INFORMATION!\n");
261                 return;
262         }
263
264         attr = ctx->attr;
265
266         standard_attr = (STANDARD_INFORMATION*)((char *)attr + le16_to_cpu(attr->value_offset));
267
268         printf("Dumping $STANDARD_INFORMATION (0x10)\n");
269
270         printf("Maximum Number of Versions: \t %d \n", le32_to_cpu (standard_attr->maximum_versions));
271         printf("Version Number: \t\t %d \n", le32_to_cpu (standard_attr->version_number));
272         printf("Class ID: \t\t\t %d \n", le32_to_cpu (standard_attr->class_id));
273         printf("User ID: \t\t\t %d \n",  le32_to_cpu (standard_attr->owner_id));
274         printf("Security ID: \t\t\t %d \n",  le32_to_cpu (standard_attr->security_id));
275
276 }
277
278 /**
279  * ntfs_get_file_attributes
280  */
281 void ntfs_get_file_attributes(ntfs_volume *vol, s64 i)
282 {
283         MFT_REF mref;
284         MFT_RECORD *mrec = NULL;
285         //ntfs_attr_search_ctx *ctx = NULL;
286         ntfs_inode *inode = NULL;
287         //int error;
288
289         mref = (MFT_REF) i;
290         inode = ntfs_inode_open(vol, mref);
291
292         if (ntfs_file_record_read(vol, mref, &mrec, NULL)) {
293                 fprintf(stderr, "ntfsinfo error: error reading file record!\n");
294                 exit(1);
295         }
296
297         //see flatcap.org/ntfs/info for what formatting should look like
298         //ntfs_dump_boot_sector_information(inode, mrec);
299         ntfs_dump_file_name_attribute(inode, mrec);
300         ntfs_dump_standard_information(inode, mrec);
301 }
302
303 /**
304  * main - Begin here
305  *
306  * Start from here.
307  *
308  * Return:  0  Success, the program worked
309  *          1  Error, something went wrong
310  */
311 int main(int argc, char **argv)
312 {
313         ntfs_volume *vol;
314
315         if (!parse_options (argc, argv))
316                 return 1;
317
318         utils_set_locale();
319
320         vol = utils_mount_volume (opts.device, MS_RDONLY, opts.force);
321         if (!vol)
322                 return 1;
323
324         ntfs_get_file_attributes (vol, opts.inode);
325
326         ntfs_umount (vol, FALSE);
327         return 0;
328 }
329