1987da915Sopenharmony_ci/** 2987da915Sopenharmony_ci * ntfsls - Part of the Linux-NTFS project. 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * Copyright (c) 2003 Lode Leroy 5987da915Sopenharmony_ci * Copyright (c) 2003-2005 Anton Altaparmakov 6987da915Sopenharmony_ci * Copyright (c) 2003 Richard Russon 7987da915Sopenharmony_ci * Copyright (c) 2004 Carmelo Kintana 8987da915Sopenharmony_ci * Copyright (c) 2004 Giang Nguyen 9987da915Sopenharmony_ci * 10987da915Sopenharmony_ci * This utility will list a directory's files. 11987da915Sopenharmony_ci * 12987da915Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 13987da915Sopenharmony_ci * it under the terms of the GNU General Public License as published by 14987da915Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 15987da915Sopenharmony_ci * (at your option) any later version. 16987da915Sopenharmony_ci * 17987da915Sopenharmony_ci * This program is distributed in the hope that it will be useful, 18987da915Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 19987da915Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20987da915Sopenharmony_ci * GNU General Public License for more details. 21987da915Sopenharmony_ci * 22987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 23987da915Sopenharmony_ci * along with this program (in the main directory of the Linux-NTFS 24987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 25987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26987da915Sopenharmony_ci */ 27987da915Sopenharmony_ci#include "config.h" 28987da915Sopenharmony_ci 29987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 30987da915Sopenharmony_ci#include <stdio.h> 31987da915Sopenharmony_ci#endif 32987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 33987da915Sopenharmony_ci#include <stdlib.h> 34987da915Sopenharmony_ci#endif 35987da915Sopenharmony_ci#ifdef HAVE_TIME_H 36987da915Sopenharmony_ci#include <time.h> 37987da915Sopenharmony_ci#endif 38987da915Sopenharmony_ci#ifdef HAVE_GETOPT_H 39987da915Sopenharmony_ci#include <getopt.h> 40987da915Sopenharmony_ci#endif 41987da915Sopenharmony_ci#ifdef HAVE_STRING_H 42987da915Sopenharmony_ci#include <string.h> 43987da915Sopenharmony_ci#endif 44987da915Sopenharmony_ci 45987da915Sopenharmony_ci#include "types.h" 46987da915Sopenharmony_ci#include "mft.h" 47987da915Sopenharmony_ci#include "attrib.h" 48987da915Sopenharmony_ci#include "layout.h" 49987da915Sopenharmony_ci#include "inode.h" 50987da915Sopenharmony_ci#include "utils.h" 51987da915Sopenharmony_ci#include "dir.h" 52987da915Sopenharmony_ci#include "list.h" 53987da915Sopenharmony_ci#include "ntfstime.h" 54987da915Sopenharmony_ci/* #include "version.h" */ 55987da915Sopenharmony_ci#include "logging.h" 56987da915Sopenharmony_ci 57987da915Sopenharmony_cistatic const char *EXEC_NAME = "ntfsls"; 58987da915Sopenharmony_ci 59987da915Sopenharmony_ci/** 60987da915Sopenharmony_ci * To hold sub-directory information for recursive listing. 61987da915Sopenharmony_ci * @depth: the level of this dir relative to opts.path 62987da915Sopenharmony_ci */ 63987da915Sopenharmony_cistruct dir { 64987da915Sopenharmony_ci struct ntfs_list_head list; 65987da915Sopenharmony_ci ntfs_inode *ni; 66987da915Sopenharmony_ci char name[MAX_PATH]; 67987da915Sopenharmony_ci int depth; 68987da915Sopenharmony_ci}; 69987da915Sopenharmony_ci 70987da915Sopenharmony_ci/** 71987da915Sopenharmony_ci * path_component - to store path component strings 72987da915Sopenharmony_ci * 73987da915Sopenharmony_ci * @name: string pointer 74987da915Sopenharmony_ci * 75987da915Sopenharmony_ci * NOTE: @name is not directly allocated memory. It simply points to the 76987da915Sopenharmony_ci * character array name in struct dir. 77987da915Sopenharmony_ci */ 78987da915Sopenharmony_cistruct path_component { 79987da915Sopenharmony_ci struct ntfs_list_head list; 80987da915Sopenharmony_ci const char *name; 81987da915Sopenharmony_ci}; 82987da915Sopenharmony_ci 83987da915Sopenharmony_ci/* The list of sub-dirs is like a "horizontal" tree. The root of 84987da915Sopenharmony_ci * the tree is opts.path, but it is not part of the list because 85987da915Sopenharmony_ci * that's not necessary. The rules of the list are (in order of 86987da915Sopenharmony_ci * precedence): 87987da915Sopenharmony_ci * 1. directories immediately follow their parent. 88987da915Sopenharmony_ci * 2. siblings are next to one another. 89987da915Sopenharmony_ci * 90987da915Sopenharmony_ci * For example, if: 91987da915Sopenharmony_ci * 1. opts.path is / 92987da915Sopenharmony_ci * 2. / has 2 sub-dirs: dir1 and dir2 93987da915Sopenharmony_ci * 3. dir1 has 2 sub-dirs: dir11 and dir12 94987da915Sopenharmony_ci * 4. dir2 has 0 sub-dirs 95987da915Sopenharmony_ci * then the list will be: 96987da915Sopenharmony_ci * dummy head -> dir1 -> dir11 -> dir12 -> dir2 97987da915Sopenharmony_ci * 98987da915Sopenharmony_ci * dir_list_insert_pos keeps track of where to insert a sub-dir 99987da915Sopenharmony_ci * into the list. 100987da915Sopenharmony_ci */ 101987da915Sopenharmony_cistatic struct ntfs_list_head *dir_list_insert_pos = NULL; 102987da915Sopenharmony_ci 103987da915Sopenharmony_ci/* The global depth relative to opts.path. 104987da915Sopenharmony_ci * ie: opts.path has depth 0, a sub-dir of opts.path has depth 1 105987da915Sopenharmony_ci */ 106987da915Sopenharmony_cistatic int depth = 0; 107987da915Sopenharmony_ci 108987da915Sopenharmony_cistatic struct options { 109987da915Sopenharmony_ci char *device; /* Device/File to work with */ 110987da915Sopenharmony_ci int quiet; /* Less output */ 111987da915Sopenharmony_ci int verbose; /* Extra output */ 112987da915Sopenharmony_ci int force; /* Override common sense */ 113987da915Sopenharmony_ci int all; 114987da915Sopenharmony_ci int system; 115987da915Sopenharmony_ci int dos; 116987da915Sopenharmony_ci int lng; 117987da915Sopenharmony_ci int inode; 118987da915Sopenharmony_ci int classify; 119987da915Sopenharmony_ci int recursive; 120987da915Sopenharmony_ci const char *path; 121987da915Sopenharmony_ci} opts; 122987da915Sopenharmony_ci 123987da915Sopenharmony_citypedef struct { 124987da915Sopenharmony_ci ntfs_volume *vol; 125987da915Sopenharmony_ci} ntfsls_dirent; 126987da915Sopenharmony_ci 127987da915Sopenharmony_cistatic int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name, 128987da915Sopenharmony_ci const int name_len, const int name_type, 129987da915Sopenharmony_ci const s64 pos, const MFT_REF mref, 130987da915Sopenharmony_ci const unsigned dt_type); 131987da915Sopenharmony_ci 132987da915Sopenharmony_ci/** 133987da915Sopenharmony_ci * version - Print version information about the program 134987da915Sopenharmony_ci * 135987da915Sopenharmony_ci * Print a copyright statement and a brief description of the program. 136987da915Sopenharmony_ci * 137987da915Sopenharmony_ci * Return: none 138987da915Sopenharmony_ci */ 139987da915Sopenharmony_cistatic void version(void) 140987da915Sopenharmony_ci{ 141987da915Sopenharmony_ci printf("\n%s v%s (libntfs-3g) - Display information about an NTFS " 142987da915Sopenharmony_ci "Volume.\n\n", EXEC_NAME, VERSION); 143987da915Sopenharmony_ci printf("Copyright (c) 2003 Lode Leroy\n"); 144987da915Sopenharmony_ci printf("Copyright (c) 2003-2005 Anton Altaparmakov\n"); 145987da915Sopenharmony_ci printf("Copyright (c) 2003 Richard Russon\n"); 146987da915Sopenharmony_ci printf("Copyright (c) 2004 Carmelo Kintana\n"); 147987da915Sopenharmony_ci printf("Copyright (c) 2004 Giang Nguyen\n"); 148987da915Sopenharmony_ci printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); 149987da915Sopenharmony_ci} 150987da915Sopenharmony_ci 151987da915Sopenharmony_ci/** 152987da915Sopenharmony_ci * usage - Print a list of the parameters to the program 153987da915Sopenharmony_ci * 154987da915Sopenharmony_ci * Print a list of the parameters and options for the program. 155987da915Sopenharmony_ci * 156987da915Sopenharmony_ci * Return: none 157987da915Sopenharmony_ci */ 158987da915Sopenharmony_cistatic void usage(void) 159987da915Sopenharmony_ci{ 160987da915Sopenharmony_ci printf("\nUsage: %s [options] device\n" 161987da915Sopenharmony_ci "\n" 162987da915Sopenharmony_ci " -a, --all Display all files\n" 163987da915Sopenharmony_ci " -F, --classify Display classification\n" 164987da915Sopenharmony_ci " -f, --force Use less caution\n" 165987da915Sopenharmony_ci " -h, --help Display this help\n" 166987da915Sopenharmony_ci " -i, --inode Display inode numbers\n" 167987da915Sopenharmony_ci " -l, --long Display long info\n" 168987da915Sopenharmony_ci " -p, --path PATH Directory whose contents to list\n" 169987da915Sopenharmony_ci " -q, --quiet Less output\n" 170987da915Sopenharmony_ci " -R, --recursive Recursively list subdirectories\n" 171987da915Sopenharmony_ci " -s, --system Display system files\n" 172987da915Sopenharmony_ci " -V, --version Display version information\n" 173987da915Sopenharmony_ci " -v, --verbose More output\n" 174987da915Sopenharmony_ci " -x, --dos Use short (DOS 8.3) names\n" 175987da915Sopenharmony_ci "\n", 176987da915Sopenharmony_ci EXEC_NAME); 177987da915Sopenharmony_ci 178987da915Sopenharmony_ci printf("NOTE: If neither -a nor -s is specified, the program defaults to -a.\n\n"); 179987da915Sopenharmony_ci 180987da915Sopenharmony_ci printf("%s%s\n", ntfs_bugs, ntfs_home); 181987da915Sopenharmony_ci} 182987da915Sopenharmony_ci 183987da915Sopenharmony_ci/** 184987da915Sopenharmony_ci * parse_options - Read and validate the programs command line 185987da915Sopenharmony_ci * 186987da915Sopenharmony_ci * Read the command line, verify the syntax and parse the options. 187987da915Sopenharmony_ci * This function is very long, but quite simple. 188987da915Sopenharmony_ci * 189987da915Sopenharmony_ci * Return: 1 Success 190987da915Sopenharmony_ci * 0 Error, one or more problems 191987da915Sopenharmony_ci */ 192987da915Sopenharmony_cistatic int parse_options(int argc, char *argv[]) 193987da915Sopenharmony_ci{ 194987da915Sopenharmony_ci static const char *sopt = "-aFfh?ilp:qRsVvx"; 195987da915Sopenharmony_ci static const struct option lopt[] = { 196987da915Sopenharmony_ci { "all", no_argument, NULL, 'a' }, 197987da915Sopenharmony_ci { "classify", no_argument, NULL, 'F' }, 198987da915Sopenharmony_ci { "force", no_argument, NULL, 'f' }, 199987da915Sopenharmony_ci { "help", no_argument, NULL, 'h' }, 200987da915Sopenharmony_ci { "inode", no_argument, NULL, 'i' }, 201987da915Sopenharmony_ci { "long", no_argument, NULL, 'l' }, 202987da915Sopenharmony_ci { "path", required_argument, NULL, 'p' }, 203987da915Sopenharmony_ci { "recursive", no_argument, NULL, 'R' }, 204987da915Sopenharmony_ci { "quiet", no_argument, NULL, 'q' }, 205987da915Sopenharmony_ci { "system", no_argument, NULL, 's' }, 206987da915Sopenharmony_ci { "version", no_argument, NULL, 'V' }, 207987da915Sopenharmony_ci { "verbose", no_argument, NULL, 'v' }, 208987da915Sopenharmony_ci { "dos", no_argument, NULL, 'x' }, 209987da915Sopenharmony_ci { NULL, 0, NULL, 0 }, 210987da915Sopenharmony_ci }; 211987da915Sopenharmony_ci 212987da915Sopenharmony_ci int c = -1; 213987da915Sopenharmony_ci int err = 0; 214987da915Sopenharmony_ci int ver = 0; 215987da915Sopenharmony_ci int help = 0; 216987da915Sopenharmony_ci int levels = 0; 217987da915Sopenharmony_ci 218987da915Sopenharmony_ci opterr = 0; /* We'll handle the errors, thank you. */ 219987da915Sopenharmony_ci 220987da915Sopenharmony_ci memset(&opts, 0, sizeof(opts)); 221987da915Sopenharmony_ci opts.device = NULL; 222987da915Sopenharmony_ci opts.path = "/"; 223987da915Sopenharmony_ci 224987da915Sopenharmony_ci while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { 225987da915Sopenharmony_ci switch (c) { 226987da915Sopenharmony_ci case 1: 227987da915Sopenharmony_ci if (!opts.device) 228987da915Sopenharmony_ci opts.device = optarg; 229987da915Sopenharmony_ci else 230987da915Sopenharmony_ci err++; 231987da915Sopenharmony_ci break; 232987da915Sopenharmony_ci case 'p': 233987da915Sopenharmony_ci opts.path = optarg; 234987da915Sopenharmony_ci break; 235987da915Sopenharmony_ci case 'f': 236987da915Sopenharmony_ci opts.force++; 237987da915Sopenharmony_ci break; 238987da915Sopenharmony_ci case 'h': 239987da915Sopenharmony_ci case '?': 240987da915Sopenharmony_ci if (strncmp (argv[optind-1], "--log-", 6) == 0) { 241987da915Sopenharmony_ci if (!ntfs_log_parse_option (argv[optind-1])) 242987da915Sopenharmony_ci err++; 243987da915Sopenharmony_ci break; 244987da915Sopenharmony_ci } 245987da915Sopenharmony_ci help++; 246987da915Sopenharmony_ci break; 247987da915Sopenharmony_ci case 'q': 248987da915Sopenharmony_ci opts.quiet++; 249987da915Sopenharmony_ci ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); 250987da915Sopenharmony_ci break; 251987da915Sopenharmony_ci case 'v': 252987da915Sopenharmony_ci opts.verbose++; 253987da915Sopenharmony_ci ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); 254987da915Sopenharmony_ci break; 255987da915Sopenharmony_ci case 'V': 256987da915Sopenharmony_ci ver++; 257987da915Sopenharmony_ci break; 258987da915Sopenharmony_ci case 'x': 259987da915Sopenharmony_ci opts.dos = 1; 260987da915Sopenharmony_ci break; 261987da915Sopenharmony_ci case 'l': 262987da915Sopenharmony_ci opts.lng++; 263987da915Sopenharmony_ci break; 264987da915Sopenharmony_ci case 'i': 265987da915Sopenharmony_ci opts.inode++; 266987da915Sopenharmony_ci break; 267987da915Sopenharmony_ci case 'F': 268987da915Sopenharmony_ci opts.classify++; 269987da915Sopenharmony_ci break; 270987da915Sopenharmony_ci case 'a': 271987da915Sopenharmony_ci opts.all++; 272987da915Sopenharmony_ci break; 273987da915Sopenharmony_ci case 's': 274987da915Sopenharmony_ci opts.system++; 275987da915Sopenharmony_ci break; 276987da915Sopenharmony_ci case 'R': 277987da915Sopenharmony_ci opts.recursive++; 278987da915Sopenharmony_ci break; 279987da915Sopenharmony_ci default: 280987da915Sopenharmony_ci ntfs_log_error("Unknown option '%s'.\n", argv[optind - 1]); 281987da915Sopenharmony_ci err++; 282987da915Sopenharmony_ci break; 283987da915Sopenharmony_ci } 284987da915Sopenharmony_ci } 285987da915Sopenharmony_ci 286987da915Sopenharmony_ci /* Make sure we're in sync with the log levels */ 287987da915Sopenharmony_ci levels = ntfs_log_get_levels(); 288987da915Sopenharmony_ci if (levels & NTFS_LOG_LEVEL_VERBOSE) 289987da915Sopenharmony_ci opts.verbose++; 290987da915Sopenharmony_ci if (!(levels & NTFS_LOG_LEVEL_QUIET)) 291987da915Sopenharmony_ci opts.quiet++; 292987da915Sopenharmony_ci 293987da915Sopenharmony_ci /* defaults to -a if -s is not specified */ 294987da915Sopenharmony_ci if (!opts.system) 295987da915Sopenharmony_ci opts.all++; 296987da915Sopenharmony_ci 297987da915Sopenharmony_ci if (help || ver) 298987da915Sopenharmony_ci opts.quiet = 0; 299987da915Sopenharmony_ci else { 300987da915Sopenharmony_ci if (opts.device == NULL) { 301987da915Sopenharmony_ci if (argc > 1) 302987da915Sopenharmony_ci ntfs_log_error("You must specify exactly one " 303987da915Sopenharmony_ci "device.\n"); 304987da915Sopenharmony_ci err++; 305987da915Sopenharmony_ci } 306987da915Sopenharmony_ci 307987da915Sopenharmony_ci if (opts.quiet && opts.verbose) { 308987da915Sopenharmony_ci ntfs_log_error("You may not use --quiet and --verbose at the " 309987da915Sopenharmony_ci "same time.\n"); 310987da915Sopenharmony_ci err++; 311987da915Sopenharmony_ci } 312987da915Sopenharmony_ci } 313987da915Sopenharmony_ci 314987da915Sopenharmony_ci if (ver) 315987da915Sopenharmony_ci version(); 316987da915Sopenharmony_ci if (help || err) 317987da915Sopenharmony_ci usage(); 318987da915Sopenharmony_ci 319987da915Sopenharmony_ci return (!err && !help && !ver); 320987da915Sopenharmony_ci} 321987da915Sopenharmony_ci 322987da915Sopenharmony_ci/** 323987da915Sopenharmony_ci * free_dir - free one dir 324987da915Sopenharmony_ci * @tofree: the dir to free 325987da915Sopenharmony_ci * 326987da915Sopenharmony_ci * Close the inode and then free the dir 327987da915Sopenharmony_ci */ 328987da915Sopenharmony_cistatic void free_dir(struct dir *tofree) 329987da915Sopenharmony_ci{ 330987da915Sopenharmony_ci if (tofree) { 331987da915Sopenharmony_ci if (tofree->ni) { 332987da915Sopenharmony_ci ntfs_inode_close(tofree->ni); 333987da915Sopenharmony_ci tofree->ni = NULL; 334987da915Sopenharmony_ci } 335987da915Sopenharmony_ci free(tofree); 336987da915Sopenharmony_ci } 337987da915Sopenharmony_ci} 338987da915Sopenharmony_ci 339987da915Sopenharmony_ci/** 340987da915Sopenharmony_ci * free_dirs - walk the list of dir's and free each of them 341987da915Sopenharmony_ci * @dir_list: the ntfs_list_head of any entry in the list 342987da915Sopenharmony_ci * 343987da915Sopenharmony_ci * Iterate over @dir_list, calling free_dir on each entry 344987da915Sopenharmony_ci */ 345987da915Sopenharmony_cistatic void free_dirs(struct ntfs_list_head *dir_list) 346987da915Sopenharmony_ci{ 347987da915Sopenharmony_ci struct dir *tofree = NULL; 348987da915Sopenharmony_ci struct ntfs_list_head *walker = NULL; 349987da915Sopenharmony_ci 350987da915Sopenharmony_ci if (dir_list) { 351987da915Sopenharmony_ci ntfs_list_for_each(walker, dir_list) { 352987da915Sopenharmony_ci free_dir(tofree); 353987da915Sopenharmony_ci tofree = ntfs_list_entry(walker, struct dir, list); 354987da915Sopenharmony_ci } 355987da915Sopenharmony_ci 356987da915Sopenharmony_ci free_dir(tofree); 357987da915Sopenharmony_ci } 358987da915Sopenharmony_ci} 359987da915Sopenharmony_ci 360987da915Sopenharmony_ci/** 361987da915Sopenharmony_ci * readdir_recursive - list a directory and sub-directories encountered 362987da915Sopenharmony_ci * @ni: ntfs inode of the directory to list 363987da915Sopenharmony_ci * @pos: current position in directory 364987da915Sopenharmony_ci * @dirent: context for filldir callback supplied by the caller 365987da915Sopenharmony_ci * 366987da915Sopenharmony_ci * For each directory, print its path relative to opts.path. List a directory, 367987da915Sopenharmony_ci * then list each of its sub-directories. 368987da915Sopenharmony_ci * 369987da915Sopenharmony_ci * Returns 0 on success or -1 on error. 370987da915Sopenharmony_ci * 371987da915Sopenharmony_ci * NOTE: Assumes recursive option. Currently no limit on the depths of 372987da915Sopenharmony_ci * recursion. 373987da915Sopenharmony_ci */ 374987da915Sopenharmony_cistatic int readdir_recursive(ntfs_inode * ni, s64 * pos, ntfsls_dirent * dirent) 375987da915Sopenharmony_ci{ 376987da915Sopenharmony_ci /* list of dirs to "ls" recursively */ 377987da915Sopenharmony_ci static struct dir dirs = { 378987da915Sopenharmony_ci .list = NTFS_LIST_HEAD_INIT(dirs.list), 379987da915Sopenharmony_ci .ni = NULL, 380987da915Sopenharmony_ci .name = {0}, 381987da915Sopenharmony_ci .depth = 0 382987da915Sopenharmony_ci }; 383987da915Sopenharmony_ci 384987da915Sopenharmony_ci static struct path_component paths = { 385987da915Sopenharmony_ci .list = NTFS_LIST_HEAD_INIT(paths.list), 386987da915Sopenharmony_ci .name = NULL 387987da915Sopenharmony_ci }; 388987da915Sopenharmony_ci 389987da915Sopenharmony_ci static struct path_component base_comp; 390987da915Sopenharmony_ci 391987da915Sopenharmony_ci struct dir *subdir = NULL; 392987da915Sopenharmony_ci struct dir *tofree = NULL; 393987da915Sopenharmony_ci struct path_component comp; 394987da915Sopenharmony_ci struct path_component *tempcomp = NULL; 395987da915Sopenharmony_ci struct ntfs_list_head *dir_walker = NULL; 396987da915Sopenharmony_ci struct ntfs_list_head *comp_walker = NULL; 397987da915Sopenharmony_ci s64 pos2 = 0; 398987da915Sopenharmony_ci int ni_depth = depth; 399987da915Sopenharmony_ci int result = 0; 400987da915Sopenharmony_ci 401987da915Sopenharmony_ci if (ntfs_list_empty(&dirs.list)) { 402987da915Sopenharmony_ci base_comp.name = opts.path; 403987da915Sopenharmony_ci ntfs_list_add(&base_comp.list, &paths.list); 404987da915Sopenharmony_ci dir_list_insert_pos = &dirs.list; 405987da915Sopenharmony_ci printf("%s:\n", opts.path); 406987da915Sopenharmony_ci } 407987da915Sopenharmony_ci 408987da915Sopenharmony_ci depth++; 409987da915Sopenharmony_ci 410987da915Sopenharmony_ci result = ntfs_readdir(ni, pos, dirent, (ntfs_filldir_t) list_dir_entry); 411987da915Sopenharmony_ci 412987da915Sopenharmony_ci if (result == 0) { 413987da915Sopenharmony_ci ntfs_list_add_tail(&comp.list, &paths.list); 414987da915Sopenharmony_ci 415987da915Sopenharmony_ci /* for each of ni's sub-dirs: list in this iteration, then 416987da915Sopenharmony_ci free at the top of the next iteration or outside of loop */ 417987da915Sopenharmony_ci ntfs_list_for_each(dir_walker, &dirs.list) { 418987da915Sopenharmony_ci if (tofree) { 419987da915Sopenharmony_ci free_dir(tofree); 420987da915Sopenharmony_ci tofree = NULL; 421987da915Sopenharmony_ci } 422987da915Sopenharmony_ci subdir = ntfs_list_entry(dir_walker, struct dir, list); 423987da915Sopenharmony_ci 424987da915Sopenharmony_ci /* subdir is not a subdir of ni */ 425987da915Sopenharmony_ci if (subdir->depth != ni_depth + 1) 426987da915Sopenharmony_ci break; 427987da915Sopenharmony_ci 428987da915Sopenharmony_ci pos2 = 0; 429987da915Sopenharmony_ci dir_list_insert_pos = &dirs.list; 430987da915Sopenharmony_ci if (!subdir->ni) { 431987da915Sopenharmony_ci subdir->ni = 432987da915Sopenharmony_ci ntfs_pathname_to_inode(ni->vol, ni, 433987da915Sopenharmony_ci subdir->name); 434987da915Sopenharmony_ci 435987da915Sopenharmony_ci if (!subdir->ni) { 436987da915Sopenharmony_ci ntfs_log_error 437987da915Sopenharmony_ci ("ntfsls::readdir_recursive(): cannot get inode from pathname.\n"); 438987da915Sopenharmony_ci result = -1; 439987da915Sopenharmony_ci break; 440987da915Sopenharmony_ci } 441987da915Sopenharmony_ci } 442987da915Sopenharmony_ci puts(""); 443987da915Sopenharmony_ci 444987da915Sopenharmony_ci comp.name = subdir->name; 445987da915Sopenharmony_ci 446987da915Sopenharmony_ci /* print relative path header */ 447987da915Sopenharmony_ci ntfs_list_for_each(comp_walker, &paths.list) { 448987da915Sopenharmony_ci tempcomp = 449987da915Sopenharmony_ci ntfs_list_entry(comp_walker, 450987da915Sopenharmony_ci struct path_component, list); 451987da915Sopenharmony_ci printf("%s", tempcomp->name); 452987da915Sopenharmony_ci if (tempcomp != &comp 453987da915Sopenharmony_ci && *tempcomp->name != PATH_SEP 454987da915Sopenharmony_ci && (!opts.classify 455987da915Sopenharmony_ci || tempcomp == &base_comp)) 456987da915Sopenharmony_ci putchar(PATH_SEP); 457987da915Sopenharmony_ci } 458987da915Sopenharmony_ci puts(":"); 459987da915Sopenharmony_ci 460987da915Sopenharmony_ci result = readdir_recursive(subdir->ni, &pos2, dirent); 461987da915Sopenharmony_ci 462987da915Sopenharmony_ci if (result) 463987da915Sopenharmony_ci break; 464987da915Sopenharmony_ci 465987da915Sopenharmony_ci tofree = subdir; 466987da915Sopenharmony_ci ntfs_list_del(dir_walker); 467987da915Sopenharmony_ci } 468987da915Sopenharmony_ci 469987da915Sopenharmony_ci ntfs_list_del(&comp.list); 470987da915Sopenharmony_ci } 471987da915Sopenharmony_ci 472987da915Sopenharmony_ci if (tofree) 473987da915Sopenharmony_ci free_dir(tofree); 474987da915Sopenharmony_ci 475987da915Sopenharmony_ci /* if at the outer-most readdir_recursive, then clean up */ 476987da915Sopenharmony_ci if (ni_depth == 0) { 477987da915Sopenharmony_ci free_dirs(&dirs.list); 478987da915Sopenharmony_ci } 479987da915Sopenharmony_ci 480987da915Sopenharmony_ci depth--; 481987da915Sopenharmony_ci 482987da915Sopenharmony_ci return result; 483987da915Sopenharmony_ci} 484987da915Sopenharmony_ci 485987da915Sopenharmony_ci/** 486987da915Sopenharmony_ci * list_dir_entry 487987da915Sopenharmony_ci * 488987da915Sopenharmony_ci * FIXME: Should we print errors as we go along? (AIA) 489987da915Sopenharmony_ci */ 490987da915Sopenharmony_cistatic int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name, 491987da915Sopenharmony_ci const int name_len, const int name_type, 492987da915Sopenharmony_ci const s64 pos __attribute__((unused)), 493987da915Sopenharmony_ci const MFT_REF mref, const unsigned dt_type) 494987da915Sopenharmony_ci{ 495987da915Sopenharmony_ci char *filename = NULL; 496987da915Sopenharmony_ci int result = 0; 497987da915Sopenharmony_ci 498987da915Sopenharmony_ci struct dir *dir = NULL; 499987da915Sopenharmony_ci 500987da915Sopenharmony_ci filename = calloc(1, MAX_PATH); 501987da915Sopenharmony_ci if (!filename) 502987da915Sopenharmony_ci return -1; 503987da915Sopenharmony_ci 504987da915Sopenharmony_ci if (ntfs_ucstombs(name, name_len, &filename, MAX_PATH) < 0) { 505987da915Sopenharmony_ci ntfs_log_error("Cannot represent filename in current locale.\n"); 506987da915Sopenharmony_ci goto free; 507987da915Sopenharmony_ci } 508987da915Sopenharmony_ci 509987da915Sopenharmony_ci result = 0; // These are successful 510987da915Sopenharmony_ci if ((MREF(mref) < FILE_first_user) && (!opts.system)) 511987da915Sopenharmony_ci goto free; 512987da915Sopenharmony_ci if (name_type == FILE_NAME_POSIX && !opts.all) 513987da915Sopenharmony_ci goto free; 514987da915Sopenharmony_ci if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_WIN32) && 515987da915Sopenharmony_ci opts.dos) 516987da915Sopenharmony_ci goto free; 517987da915Sopenharmony_ci if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_DOS) && 518987da915Sopenharmony_ci !opts.dos) 519987da915Sopenharmony_ci goto free; 520987da915Sopenharmony_ci if (dt_type == NTFS_DT_DIR && opts.classify) 521987da915Sopenharmony_ci sprintf(filename + strlen(filename), "/"); 522987da915Sopenharmony_ci 523987da915Sopenharmony_ci if (dt_type == NTFS_DT_DIR && opts.recursive 524987da915Sopenharmony_ci && strcmp(filename, ".") && strcmp(filename, "./") 525987da915Sopenharmony_ci && strcmp(filename, "..") && strcmp(filename, "../")) 526987da915Sopenharmony_ci { 527987da915Sopenharmony_ci dir = (struct dir *)calloc(1, sizeof(struct dir)); 528987da915Sopenharmony_ci 529987da915Sopenharmony_ci if (!dir) { 530987da915Sopenharmony_ci ntfs_log_error("Failed to allocate for subdir.\n"); 531987da915Sopenharmony_ci result = -1; 532987da915Sopenharmony_ci goto free; 533987da915Sopenharmony_ci } 534987da915Sopenharmony_ci 535987da915Sopenharmony_ci strcpy(dir->name, filename); 536987da915Sopenharmony_ci dir->ni = NULL; 537987da915Sopenharmony_ci dir->depth = depth; 538987da915Sopenharmony_ci } 539987da915Sopenharmony_ci 540987da915Sopenharmony_ci if (!opts.lng) { 541987da915Sopenharmony_ci if (!opts.inode) 542987da915Sopenharmony_ci printf("%s\n", filename); 543987da915Sopenharmony_ci else 544987da915Sopenharmony_ci printf("%7llu %s\n", (unsigned long long)MREF(mref), 545987da915Sopenharmony_ci filename); 546987da915Sopenharmony_ci result = 0; 547987da915Sopenharmony_ci } else { 548987da915Sopenharmony_ci s64 filesize = 0; 549987da915Sopenharmony_ci ntfs_inode *ni; 550987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx = NULL; 551987da915Sopenharmony_ci FILE_NAME_ATTR *file_name_attr; 552987da915Sopenharmony_ci ATTR_RECORD *attr; 553987da915Sopenharmony_ci struct timespec change_time; 554987da915Sopenharmony_ci char t_buf[26]; 555987da915Sopenharmony_ci 556987da915Sopenharmony_ci result = -1; // Everything else is bad 557987da915Sopenharmony_ci 558987da915Sopenharmony_ci ni = ntfs_inode_open(dirent->vol, mref); 559987da915Sopenharmony_ci if (!ni) 560987da915Sopenharmony_ci goto release; 561987da915Sopenharmony_ci 562987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(ni, NULL); 563987da915Sopenharmony_ci if (!ctx) 564987da915Sopenharmony_ci goto release; 565987da915Sopenharmony_ci 566987da915Sopenharmony_ci if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 567987da915Sopenharmony_ci 0, ctx)) 568987da915Sopenharmony_ci goto release; 569987da915Sopenharmony_ci attr = ctx->attr; 570987da915Sopenharmony_ci 571987da915Sopenharmony_ci file_name_attr = (FILE_NAME_ATTR *)((char *)attr + 572987da915Sopenharmony_ci le16_to_cpu(attr->value_offset)); 573987da915Sopenharmony_ci if (!file_name_attr) 574987da915Sopenharmony_ci goto release; 575987da915Sopenharmony_ci 576987da915Sopenharmony_ci change_time = ntfs2timespec(file_name_attr->last_data_change_time); 577987da915Sopenharmony_ci strcpy(t_buf, ctime(&change_time.tv_sec)); 578987da915Sopenharmony_ci memmove(t_buf+16, t_buf+19, 5); 579987da915Sopenharmony_ci t_buf[21] = '\0'; 580987da915Sopenharmony_ci 581987da915Sopenharmony_ci if (dt_type != NTFS_DT_DIR) { 582987da915Sopenharmony_ci if (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, 583987da915Sopenharmony_ci NULL, 0, ctx)) 584987da915Sopenharmony_ci filesize = ntfs_get_attribute_value_length( 585987da915Sopenharmony_ci ctx->attr); 586987da915Sopenharmony_ci } 587987da915Sopenharmony_ci 588987da915Sopenharmony_ci if (opts.inode) 589987da915Sopenharmony_ci printf("%7llu %8lld %s %s\n", 590987da915Sopenharmony_ci (unsigned long long)MREF(mref), 591987da915Sopenharmony_ci (long long)filesize, t_buf + 4, 592987da915Sopenharmony_ci filename); 593987da915Sopenharmony_ci else 594987da915Sopenharmony_ci printf("%8lld %s %s\n", (long long)filesize, t_buf + 4, 595987da915Sopenharmony_ci filename); 596987da915Sopenharmony_ci 597987da915Sopenharmony_ci if (dir) { 598987da915Sopenharmony_ci dir->ni = ni; 599987da915Sopenharmony_ci ni = NULL; /* so release does not close inode */ 600987da915Sopenharmony_ci } 601987da915Sopenharmony_ci 602987da915Sopenharmony_ci result = 0; 603987da915Sopenharmony_cirelease: 604987da915Sopenharmony_ci /* Release attribute search context and close the inode. */ 605987da915Sopenharmony_ci if (ctx) 606987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 607987da915Sopenharmony_ci if (ni) 608987da915Sopenharmony_ci ntfs_inode_close(ni); 609987da915Sopenharmony_ci } 610987da915Sopenharmony_ci 611987da915Sopenharmony_ci if (dir) { 612987da915Sopenharmony_ci if (result == 0) { 613987da915Sopenharmony_ci ntfs_list_add(&dir->list, dir_list_insert_pos); 614987da915Sopenharmony_ci dir_list_insert_pos = &dir->list; 615987da915Sopenharmony_ci } else { 616987da915Sopenharmony_ci free(dir); 617987da915Sopenharmony_ci dir = NULL; 618987da915Sopenharmony_ci } 619987da915Sopenharmony_ci } 620987da915Sopenharmony_ci 621987da915Sopenharmony_cifree: 622987da915Sopenharmony_ci free(filename); 623987da915Sopenharmony_ci return result; 624987da915Sopenharmony_ci} 625987da915Sopenharmony_ci 626987da915Sopenharmony_ci/** 627987da915Sopenharmony_ci * main - Begin here 628987da915Sopenharmony_ci * 629987da915Sopenharmony_ci * Start from here. 630987da915Sopenharmony_ci * 631987da915Sopenharmony_ci * Return: 0 Success, the program worked 632987da915Sopenharmony_ci * 1 Error, parsing mount options failed 633987da915Sopenharmony_ci * 2 Error, mount attempt failed 634987da915Sopenharmony_ci * 3 Error, failed to open root directory 635987da915Sopenharmony_ci * 4 Error, failed to open directory in search path 636987da915Sopenharmony_ci */ 637987da915Sopenharmony_ciint main(int argc, char **argv) 638987da915Sopenharmony_ci{ 639987da915Sopenharmony_ci s64 pos; 640987da915Sopenharmony_ci ntfs_volume *vol; 641987da915Sopenharmony_ci ntfs_inode *ni; 642987da915Sopenharmony_ci ntfsls_dirent dirent; 643987da915Sopenharmony_ci 644987da915Sopenharmony_ci ntfs_log_set_handler(ntfs_log_handler_outerr); 645987da915Sopenharmony_ci 646987da915Sopenharmony_ci if (!parse_options(argc, argv)) { 647987da915Sopenharmony_ci // FIXME: Print error... (AIA) 648987da915Sopenharmony_ci return 1; 649987da915Sopenharmony_ci } 650987da915Sopenharmony_ci 651987da915Sopenharmony_ci utils_set_locale(); 652987da915Sopenharmony_ci 653987da915Sopenharmony_ci vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | 654987da915Sopenharmony_ci (opts.force ? NTFS_MNT_RECOVER : 0)); 655987da915Sopenharmony_ci if (!vol) { 656987da915Sopenharmony_ci // FIXME: Print error... (AIA) 657987da915Sopenharmony_ci return 2; 658987da915Sopenharmony_ci } 659987da915Sopenharmony_ci 660987da915Sopenharmony_ci ni = ntfs_pathname_to_inode(vol, NULL, opts.path); 661987da915Sopenharmony_ci if (!ni) { 662987da915Sopenharmony_ci // FIXME: Print error... (AIA) 663987da915Sopenharmony_ci ntfs_umount(vol, FALSE); 664987da915Sopenharmony_ci return 3; 665987da915Sopenharmony_ci } 666987da915Sopenharmony_ci 667987da915Sopenharmony_ci /* 668987da915Sopenharmony_ci * We now are at the final path component. If it is a file just 669987da915Sopenharmony_ci * list it. If it is a directory, list its contents. 670987da915Sopenharmony_ci */ 671987da915Sopenharmony_ci pos = 0; 672987da915Sopenharmony_ci memset(&dirent, 0, sizeof(dirent)); 673987da915Sopenharmony_ci dirent.vol = vol; 674987da915Sopenharmony_ci if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { 675987da915Sopenharmony_ci if (opts.recursive) 676987da915Sopenharmony_ci readdir_recursive(ni, &pos, &dirent); 677987da915Sopenharmony_ci else 678987da915Sopenharmony_ci ntfs_readdir(ni, &pos, &dirent, 679987da915Sopenharmony_ci (ntfs_filldir_t) list_dir_entry); 680987da915Sopenharmony_ci // FIXME: error checking... (AIA) 681987da915Sopenharmony_ci } else { 682987da915Sopenharmony_ci ATTR_RECORD *rec; 683987da915Sopenharmony_ci FILE_NAME_ATTR *attr; 684987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 685987da915Sopenharmony_ci int space = 4; 686987da915Sopenharmony_ci ntfschar *name = NULL; 687987da915Sopenharmony_ci int name_len = 0;; 688987da915Sopenharmony_ci 689987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(ni, NULL); 690987da915Sopenharmony_ci if (!ctx) 691987da915Sopenharmony_ci return -1; 692987da915Sopenharmony_ci 693987da915Sopenharmony_ci while ((rec = find_attribute(AT_FILE_NAME, ctx))) { 694987da915Sopenharmony_ci /* We know this will always be resident. */ 695987da915Sopenharmony_ci attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset)); 696987da915Sopenharmony_ci 697987da915Sopenharmony_ci if (attr->file_name_type < space) { 698987da915Sopenharmony_ci name = attr->file_name; 699987da915Sopenharmony_ci name_len = attr->file_name_length; 700987da915Sopenharmony_ci space = attr->file_name_type; 701987da915Sopenharmony_ci } 702987da915Sopenharmony_ci } 703987da915Sopenharmony_ci 704987da915Sopenharmony_ci list_dir_entry(&dirent, name, name_len, space, pos, ni->mft_no, 705987da915Sopenharmony_ci NTFS_DT_REG); 706987da915Sopenharmony_ci // FIXME: error checking... (AIA) 707987da915Sopenharmony_ci 708987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 709987da915Sopenharmony_ci } 710987da915Sopenharmony_ci 711987da915Sopenharmony_ci /* Finished with the inode; release it. */ 712987da915Sopenharmony_ci ntfs_inode_close(ni); 713987da915Sopenharmony_ci 714987da915Sopenharmony_ci ntfs_umount(vol, FALSE); 715987da915Sopenharmony_ci return 0; 716987da915Sopenharmony_ci} 717987da915Sopenharmony_ci 718