1N/A * ntfsundelete - Part of the Linux-NTFS project. 1N/A * Copyright (c) 2002-2005 Richard Russon 1N/A * Copyright (c) 2004-2005 Holger Ohmacht 1N/A * Copyright (c) 2005 Anton Altaparmakov 1N/A * Copyright (c) 2007 Yura Pakhuchiy 1N/A * This utility will recover deleted files from an NTFS volume. 1N/A * This program is free software; you can redistribute it and/or modify 1N/A * it under the terms of the GNU General Public License as published by 1N/A * the Free Software Foundation; either version 2 of the License, or 1N/A * (at your option) any later version. 1N/A * This program is distributed in the hope that it will be useful, 1N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of 1N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1N/A * GNU General Public License for more details. 1N/A * You should have received a copy of the GNU General Public License 1N/A * along with this program (in the main directory of the Linux-NTFS 1N/A * distribution in the file COPYING); if not, write to the Free Software 1N/A * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1N/Astatic range *
ranges;
/* Array containing all Inode-Ranges for undelete */ 1N/A * parse_inode_arg - parses the inode expression 1N/A * Parses the optarg after parameter -u for valid ranges 1N/A * Return: Number of correct inode specifications or -1 for error 1N/A /* Check whether optarg is available or not */ 1N/A return (0);
/* bailout if no optarg */ 1N/A /* init variables */ 1N/A /* alloc mem for range table */ 1N/A /* Try to get inode */ 1N/A /* invalid char at begin */ 1N/A /* RANGE - Check for range */ 1N/A /* check for correct values */ 1N/A /* put into struct */ 1N/A /* SINGLE VALUE, BUT CONTINUING */ 1N/A /* put inode into range list */ 1N/A }
else {
/* SINGLE VALUE, END */ 1N/A * version - Print version information about the program 1N/A * Print a copyright statement and a brief description of the program. 1N/A "Copyright (c) 2004-2005 Holger Ohmacht\n" 1N/A "Copyright (c) 2005 Anton Altaparmakov\n" 1N/A "Copyright (c) 2007 Yura Pakhuchiy\n");
1N/A * usage - Print a list of the parameters to the program 1N/A * Print a list of the parameters and options for the program. 1N/A " -s, --scan Scan for files (default)\n" 1N/A " -p, --percentage NUM Minimum percentage recoverable\n" 1N/A " -m, --match PATTERN Only work on files with matching names\n" 1N/A " -C, --case Case sensitive matching\n" 1N/A " -S, --size RANGE Match files of this size\n" 1N/A " -t, --time SINCE Last referenced since this time\n" 1N/A " -u, --undelete Undelete mode\n" 1N/A " -i, --inodes RANGE Recover these inodes\n" 1N/A //" -I, --interactive Interactive mode\n" 1N/A " -o, --output FILE Save with this filename\n" 1N/A " -O, --optimistic Undelete in-use clusters as well\n" 1N/A " -d, --destination DIR Destination directory\n" 1N/A " -b, --byte NUM Fill missing parts with this byte\n" 1N/A " -T, --truncate Truncate 100%% recoverable file to exact size.\n" 1N/A " -P, --parent Show parent directory\n" 1N/A " -c, --copy RANGE Write a range of MFT records to a file\n" 1N/A " -f, --force Use less caution\n" 1N/A " -q, --quiet Less output\n" 1N/A " -v, --verbose More output\n" 1N/A " -V, --version Display version information\n" 1N/A " -h, --help Display this help\n\n",
1N/A * transform - Convert a shell style pattern to a regex 1N/A * @pattern: String to be converted 1N/A * @regex: Resulting regular expression is put here 1N/A * This will transform patterns, such as "*.doc" to true regular expressions. 1N/A * The function will also place '^' and '$' around the expression to make it 1N/A * behave as the user would expect 1N/A * The returned string must be freed by the caller. 1N/A * If transform fails, @regex will not be changed. 1N/A * Return: 1, Success, the string was transformed 1N/A * 0, An error occurred 1N/A * parse_time - Convert a time abbreviation to seconds 1N/A * @string: The string to be converted 1N/A * @since: The absolute time referred to 1N/A * Strings representing times will be converted into a time_t. The numbers will 1N/A * be regarded as seconds unless suffixed. 1N/A * Suffix Description 1N/A * Therefore, passing "1W" will return the time_t representing 1 week ago. 1N/A * Only the first character of the suffix is read. 1N/A * If parse_time fails, @since will not be changed 1N/A * 0 Error, the string was malformed 1N/A * parse_options - Read and validate the programs command line 1N/A * Read the command line, verify the syntax and parse the options. 1N/A * This function is very long, but quite simple. 1N/A * 0 Error, one or more problems 1N/A static const char *
sopt =
"-b:Cc:d:fh?i:m:o:OPp:sS:t:TuqvV";
1N/A //{ "interactive", no_argument, NULL, 'I' }, 1N/A opterr = 0;
/* We'll handle the errors, thank you. */ 1N/A case 1:
/* A non-option argument */ 1N/A /* set regex-flag on true ;) */ 1N/A /* Make sure we're in sync with the log levels */ 1N/A "--match, --ignore-case, --size and --time.\n");
1N/A /*if ((opts.percent != -1) || (opts.size_begin > 0) || (opts.size_end > 0)) { 1N/A ntfs_log_error("Undelete can only be used with " 1N/A "--output, --destination, --byte and --truncate.\n"); 1N/A * free_file - Release the resources used by a file object 1N/A * @file: The unwanted file object 1N/A * This will free up the memory used by a file object and iterate through the 1N/A * object's children, freeing their resources too. 1N/A * verify_parent - confirm a record is parent of a file 1N/A * @name: a filename of the file 1N/A * @rec: the mft record of the possible parent 1N/A * Check that @rec is the parent of the file represented by @name. 1N/A * If @rec is a directory, but it is created after @name, then we 1N/A * can't determine whether @rec is really @name's parent. 1N/A * Return: @rec's filename, either same name space as @name or lowest space. 1N/A * NULL if can't determine parenthood or on error. 1N/A /* if name is older than this dir -> can't determine */ 1N/A * get_parent_name - Find the name of a file's parent. 1N/A * @name: the filename whose parent's name to find 1N/A "get_parent_name()\n");
1N/A "filename to current " 1N/A * get_filenames - Read an MFT Record's $FILENAME attributes 1N/A * @file: The file object to work with 1N/A * A single file may have more than one filename. This is quite common. 1N/A * Windows creates a short DOS name for each long name, e.g. LONGFI~1.XYZ, 1N/A * The filenames that are found are put in filename objects and added to a 1N/A * linked list of filenames in the file object. For convenience, the unicode 1N/A * filename is converted into the current locale and stored in the filename 1N/A * One of the filenames is picked (the one with the lowest numbered namespace) 1N/A * and its locale friendly name is put in pref_name. 1N/A * Return: n The number of $FILENAME attributes found 1N/A /* We know this will always be resident. */ 1N/A "get_filenames().\n");
1N/A "current locale.\n");
1N/A * get_data - Read an MFT Record's $DATA attributes 1N/A * @file: The file object to work with 1N/A * @vol: An ntfs volume obtained from ntfs_mount 1N/A * A file may have more than one data stream. All files will have an unnamed 1N/A * data stream which contains the file's data. Some Windows applications store 1N/A * extra information in a separate stream. 1N/A * The streams that are found are put in data objects and added to a linked 1N/A * list of data streams in the file object. 1N/A * Return: n The number of $FILENAME attributes found 1N/A "into current locale.\n");
1N/A * read_record - Read an MFT record into memory 1N/A * @vol: An ntfs volume obtained from ntfs_mount 1N/A * @record: The record number to read 1N/A * Read the specified MFT record and gather as much information about it as 1N/A * Return: Pointer A ufile object containing the results 1N/A * calc_percentage - Calculate how much of the file is recoverable 1N/A * @file: The file object to work with 1N/A * @vol: An ntfs volume obtained from ntfs_mount 1N/A * Read through all the $DATA streams and determine if each cluster in each 1N/A * stream is still free disk space. This is just measuring the potential for 1N/A * recovery. The data may have still been overwritten by a another file which 1N/A * Files with a resident $DATA stream will have a 100% potential. 1N/A * N.B. If $DATA attribute spans more than one MFT record (i.e. badly 1N/A * fragmented) then only the data in this segment will be used for the 1N/A * N.B. Currently, compressed and encrypted files cannot be recovered, so they 1N/A * Return: n The percentage of the file that _could_ be recovered 1N/A "calculating percentage for inode %lld\n",
1N/A * dump_record - Print everything we know about an MFT record 1N/A * @file: The file to work with 1N/A * Output the contents of the file object. This will print everything that has 1N/A * been read from the MFT record, or implied by various means. 1N/A * Because of the redundant nature of NTFS, there will be some duplication of 1N/A * information, though it will have been read from different sources. 1N/A * N.B. If the filename is missing, or couldn't be converted to the current 1N/A * locale, "<none>" will be displayed. 1N/A * list_record - Print a one line summary of the file 1N/A * @file: The file to work with 1N/A * Print a one line description of a file. 1N/A * Inode Flags %age Date Size Filename 1N/A * The output will contain the file's inode number (MFT Record), some flags, 1N/A * the percentage of the file that is recoverable, the last modification date, 1N/A * the size and the filename. 1N/A * C = Compressed, E = Encrypted, ! = Metadata may span multiple records. 1N/A * N.B. The file size is stored in many forms in several attributes. This 1N/A * display the largest it finds. 1N/A * N.B. If the filename is missing, or couldn't be converted to the current 1N/A * locale, "<none>" will be displayed. 1N/A * name_match - Does a file have a name matching a regex 1N/A * @re: The regular expression object 1N/A * @file: The file to be tested 1N/A * Iterate through the file's $FILENAME attributes and compare them against the 1N/A * regular expression, created with regcomp. 1N/A * Return: 1 There is a matching filename. 1N/A * 0 There is no match. 1N/A * write_data - Write out a block of data 1N/A * @fd: File descriptor to write to 1N/A * @buffer: Data to write 1N/A * @bufsize: Amount of data to write 1N/A * Write a block of data to a file descriptor. 1N/A * Return: -1 Error, something went wrong 1N/A * 0 Success, all the data was written 1N/A /* Try again with the rest of the buffer */ 1N/A * create_pathname - Create a path/file from some components 1N/A * @dir: Directory in which to create the file (optional) 1N/A * @name: Filename to give the file (optional) 1N/A * @stream: Name of the stream (optional) 1N/A * @buffer: Store the result here 1N/A * @bufsize: Size of buffer 1N/A * Create a filename from various pieces. The output will be of the form: 1N/A * All the components are optional. If the name is missing, "unknown" will be 1N/A * used. If the directory is missing the file will be created in the current 1N/A * directory. If the stream name is present it will be appended to the 1N/A * filename, delimited by a colon. 1N/A * N.B. If the buffer isn't large enough the name will be truncated. 1N/A * Return: n Length of the allocated name 1N/A * open_file - Open a file to write to 1N/A * @pathname: Path, name and stream of the file to open 1N/A * Create a file and return the file descriptor. 1N/A * N.B. If option force is given and existing file will be overwritten. 1N/A * Return: -1 Error, failed to create the file 1N/A * n Success, this is the file descriptor 1N/A * set_date - Set the file's date and time 1N/A * @pathname: Path and name of the file to alter 1N/A * @date: Date and time to set 1N/A * Give a file a particular date and time. 1N/A * Return: 1 Success, set the file's date and time 1N/A * 0 Error, failed to change the file's date and time 1N/A * undelete_file - Recover a deleted file from an NTFS volume 1N/A * @vol: An ntfs volume obtained from ntfs_mount 1N/A * @inode: MFT Record number to be recovered 1N/A * Read an MFT Record and try an recover any data associated with it. Some of 1N/A * the clusters may be in use; these will be filled with zeros or the fill byte 1N/A * supplied in the options. 1N/A * Each data stream will be recovered and saved to a file. The file's name will 1N/A * be the original filename and it will be written to the current directory. 1N/A * Any named data stream will be saved as filename:streamname. 1N/A * The output file's name and location can be altered by using the command line 1N/A * N.B. We cannot tell if someone has overwritten some of the data since the 1N/A * Return: 0 Error, something went wrong 1N/A * 1 Success, the data was recovered 1N/A /* try to get record */ 1N/A /* if flag was not set, print file informations */ 1N/A //ntfs_log_quiet("\n"); 1N/A /* calc_percentage() must be called before dump_record() or 1N/A * list_record(). Otherwise, when undeleting, a file will always be 1N/A * listed as 0% recoverable even if successfully undeleted. +mabs 1N/A * The following block of code implements the --truncate option. 1N/A * Its semantics are as follows: 1N/A * IF opts.truncate is set AND data stream currently being recovered is 1N/A * non-resident AND data stream has no holes (100% recoverability) AND 1N/A * 0 <= (data->size_alloc - data->size_data) <= vol->cluster_size AND 1N/A * cluster_count * vol->cluster_size == data->size_alloc THEN file 1N/A * currently being written is truncated to data->size_data bytes before 1N/A * This multiple checks try to ensure that only files with consistent 1N/A * that resident streams need not be truncated, since the original code 1N/A * already recovers their exact length. +mabs 1N/A "inconsistent $MFT record.\n");
1N/A * scan_disk - Search an NTFS volume for files that could be undeleted 1N/A * @vol: An ntfs volume obtained from ntfs_mount 1N/A * Read through all the MFT entries looking for deleted files. For each one 1N/A * determine how much of the data lies in unused disk space. 1N/A * The list can be filtered by name, size and date, using command line options. 1N/A * Return: -1 Error, something went wrong 1N/A * n Success, the number of recoverable files 1N/A for (k = 0; k <
8; k++, b>>=
1) {
1N/A /* Was -u specified with no inode 1N/A so undelete file by regex */ 1N/A * copy_mft - Write a range of MFT Records to a file 1N/A * @vol: An ntfs volume obtained from ntfs_mount 1N/A * @mft_begin: First MFT Record to save 1N/A * @mft_end: Last MFT Record to save 1N/A * Read a number of MFT Records and write them to a file. 1N/A * Return: 0 Success, all the records were written 1N/A * 1 Error, something went wrong 1N/A * Handles the undelete 1N/A /* Check whether (an) inode(s) was specified or at least a regex! */ 1N/A /* Normal undelete by specifying inode(s) */ 1N/A /* loop all given inodes */ 1N/A /* Now undelete file */ 1N/A * Return: 0 Success, the program worked 1N/A * 1 Error, something went wrong 1N/A /* handling of the different modes */ 1N/A /* Undelete-handling */ 1N/A /* Handling of copy mft */ 1N/A ;
/* Cannot happen */