1N/A/**
1N/A * ntfsls - Part of the Linux-NTFS project.
1N/A *
1N/A * Copyright (c) 2003 Lode Leroy
1N/A * Copyright (c) 2003-2005 Anton Altaparmakov
1N/A * Copyright (c) 2003 Richard Russon
1N/A * Copyright (c) 2004 Carmelo Kintana
1N/A * Copyright (c) 2004 Giang Nguyen
1N/A *
1N/A * This utility will list a directory's files.
1N/A *
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 *
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 *
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/A */
1N/A#include "config.h"
1N/A
1N/A#ifdef HAVE_STDIO_H
1N/A#include <stdio.h>
1N/A#endif
1N/A#ifdef HAVE_STDLIB_H
1N/A#include <stdlib.h>
1N/A#endif
1N/A#ifdef HAVE_TIME_H
1N/A#include <time.h>
1N/A#endif
1N/A#ifdef HAVE_GETOPT_H
1N/A#include <getopt.h>
1N/A#endif
1N/A#ifdef HAVE_STRING_H
1N/A#include <string.h>
1N/A#endif
1N/A
1N/A#include "compat.h"
1N/A#include "types.h"
1N/A#include "mft.h"
1N/A#include "attrib.h"
1N/A#include "layout.h"
1N/A#include "inode.h"
1N/A#include "utils.h"
1N/A#include "dir.h"
1N/A#include "list.h"
1N/A#include "ntfstime.h"
1N/A#include "version.h"
1N/A#include "logging.h"
1N/A
1N/Astatic const char *EXEC_NAME = "ntfsls";
1N/A
1N/A/**
1N/A * To hold sub-directory information for recursive listing.
1N/A * @depth: the level of this dir relative to opts.path
1N/A */
1N/Astruct dir {
1N/A struct list_head list;
1N/A ntfs_inode *ni;
1N/A char name[MAX_PATH];
1N/A int depth;
1N/A};
1N/A
1N/A/**
1N/A * path_component - to store path component strings
1N/A *
1N/A * @name: string pointer
1N/A *
1N/A * NOTE: @name is not directly allocated memory. It simply points to the
1N/A * character array name in struct dir.
1N/A */
1N/Astruct path_component {
1N/A struct list_head list;
1N/A const char *name;
1N/A};
1N/A
1N/A/* The list of sub-dirs is like a "horizontal" tree. The root of
1N/A * the tree is opts.path, but it is not part of the list because
1N/A * that's not necessary. The rules of the list are (in order of
1N/A * precedence):
1N/A * 1. directories immediately follow their parent.
1N/A * 2. siblings are next to one another.
1N/A *
1N/A * For example, if:
1N/A * 1. opts.path is /
1N/A * 2. / has 2 sub-dirs: dir1 and dir2
1N/A * 3. dir1 has 2 sub-dirs: dir11 and dir12
1N/A * 4. dir2 has 0 sub-dirs
1N/A * then the list will be:
1N/A * dummy head -> dir1 -> dir11 -> dir12 -> dir2
1N/A *
1N/A * dir_list_insert_pos keeps track of where to insert a sub-dir
1N/A * into the list.
1N/A */
1N/Astatic struct list_head *dir_list_insert_pos = NULL;
1N/A
1N/A/* The global depth relative to opts.path.
1N/A * ie: opts.path has depth 0, a sub-dir of opts.path has depth 1
1N/A */
1N/Astatic int depth = 0;
1N/A
1N/Astatic struct options {
1N/A char *device; /* Device/File to work with */
1N/A int quiet; /* Less output */
1N/A int verbose; /* Extra output */
1N/A int force; /* Override common sense */
1N/A int all;
1N/A int system;
1N/A int dos;
1N/A int lng;
1N/A int inode;
1N/A int classify;
1N/A int recursive;
1N/A const char *path;
1N/A} opts;
1N/A
1N/Atypedef struct {
1N/A ntfs_volume *vol;
1N/A} ntfsls_dirent;
1N/A
1N/Astatic int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name,
1N/A const int name_len, const int name_type,
1N/A const s64 pos, const MFT_REF mref,
1N/A const unsigned dt_type);
1N/A
1N/A/**
1N/A * version - Print version information about the program
1N/A *
1N/A * Print a copyright statement and a brief description of the program.
1N/A *
1N/A * Return: none
1N/A */
1N/Astatic void version(void)
1N/A{
1N/A printf("\n%s v%s (libntfs %s) - Display information about an NTFS "
1N/A "Volume.\n\n", EXEC_NAME, VERSION,
1N/A ntfs_libntfs_version());
1N/A printf("Copyright (c) 2003 Lode Leroy\n");
1N/A printf("Copyright (c) 2003-2005 Anton Altaparmakov\n");
1N/A printf("Copyright (c) 2003 Richard Russon\n");
1N/A printf("Copyright (c) 2004 Carmelo Kintana\n");
1N/A printf("Copyright (c) 2004 Giang Nguyen\n");
1N/A printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
1N/A}
1N/A
1N/A/**
1N/A * usage - Print a list of the parameters to the program
1N/A *
1N/A * Print a list of the parameters and options for the program.
1N/A *
1N/A * Return: none
1N/A */
1N/Astatic void usage(void)
1N/A{
1N/A printf("\nUsage: %s [options] device\n"
1N/A "\n"
1N/A " -a, --all Display all files\n"
1N/A " -F, --classify Display classification\n"
1N/A " -f, --force Use less caution\n"
1N/A " -h, --help Display this help\n"
1N/A " -i, --inode Display inode numbers\n"
1N/A " -l, --long Display long info\n"
1N/A " -p, --path PATH Directory whose contents to list\n"
1N/A " -q, --quiet Less output\n"
1N/A " -R, --recursive Recursively list subdirectories\n"
1N/A " -s, --system Display system files\n"
1N/A " -V, --version Display version information\n"
1N/A " -v, --verbose More output\n"
1N/A " -x, --dos Use short (DOS 8.3) names\n"
1N/A "\n",
1N/A EXEC_NAME);
1N/A
1N/A printf("NOTE: If neither -a nor -s is specified, the program defaults to -a.\n\n");
1N/A
1N/A printf("%s%s\n", ntfs_bugs, ntfs_home);
1N/A}
1N/A
1N/A/**
1N/A * parse_options - Read and validate the programs command line
1N/A *
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 *
1N/A * Return: 1 Success
1N/A * 0 Error, one or more problems
1N/A */
1N/Astatic int parse_options(int argc, char *argv[])
1N/A{
1N/A static const char *sopt = "-aFfh?ilp:qRsVvx";
1N/A static const struct option lopt[] = {
1N/A { "all", no_argument, NULL, 'a' },
1N/A { "classify", no_argument, NULL, 'F' },
1N/A { "force", no_argument, NULL, 'f' },
1N/A { "help", no_argument, NULL, 'h' },
1N/A { "inode", no_argument, NULL, 'i' },
1N/A { "long", no_argument, NULL, 'l' },
1N/A { "path", required_argument, NULL, 'p' },
1N/A { "recursive", no_argument, NULL, 'R' },
1N/A { "quiet", no_argument, NULL, 'q' },
1N/A { "system", no_argument, NULL, 's' },
1N/A { "version", no_argument, NULL, 'V' },
1N/A { "verbose", no_argument, NULL, 'v' },
1N/A { "dos", no_argument, NULL, 'x' },
1N/A { NULL, 0, NULL, 0 },
1N/A };
1N/A
1N/A int c = -1;
1N/A int err = 0;
1N/A int ver = 0;
1N/A int help = 0;
1N/A int levels = 0;
1N/A
1N/A opterr = 0; /* We'll handle the errors, thank you. */
1N/A
1N/A memset(&opts, 0, sizeof(opts));
1N/A opts.device = NULL;
1N/A opts.path = "/";
1N/A
1N/A while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
1N/A switch (c) {
1N/A case 1:
1N/A if (!opts.device)
1N/A opts.device = optarg;
1N/A else
1N/A err++;
1N/A break;
1N/A case 'p':
1N/A opts.path = optarg;
1N/A break;
1N/A case 'f':
1N/A opts.force++;
1N/A break;
1N/A case 'h':
1N/A case '?':
1N/A if (strncmp (argv[optind-1], "--log-", 6) == 0) {
1N/A if (!ntfs_log_parse_option (argv[optind-1]))
1N/A err++;
1N/A break;
1N/A }
1N/A help++;
1N/A break;
1N/A case 'q':
1N/A opts.quiet++;
1N/A ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
1N/A break;
1N/A case 'v':
1N/A opts.verbose++;
1N/A ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
1N/A break;
1N/A case 'V':
1N/A ver++;
1N/A break;
1N/A case 'x':
1N/A opts.dos = 1;
1N/A break;
1N/A case 'l':
1N/A opts.lng++;
1N/A break;
1N/A case 'i':
1N/A opts.inode++;
1N/A break;
1N/A case 'F':
1N/A opts.classify++;
1N/A break;
1N/A case 'a':
1N/A opts.all++;
1N/A break;
1N/A case 's':
1N/A opts.system++;
1N/A break;
1N/A case 'R':
1N/A opts.recursive++;
1N/A break;
1N/A default:
1N/A ntfs_log_error("Unknown option '%s'.\n", argv[optind - 1]);
1N/A err++;
1N/A break;
1N/A }
1N/A }
1N/A
1N/A /* Make sure we're in sync with the log levels */
1N/A levels = ntfs_log_get_levels();
1N/A if (levels & NTFS_LOG_LEVEL_VERBOSE)
1N/A opts.verbose++;
1N/A if (!(levels & NTFS_LOG_LEVEL_QUIET))
1N/A opts.quiet++;
1N/A
1N/A /* defaults to -a if -s is not specified */
1N/A if (!opts.system)
1N/A opts.all++;
1N/A
1N/A if (help || ver)
1N/A opts.quiet = 0;
1N/A else {
1N/A if (opts.device == NULL) {
1N/A if (argc > 1)
1N/A ntfs_log_error("You must specify exactly one "
1N/A "device.\n");
1N/A err++;
1N/A }
1N/A
1N/A if (opts.quiet && opts.verbose) {
1N/A ntfs_log_error("You may not use --quiet and --verbose at the "
1N/A "same time.\n");
1N/A err++;
1N/A }
1N/A }
1N/A
1N/A if (ver)
1N/A version();
1N/A if (help || err)
1N/A usage();
1N/A
1N/A return (!err && !help && !ver);
1N/A}
1N/A
1N/A/**
1N/A * free_dir - free one dir
1N/A * @tofree: the dir to free
1N/A *
1N/A * Close the inode and then free the dir
1N/A */
1N/Astatic void free_dir(struct dir *tofree)
1N/A{
1N/A if (tofree) {
1N/A if (tofree->ni) {
1N/A ntfs_inode_close(tofree->ni);
1N/A tofree->ni = NULL;
1N/A }
1N/A free(tofree);
1N/A }
1N/A}
1N/A
1N/A/**
1N/A * free_dirs - walk the list of dir's and free each of them
1N/A * @dir_list: the list_head of any entry in the list
1N/A *
1N/A * Iterate over @dir_list, calling free_dir on each entry
1N/A */
1N/Astatic void free_dirs(struct list_head *dir_list)
1N/A{
1N/A struct dir *tofree = NULL;
1N/A struct list_head *walker = NULL;
1N/A
1N/A if (dir_list) {
1N/A list_for_each(walker, dir_list) {
1N/A free_dir(tofree);
1N/A tofree = list_entry(walker, struct dir, list);
1N/A }
1N/A
1N/A free_dir(tofree);
1N/A }
1N/A}
1N/A
1N/A/**
1N/A * readdir_recursive - list a directory and sub-directories encountered
1N/A * @ni: ntfs inode of the directory to list
1N/A * @pos: current position in directory
1N/A * @dirent: context for filldir callback supplied by the caller
1N/A *
1N/A * For each directory, print its path relative to opts.path. List a directory,
1N/A * then list each of its sub-directories.
1N/A *
1N/A * Returns 0 on success or -1 on error.
1N/A *
1N/A * NOTE: Assumes recursive option. Currently no limit on the depths of
1N/A * recursion.
1N/A */
1N/Astatic int readdir_recursive(ntfs_inode * ni, s64 * pos, ntfsls_dirent * dirent)
1N/A{
1N/A /* list of dirs to "ls" recursively */
1N/A static struct dir dirs = {
1N/A .list = LIST_HEAD_INIT(dirs.list),
1N/A .ni = NULL,
1N/A .name = {0},
1N/A .depth = 0
1N/A };
1N/A
1N/A static struct path_component paths = {
1N/A .list = LIST_HEAD_INIT(paths.list),
1N/A .name = NULL
1N/A };
1N/A
1N/A static struct path_component base_comp;
1N/A
1N/A struct dir *subdir = NULL;
1N/A struct dir *tofree = NULL;
1N/A struct path_component comp;
1N/A struct path_component *tempcomp = NULL;
1N/A struct list_head *dir_walker = NULL;
1N/A struct list_head *comp_walker = NULL;
1N/A s64 pos2 = 0;
1N/A int ni_depth = depth;
1N/A int result = 0;
1N/A
1N/A if (list_empty(&dirs.list)) {
1N/A base_comp.name = opts.path;
1N/A list_add(&base_comp.list, &paths.list);
1N/A dir_list_insert_pos = &dirs.list;
1N/A printf("%s:\n", opts.path);
1N/A }
1N/A
1N/A depth++;
1N/A
1N/A result = ntfs_readdir(ni, pos, dirent, (ntfs_filldir_t) list_dir_entry);
1N/A
1N/A if (result == 0) {
1N/A list_add_tail(&comp.list, &paths.list);
1N/A
1N/A /* for each of ni's sub-dirs: list in this iteration, then
1N/A free at the top of the next iteration or outside of loop */
1N/A list_for_each(dir_walker, &dirs.list) {
1N/A if (tofree) {
1N/A free_dir(tofree);
1N/A tofree = NULL;
1N/A }
1N/A subdir = list_entry(dir_walker, struct dir, list);
1N/A
1N/A /* subdir is not a subdir of ni */
1N/A if (subdir->depth != ni_depth + 1)
1N/A break;
1N/A
1N/A pos2 = 0;
1N/A dir_list_insert_pos = &dirs.list;
1N/A if (!subdir->ni) {
1N/A subdir->ni =
1N/A ntfs_pathname_to_inode(ni->vol, ni,
1N/A subdir->name);
1N/A
1N/A if (!subdir->ni) {
1N/A ntfs_log_error
1N/A ("ntfsls::readdir_recursive(): cannot get inode from pathname.\n");
1N/A result = -1;
1N/A break;
1N/A }
1N/A }
1N/A puts("");
1N/A
1N/A comp.name = subdir->name;
1N/A
1N/A /* print relative path header */
1N/A list_for_each(comp_walker, &paths.list) {
1N/A tempcomp =
1N/A list_entry(comp_walker,
1N/A struct path_component, list);
1N/A printf("%s", tempcomp->name);
1N/A if (tempcomp != &comp
1N/A && *tempcomp->name != PATH_SEP
1N/A && (!opts.classify
1N/A || tempcomp == &base_comp))
1N/A putchar(PATH_SEP);
1N/A }
1N/A puts(":");
1N/A
1N/A result = readdir_recursive(subdir->ni, &pos2, dirent);
1N/A
1N/A if (result)
1N/A break;
1N/A
1N/A tofree = subdir;
1N/A list_del(dir_walker);
1N/A }
1N/A
1N/A list_del(&comp.list);
1N/A }
1N/A
1N/A if (tofree)
1N/A free_dir(tofree);
1N/A
1N/A /* if at the outer-most readdir_recursive, then clean up */
1N/A if (ni_depth == 0) {
1N/A free_dirs(&dirs.list);
1N/A }
1N/A
1N/A depth--;
1N/A
1N/A return result;
1N/A}
1N/A
1N/A/**
1N/A * list_dir_entry
1N/A *
1N/A * FIXME: Should we print errors as we go along? (AIA)
1N/A */
1N/Astatic int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name,
1N/A const int name_len, const int name_type,
1N/A const s64 pos __attribute__((unused)),
1N/A const MFT_REF mref, const unsigned dt_type)
1N/A{
1N/A char *filename = NULL;
1N/A int result = 0;
1N/A
1N/A struct dir *dir = NULL;
1N/A
1N/A filename = calloc(1, MAX_PATH);
1N/A if (!filename)
1N/A return -1;
1N/A
1N/A if (ntfs_ucstombs(name, name_len, &filename, MAX_PATH) < 0) {
1N/A ntfs_log_error("Cannot represent filename in current locale.\n");
1N/A goto free;
1N/A }
1N/A
1N/A result = 0; // These are successful
1N/A if ((MREF(mref) < FILE_first_user) && (!opts.system))
1N/A goto free;
1N/A if (name_type == FILE_NAME_POSIX && !opts.all)
1N/A goto free;
1N/A if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_WIN32) &&
1N/A opts.dos)
1N/A goto free;
1N/A if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_DOS) &&
1N/A !opts.dos)
1N/A goto free;
1N/A if (dt_type == NTFS_DT_DIR && opts.classify)
1N/A sprintf(filename + strlen(filename), "/");
1N/A
1N/A if (dt_type == NTFS_DT_DIR && opts.recursive
1N/A && strcmp(filename, ".") && strcmp(filename, "./")
1N/A && strcmp(filename, "..") && strcmp(filename, "../"))
1N/A {
1N/A dir = (struct dir *)calloc(1, sizeof(struct dir));
1N/A
1N/A if (!dir) {
1N/A ntfs_log_error("Failed to allocate for subdir.\n");
1N/A result = -1;
1N/A goto free;
1N/A }
1N/A
1N/A strcpy(dir->name, filename);
1N/A dir->ni = NULL;
1N/A dir->depth = depth;
1N/A }
1N/A
1N/A if (!opts.lng) {
1N/A if (!opts.inode)
1N/A printf("%s\n", filename);
1N/A else
1N/A printf("%7llu %s\n", (unsigned long long)MREF(mref),
1N/A filename);
1N/A result = 0;
1N/A } else {
1N/A s64 filesize = 0;
1N/A ntfs_inode *ni;
1N/A ntfs_attr_search_ctx *ctx = NULL;
1N/A FILE_NAME_ATTR *file_name_attr;
1N/A ATTR_RECORD *attr;
1N/A time_t ntfs_time;
1N/A char t_buf[26];
1N/A
1N/A result = -1; // Everything else is bad
1N/A
1N/A ni = ntfs_inode_open(dirent->vol, mref);
1N/A if (!ni)
1N/A goto release;
1N/A
1N/A ctx = ntfs_attr_get_search_ctx(ni, NULL);
1N/A if (!ctx)
1N/A goto release;
1N/A
1N/A if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL,
1N/A 0, ctx))
1N/A goto release;
1N/A attr = ctx->attr;
1N/A
1N/A file_name_attr = (FILE_NAME_ATTR *)((char *)attr +
1N/A le16_to_cpu(attr->u.res.value_offset));
1N/A if (!file_name_attr)
1N/A goto release;
1N/A
1N/A ntfs_time = ntfs2utc(file_name_attr->last_data_change_time);
1N/A strcpy(t_buf, ctime(&ntfs_time));
1N/A memmove(t_buf+16, t_buf+19, 5);
1N/A t_buf[21] = '\0';
1N/A
1N/A if (dt_type != NTFS_DT_DIR) {
1N/A if (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0,
1N/A NULL, 0, ctx))
1N/A filesize = ntfs_get_attribute_value_length(
1N/A ctx->attr);
1N/A }
1N/A
1N/A if (opts.inode)
1N/A printf("%7llu %8lld %s %s\n",
1N/A (unsigned long long)MREF(mref),
1N/A (long long)filesize, t_buf + 4,
1N/A filename);
1N/A else
1N/A printf("%8lld %s %s\n", (long long)filesize, t_buf + 4,
1N/A filename);
1N/A
1N/A if (dir) {
1N/A dir->ni = ni;
1N/A ni = NULL; /* so release does not close inode */
1N/A }
1N/A
1N/A result = 0;
1N/Arelease:
1N/A /* Release attribute search context and close the inode. */
1N/A if (ctx)
1N/A ntfs_attr_put_search_ctx(ctx);
1N/A if (ni)
1N/A ntfs_inode_close(ni);
1N/A }
1N/A
1N/A if (dir) {
1N/A if (result == 0) {
1N/A list_add(&dir->list, dir_list_insert_pos);
1N/A dir_list_insert_pos = &dir->list;
1N/A } else {
1N/A free(dir);
1N/A dir = NULL;
1N/A }
1N/A }
1N/A
1N/Afree:
1N/A free(filename);
1N/A return result;
1N/A}
1N/A
1N/A/**
1N/A * main - Begin here
1N/A *
1N/A * Start from here.
1N/A *
1N/A * Return: 0 Success, the program worked
1N/A * 1 Error, parsing mount options failed
1N/A * 2 Error, mount attempt failed
1N/A * 3 Error, failed to open root directory
1N/A * 4 Error, failed to open directory in search path
1N/A */
1N/Aint main(int argc, char **argv)
1N/A{
1N/A s64 pos;
1N/A ntfs_volume *vol;
1N/A ntfs_inode *ni;
1N/A ntfsls_dirent dirent;
1N/A
1N/A ntfs_log_set_handler(ntfs_log_handler_outerr);
1N/A
1N/A if (!parse_options(argc, argv)) {
1N/A // FIXME: Print error... (AIA)
1N/A return 1;
1N/A }
1N/A
1N/A utils_set_locale();
1N/A
1N/A vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY |
1N/A (opts.force ? NTFS_MNT_FORCE : 0));
1N/A if (!vol) {
1N/A // FIXME: Print error... (AIA)
1N/A return 2;
1N/A }
1N/A
1N/A ni = ntfs_pathname_to_inode(vol, NULL, opts.path);
1N/A if (!ni) {
1N/A // FIXME: Print error... (AIA)
1N/A ntfs_umount(vol, FALSE);
1N/A return 3;
1N/A }
1N/A
1N/A /*
1N/A * We now are at the final path component. If it is a file just
1N/A * list it. If it is a directory, list its contents.
1N/A */
1N/A pos = 0;
1N/A memset(&dirent, 0, sizeof(dirent));
1N/A dirent.vol = vol;
1N/A if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1N/A if (opts.recursive)
1N/A readdir_recursive(ni, &pos, &dirent);
1N/A else
1N/A ntfs_readdir(ni, &pos, &dirent,
1N/A (ntfs_filldir_t) list_dir_entry);
1N/A // FIXME: error checking... (AIA)
1N/A } else {
1N/A ATTR_RECORD *rec;
1N/A FILE_NAME_ATTR *attr;
1N/A ntfs_attr_search_ctx *ctx;
1N/A int space = 4;
1N/A ntfschar *name = NULL;
1N/A int name_len = 0;;
1N/A
1N/A ctx = ntfs_attr_get_search_ctx(ni, NULL);
1N/A if (!ctx)
1N/A return -1;
1N/A
1N/A while ((rec = find_attribute(AT_FILE_NAME, ctx))) {
1N/A /* We know this will always be resident. */
1N/A attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->u.res.value_offset));
1N/A
1N/A if (attr->file_name_type < space) {
1N/A name = attr->file_name;
1N/A name_len = attr->file_name_length;
1N/A space = attr->file_name_type;
1N/A }
1N/A }
1N/A
1N/A list_dir_entry(&dirent, name, name_len, space, pos, ni->mft_no,
1N/A NTFS_DT_REG);
1N/A // FIXME: error checking... (AIA)
1N/A
1N/A ntfs_attr_put_search_ctx(ctx);
1N/A }
1N/A
1N/A /* Finished with the inode; release it. */
1N/A ntfs_inode_close(ni);
1N/A
1N/A ntfs_umount(vol, FALSE);
1N/A return 0;
1N/A}
1N/A