summaryrefslogtreecommitdiff
Diffstat
-rwxr-xr-xAndroid.mk138
-rwxr-xr-xAndroid.mk.bak89
-rwxr-xr-xCREDITS20
-rwxr-xr-xINSTALL200
-rwxr-xr-xMakefile715
-rwxr-xr-xMakefile.am106
-rwxr-xr-xMakefile.in955
-rwxr-xr-xNEWS4
-rwxr-xr-xREADME80
-rwxr-xr-xTODO.ntfsprogs126
-rwxr-xr-xaclocal.m47091
-rwxr-xr-xcompile21
-rwxr-xr-xconfig.guess292
-rw-r--r--[-rwxr-xr-x]config.h165
-rwxr-xr-xconfig.h.in110
-rwxr-xr-xconfig.log3290
-rwxr-xr-xconfig.status1220
-rwxr-xr-xconfig.sub104
-rwxr-xr-xconfigure26448
-rwxr-xr-xconfigure.ac291
-rwxr-xr-xdepcomp87
-rwxr-xr-xinclude/Makefile.in181
-rwxr-xr-xinclude/fuse-lite/Makefile.in112
-rwxr-xr-xinclude/fuse-lite/fuse.h61
-rwxr-xr-xinclude/fuse-lite/fuse_common.h49
-rwxr-xr-xinclude/fuse-lite/fuse_kernel.h6
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel.h20
-rwxr-xr-xinclude/ntfs-3g/Makefile.am4
-rwxr-xr-xinclude/ntfs-3g/Makefile.in163
-rwxr-xr-xinclude/ntfs-3g/acls.h3
-rwxr-xr-xinclude/ntfs-3g/attrib.h50
-rwxr-xr-xinclude/ntfs-3g/cache.h7
-rwxr-xr-xinclude/ntfs-3g/compat.h6
-rwxr-xr-xinclude/ntfs-3g/compress.h6
-rwxr-xr-xinclude/ntfs-3g/debug.h4
-rwxr-xr-xinclude/ntfs-3g/device.h18
-rwxr-xr-xinclude/ntfs-3g/device_io.h21
-rwxr-xr-xinclude/ntfs-3g/dir.h11
-rwxr-xr-xinclude/ntfs-3g/layout.h32
-rwxr-xr-xinclude/ntfs-3g/lcnalloc.h1
-rwxr-xr-xinclude/ntfs-3g/logging.h3
-rwxr-xr-xinclude/ntfs-3g/mst.h3
-rwxr-xr-xinclude/ntfs-3g/ntfstime.h12
-rwxr-xr-xinclude/ntfs-3g/param.h72
-rwxr-xr-xinclude/ntfs-3g/realpath.h24
-rwxr-xr-xinclude/ntfs-3g/runlist.h3
-rwxr-xr-xinclude/ntfs-3g/security.h20
-rwxr-xr-xinclude/ntfs-3g/types.h8
-rwxr-xr-xinclude/ntfs-3g/unistr.h13
-rwxr-xr-xinclude/ntfs-3g/volume.h78
-rwxr-xr-xinclude/ntfs-3g/xattrs.h75
-rwxr-xr-xinstall-sh5
-rwxr-xr-xlibfuse-lite/Makefile.am3
-rwxr-xr-xlibfuse-lite/Makefile.in188
-rwxr-xr-xlibfuse-lite/fuse.c418
-rwxr-xr-xlibfuse-lite/fuse_kern_chan.c2
-rwxr-xr-xlibfuse-lite/fuse_lowlevel.c53
-rwxr-xr-xlibfuse-lite/fuse_opt.c20
-rwxr-xr-xlibfuse-lite/fuse_session.c12
-rwxr-xr-xlibfuse-lite/fusermount.c97
-rwxr-xr-xlibfuse-lite/helper.c21
-rwxr-xr-xlibfuse-lite/mount.c486
-rwxr-xr-xlibfuse-lite/mount_util.c246
-rwxr-xr-xlibfuse-lite/mount_util.h11
-rwxr-xr-xlibntfs-3g/Makefile.am15
-rwxr-xr-xlibntfs-3g/Makefile.in420
-rwxr-xr-xlibntfs-3g/acls.c219
-rwxr-xr-xlibntfs-3g/attrib.c1205
-rwxr-xr-xlibntfs-3g/bootsect.c4
-rwxr-xr-xlibntfs-3g/cache.c7
-rwxr-xr-xlibntfs-3g/compress.c962
-rwxr-xr-xlibntfs-3g/device.c252
-rwxr-xr-xlibntfs-3g/dir.c374
-rwxr-xr-xlibntfs-3g/efs.c217
-rwxr-xr-xlibntfs-3g/index.c30
-rwxr-xr-xlibntfs-3g/inode.c46
-rwxr-xr-xlibntfs-3g/lcnalloc.c36
-rw-r--r--libntfs-3g/libntfs-3g.pc10
-rw-r--r--libntfs-3g/libntfs-3g.script.so2
-rwxr-xr-xlibntfs-3g/logfile.c23
-rwxr-xr-xlibntfs-3g/logging.c24
-rwxr-xr-xlibntfs-3g/mft.c12
-rwxr-xr-xlibntfs-3g/mst.c24
-rwxr-xr-xlibntfs-3g/object_id.c9
-rwxr-xr-xlibntfs-3g/realpath.c103
-rwxr-xr-xlibntfs-3g/reparse.c67
-rwxr-xr-xlibntfs-3g/runlist.c62
-rwxr-xr-xlibntfs-3g/security.c345
-rwxr-xr-xlibntfs-3g/unistr.c244
-rwxr-xr-xlibntfs-3g/unix_io.c19
-rwxr-xr-xlibntfs-3g/volume.c365
-rwxr-xr-xlibntfs-3g/win32_io.c708
-rwxr-xr-xlibntfs-3g/xattrs.c791
-rwxr-xr-xlibtool9301
-rwxr-xr-xltmain.sh8439
-rwxr-xr-xm4/libtool.m47377
-rwxr-xr-xm4/ltoptions.m4368
-rwxr-xr-xm4/ltsugar.m4123
-rwxr-xr-xm4/ltversion.m423
-rwxr-xr-xm4/lt~obsolete.m492
-rwxr-xr-xmissing49
-rwxr-xr-xntfsprogs/Makefile.am154
-rwxr-xr-xntfsprogs/Makefile.in1199
-rwxr-xr-xntfsprogs/attrdef.c168
-rwxr-xr-xntfsprogs/attrdef.h7
-rwxr-xr-xntfsprogs/boot.c268
-rwxr-xr-xntfsprogs/boot.h7
-rwxr-xr-xntfsprogs/cluster.c118
-rwxr-xr-xntfsprogs/cluster.h39
-rwxr-xr-xntfsprogs/list.h194
-rw-r--r--ntfsprogs/mkntfs.8290
-rwxr-xr-xntfsprogs/mkntfs.8.in290
-rwxr-xr-xntfsprogs/mkntfs.c5177
-rw-r--r--ntfsprogs/ntfscat.8136
-rwxr-xr-xntfsprogs/ntfscat.8.in136
-rwxr-xr-xntfsprogs/ntfscat.c440
-rwxr-xr-xntfsprogs/ntfscat.h46
-rwxr-xr-xntfsprogs/ntfsck.c883
-rw-r--r--ntfsprogs/ntfsclone.8391
-rwxr-xr-xntfsprogs/ntfsclone.8.in391
-rwxr-xr-xntfsprogs/ntfsclone.c2701
-rw-r--r--ntfsprogs/ntfscluster.8124
-rwxr-xr-xntfsprogs/ntfscluster.8.in124
-rwxr-xr-xntfsprogs/ntfscluster.c563
-rwxr-xr-xntfsprogs/ntfscluster.h63
-rw-r--r--ntfsprogs/ntfscmp.877
-rwxr-xr-xntfsprogs/ntfscmp.8.in77
-rwxr-xr-xntfsprogs/ntfscmp.c1012
-rw-r--r--ntfsprogs/ntfscp.8111
-rwxr-xr-xntfsprogs/ntfscp.8.in111
-rwxr-xr-xntfsprogs/ntfscp.c590
-rwxr-xr-xntfsprogs/ntfsdecrypt.c1436
-rwxr-xr-xntfsprogs/ntfsdump_logfile.c779
-rw-r--r--ntfsprogs/ntfsfix.881
-rwxr-xr-xntfsprogs/ntfsfix.8.in81
-rwxr-xr-xntfsprogs/ntfsfix.c1657
-rw-r--r--ntfsprogs/ntfsinfo.889
-rwxr-xr-xntfsprogs/ntfsinfo.8.in89
-rwxr-xr-xntfsprogs/ntfsinfo.c2384
-rw-r--r--ntfsprogs/ntfslabel.8118
-rwxr-xr-xntfsprogs/ntfslabel.8.in118
-rwxr-xr-xntfsprogs/ntfslabel.c458
-rw-r--r--ntfsprogs/ntfsls.8172
-rwxr-xr-xntfsprogs/ntfsls.8.in172
-rwxr-xr-xntfsprogs/ntfsls.c717
-rwxr-xr-xntfsprogs/ntfsmftalloc.c368
-rwxr-xr-xntfsprogs/ntfsmove.c923
-rwxr-xr-xntfsprogs/ntfsmove.h46
-rw-r--r--ntfsprogs/ntfsprogs.869
-rwxr-xr-xntfsprogs/ntfsprogs.8.in69
-rw-r--r--ntfsprogs/ntfsresize.8326
-rwxr-xr-xntfsprogs/ntfsresize.8.in326
-rwxr-xr-xntfsprogs/ntfsresize.c4497
-rwxr-xr-xntfsprogs/ntfstruncate.c809
-rw-r--r--ntfsprogs/ntfsundelete.8324
-rwxr-xr-xntfsprogs/ntfsundelete.8.in324
-rwxr-xr-xntfsprogs/ntfsundelete.c2490
-rwxr-xr-xntfsprogs/ntfsundelete.h112
-rwxr-xr-xntfsprogs/ntfswipe.c2131
-rwxr-xr-xntfsprogs/ntfswipe.h54
-rwxr-xr-xntfsprogs/sd.c607
-rwxr-xr-xntfsprogs/sd.h11
-rwxr-xr-xntfsprogs/utils.c1184
-rwxr-xr-xntfsprogs/utils.h137
-rwxr-xr-xprog.IAB1071
-rwxr-xr-xprog.IAD5
-rwxr-xr-xprog.IMB466
-rwxr-xr-xprog.IMD2
-rwxr-xr-xprog.PFI2
-rwxr-xr-xprog.PO1
-rwxr-xr-xprog.PR14
-rwxr-xr-xprog.PRI219
-rwxr-xr-xprog.PS979
-rwxr-xr-xprog.SearchResults3
-rwxr-xr-xprog.WK39
-rwxr-xr-xsrc/Makefile.am86
-rwxr-xr-xsrc/Makefile.in938
-rwxr-xr-xsrc/lowntfs-3g.c1538
-rw-r--r--src/ntfs-3g.8448
-rwxr-xr-xsrc/ntfs-3g.8.in217
-rwxr-xr-xsrc/ntfs-3g.c1357
-rw-r--r--src/ntfs-3g.probe.881
-rwxr-xr-xsrc/ntfs-3g.probe.8.in4
-rwxr-xr-xsrc/ntfs-3g.probe.c9
-rw-r--r--src/ntfs-3g.secaudit.8184
-rwxr-xr-xsrc/ntfs-3g.secaudit.8.in15
-rw-r--r--src/ntfs-3g.usermap.896
-rwxr-xr-xsrc/ntfs-3g_common.c745
-rwxr-xr-xsrc/ntfs-3g_common.h185
-rwxr-xr-xsrc/secaudit.c673
-rwxr-xr-xsrc/secaudit.h32
-rwxr-xr-xsrc/usermap.c3
-rw-r--r--[-rwxr-xr-x]stamp-h10
193 files changed, 80411 insertions, 44563 deletions
diff --git a/ntfsprogs/ntfsls.c b/ntfsprogs/ntfsls.c
new file mode 100755
index 0000000..909e7bb
--- a/dev/null
+++ b/ntfsprogs/ntfsls.c
@@ -0,0 +1,717 @@
+/**
+ * ntfsls - Part of the Linux-NTFS project.
+ *
+ * Copyright (c) 2003 Lode Leroy
+ * Copyright (c) 2003-2005 Anton Altaparmakov
+ * Copyright (c) 2003 Richard Russon
+ * Copyright (c) 2004 Carmelo Kintana
+ * Copyright (c) 2004 Giang Nguyen
+ *
+ * This utility will list a directory's files.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "config.h"
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "types.h"
+#include "mft.h"
+#include "attrib.h"
+#include "layout.h"
+#include "inode.h"
+#include "utils.h"
+#include "dir.h"
+#include "list.h"
+#include "ntfstime.h"
+/* #include "version.h" */
+#include "logging.h"
+
+static const char *EXEC_NAME = "ntfsls";
+
+/**
+ * To hold sub-directory information for recursive listing.
+ * @depth: the level of this dir relative to opts.path
+ */
+struct dir {
+ struct ntfs_list_head list;
+ ntfs_inode *ni;
+ char name[MAX_PATH];
+ int depth;
+};
+
+/**
+ * path_component - to store path component strings
+ *
+ * @name: string pointer
+ *
+ * NOTE: @name is not directly allocated memory. It simply points to the
+ * character array name in struct dir.
+ */
+struct path_component {
+ struct ntfs_list_head list;
+ const char *name;
+};
+
+/* The list of sub-dirs is like a "horizontal" tree. The root of
+ * the tree is opts.path, but it is not part of the list because
+ * that's not necessary. The rules of the list are (in order of
+ * precedence):
+ * 1. directories immediately follow their parent.
+ * 2. siblings are next to one another.
+ *
+ * For example, if:
+ * 1. opts.path is /
+ * 2. / has 2 sub-dirs: dir1 and dir2
+ * 3. dir1 has 2 sub-dirs: dir11 and dir12
+ * 4. dir2 has 0 sub-dirs
+ * then the list will be:
+ * dummy head -> dir1 -> dir11 -> dir12 -> dir2
+ *
+ * dir_list_insert_pos keeps track of where to insert a sub-dir
+ * into the list.
+ */
+static struct ntfs_list_head *dir_list_insert_pos = NULL;
+
+/* The global depth relative to opts.path.
+ * ie: opts.path has depth 0, a sub-dir of opts.path has depth 1
+ */
+static int depth = 0;
+
+static struct options {
+ char *device; /* Device/File to work with */
+ int quiet; /* Less output */
+ int verbose; /* Extra output */
+ int force; /* Override common sense */
+ int all;
+ int system;
+ int dos;
+ int lng;
+ int inode;
+ int classify;
+ int recursive;
+ const char *path;
+} opts;
+
+typedef struct {
+ ntfs_volume *vol;
+} ntfsls_dirent;
+
+static int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name,
+ const int name_len, const int name_type,
+ const s64 pos, const MFT_REF mref,
+ const unsigned dt_type);
+
+/**
+ * version - Print version information about the program
+ *
+ * Print a copyright statement and a brief description of the program.
+ *
+ * Return: none
+ */
+static void version(void)
+{
+ printf("\n%s v%s (libntfs-3g) - Display information about an NTFS "
+ "Volume.\n\n", EXEC_NAME, VERSION);
+ printf("Copyright (c) 2003 Lode Leroy\n");
+ printf("Copyright (c) 2003-2005 Anton Altaparmakov\n");
+ printf("Copyright (c) 2003 Richard Russon\n");
+ printf("Copyright (c) 2004 Carmelo Kintana\n");
+ printf("Copyright (c) 2004 Giang Nguyen\n");
+ printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
+}
+
+/**
+ * usage - Print a list of the parameters to the program
+ *
+ * Print a list of the parameters and options for the program.
+ *
+ * Return: none
+ */
+static void usage(void)
+{
+ printf("\nUsage: %s [options] device\n"
+ "\n"
+ " -a, --all Display all files\n"
+ " -F, --classify Display classification\n"
+ " -f, --force Use less caution\n"
+ " -h, --help Display this help\n"
+ " -i, --inode Display inode numbers\n"
+ " -l, --long Display long info\n"
+ " -p, --path PATH Directory whose contents to list\n"
+ " -q, --quiet Less output\n"
+ " -R, --recursive Recursively list subdirectories\n"
+ " -s, --system Display system files\n"
+ " -V, --version Display version information\n"
+ " -v, --verbose More output\n"
+ " -x, --dos Use short (DOS 8.3) names\n"
+ "\n",
+ EXEC_NAME);
+
+ printf("NOTE: If neither -a nor -s is specified, the program defaults to -a.\n\n");
+
+ printf("%s%s\n", ntfs_bugs, ntfs_home);
+}
+
+/**
+ * parse_options - Read and validate the programs command line
+ *
+ * Read the command line, verify the syntax and parse the options.
+ * This function is very long, but quite simple.
+ *
+ * Return: 1 Success
+ * 0 Error, one or more problems
+ */
+static int parse_options(int argc, char *argv[])
+{
+ static const char *sopt = "-aFfh?ilp:qRsVvx";
+ static const struct option lopt[] = {
+ { "all", no_argument, NULL, 'a' },
+ { "classify", no_argument, NULL, 'F' },
+ { "force", no_argument, NULL, 'f' },
+ { "help", no_argument, NULL, 'h' },
+ { "inode", no_argument, NULL, 'i' },
+ { "long", no_argument, NULL, 'l' },
+ { "path", required_argument, NULL, 'p' },
+ { "recursive", no_argument, NULL, 'R' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "system", no_argument, NULL, 's' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "dos", no_argument, NULL, 'x' },
+ { NULL, 0, NULL, 0 },
+ };
+
+ int c = -1;
+ int err = 0;
+ int ver = 0;
+ int help = 0;
+ int levels = 0;
+
+ opterr = 0; /* We'll handle the errors, thank you. */
+
+ memset(&opts, 0, sizeof(opts));
+ opts.device = NULL;
+ opts.path = "/";
+
+ while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
+ switch (c) {
+ case 1:
+ if (!opts.device)
+ opts.device = optarg;
+ else
+ err++;
+ break;
+ case 'p':
+ opts.path = optarg;
+ break;
+ case 'f':
+ opts.force++;
+ break;
+ case 'h':
+ case '?':
+ if (strncmp (argv[optind-1], "--log-", 6) == 0) {
+ if (!ntfs_log_parse_option (argv[optind-1]))
+ err++;
+ break;
+ }
+ help++;
+ break;
+ case 'q':
+ opts.quiet++;
+ ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
+ break;
+ case 'v':
+ opts.verbose++;
+ ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
+ break;
+ case 'V':
+ ver++;
+ break;
+ case 'x':
+ opts.dos = 1;
+ break;
+ case 'l':
+ opts.lng++;
+ break;
+ case 'i':
+ opts.inode++;
+ break;
+ case 'F':
+ opts.classify++;
+ break;
+ case 'a':
+ opts.all++;
+ break;
+ case 's':
+ opts.system++;
+ break;
+ case 'R':
+ opts.recursive++;
+ break;
+ default:
+ ntfs_log_error("Unknown option '%s'.\n", argv[optind - 1]);
+ err++;
+ break;
+ }
+ }
+
+ /* Make sure we're in sync with the log levels */
+ levels = ntfs_log_get_levels();
+ if (levels & NTFS_LOG_LEVEL_VERBOSE)
+ opts.verbose++;
+ if (!(levels & NTFS_LOG_LEVEL_QUIET))
+ opts.quiet++;
+
+ /* defaults to -a if -s is not specified */
+ if (!opts.system)
+ opts.all++;
+
+ if (help || ver)
+ opts.quiet = 0;
+ else {
+ if (opts.device == NULL) {
+ if (argc > 1)
+ ntfs_log_error("You must specify exactly one "
+ "device.\n");
+ err++;
+ }
+
+ if (opts.quiet && opts.verbose) {
+ ntfs_log_error("You may not use --quiet and --verbose at the "
+ "same time.\n");
+ err++;
+ }
+ }
+
+ if (ver)
+ version();
+ if (help || err)
+ usage();
+
+ return (!err && !help && !ver);
+}
+
+/**
+ * free_dir - free one dir
+ * @tofree: the dir to free
+ *
+ * Close the inode and then free the dir
+ */
+static void free_dir(struct dir *tofree)
+{
+ if (tofree) {
+ if (tofree->ni) {
+ ntfs_inode_close(tofree->ni);
+ tofree->ni = NULL;
+ }
+ free(tofree);
+ }
+}
+
+/**
+ * free_dirs - walk the list of dir's and free each of them
+ * @dir_list: the ntfs_list_head of any entry in the list
+ *
+ * Iterate over @dir_list, calling free_dir on each entry
+ */
+static void free_dirs(struct ntfs_list_head *dir_list)
+{
+ struct dir *tofree = NULL;
+ struct ntfs_list_head *walker = NULL;
+
+ if (dir_list) {
+ ntfs_list_for_each(walker, dir_list) {
+ free_dir(tofree);
+ tofree = ntfs_list_entry(walker, struct dir, list);
+ }
+
+ free_dir(tofree);
+ }
+}
+
+/**
+ * readdir_recursive - list a directory and sub-directories encountered
+ * @ni: ntfs inode of the directory to list
+ * @pos: current position in directory
+ * @dirent: context for filldir callback supplied by the caller
+ *
+ * For each directory, print its path relative to opts.path. List a directory,
+ * then list each of its sub-directories.
+ *
+ * Returns 0 on success or -1 on error.
+ *
+ * NOTE: Assumes recursive option. Currently no limit on the depths of
+ * recursion.
+ */
+static int readdir_recursive(ntfs_inode * ni, s64 * pos, ntfsls_dirent * dirent)
+{
+ /* list of dirs to "ls" recursively */
+ static struct dir dirs = {
+ .list = NTFS_LIST_HEAD_INIT(dirs.list),
+ .ni = NULL,
+ .name = {0},
+ .depth = 0
+ };
+
+ static struct path_component paths = {
+ .list = NTFS_LIST_HEAD_INIT(paths.list),
+ .name = NULL
+ };
+
+ static struct path_component base_comp;
+
+ struct dir *subdir = NULL;
+ struct dir *tofree = NULL;
+ struct path_component comp;
+ struct path_component *tempcomp = NULL;
+ struct ntfs_list_head *dir_walker = NULL;
+ struct ntfs_list_head *comp_walker = NULL;
+ s64 pos2 = 0;
+ int ni_depth = depth;
+ int result = 0;
+
+ if (ntfs_list_empty(&dirs.list)) {
+ base_comp.name = opts.path;
+ ntfs_list_add(&base_comp.list, &paths.list);
+ dir_list_insert_pos = &dirs.list;
+ printf("%s:\n", opts.path);
+ }
+
+ depth++;
+
+ result = ntfs_readdir(ni, pos, dirent, (ntfs_filldir_t) list_dir_entry);
+
+ if (result == 0) {
+ ntfs_list_add_tail(&comp.list, &paths.list);
+
+ /* for each of ni's sub-dirs: list in this iteration, then
+ free at the top of the next iteration or outside of loop */
+ ntfs_list_for_each(dir_walker, &dirs.list) {
+ if (tofree) {
+ free_dir(tofree);
+ tofree = NULL;
+ }
+ subdir = ntfs_list_entry(dir_walker, struct dir, list);
+
+ /* subdir is not a subdir of ni */
+ if (subdir->depth != ni_depth + 1)
+ break;
+
+ pos2 = 0;
+ dir_list_insert_pos = &dirs.list;
+ if (!subdir->ni) {
+ subdir->ni =
+ ntfs_pathname_to_inode(ni->vol, ni,
+ subdir->name);
+
+ if (!subdir->ni) {
+ ntfs_log_error
+ ("ntfsls::readdir_recursive(): cannot get inode from pathname.\n");
+ result = -1;
+ break;
+ }
+ }
+ puts("");
+
+ comp.name = subdir->name;
+
+ /* print relative path header */
+ ntfs_list_for_each(comp_walker, &paths.list) {
+ tempcomp =
+ ntfs_list_entry(comp_walker,
+ struct path_component, list);
+ printf("%s", tempcomp->name);
+ if (tempcomp != &comp
+ && *tempcomp->name != PATH_SEP
+ && (!opts.classify
+ || tempcomp == &base_comp))
+ putchar(PATH_SEP);
+ }
+ puts(":");
+
+ result = readdir_recursive(subdir->ni, &pos2, dirent);
+
+ if (result)
+ break;
+
+ tofree = subdir;
+ ntfs_list_del(dir_walker);
+ }
+
+ ntfs_list_del(&comp.list);
+ }
+
+ if (tofree)
+ free_dir(tofree);
+
+ /* if at the outer-most readdir_recursive, then clean up */
+ if (ni_depth == 0) {
+ free_dirs(&dirs.list);
+ }
+
+ depth--;
+
+ return result;
+}
+
+/**
+ * list_dir_entry
+ *
+ * FIXME: Should we print errors as we go along? (AIA)
+ */
+static int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name,
+ const int name_len, const int name_type,
+ const s64 pos __attribute__((unused)),
+ const MFT_REF mref, const unsigned dt_type)
+{
+ char *filename = NULL;
+ int result = 0;
+
+ struct dir *dir = NULL;
+
+ filename = calloc(1, MAX_PATH);
+ if (!filename)
+ return -1;
+
+ if (ntfs_ucstombs(name, name_len, &filename, MAX_PATH) < 0) {
+ ntfs_log_error("Cannot represent filename in current locale.\n");
+ goto free;
+ }
+
+ result = 0; // These are successful
+ if ((MREF(mref) < FILE_first_user) && (!opts.system))
+ goto free;
+ if (name_type == FILE_NAME_POSIX && !opts.all)
+ goto free;
+ if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_WIN32) &&
+ opts.dos)
+ goto free;
+ if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_DOS) &&
+ !opts.dos)
+ goto free;
+ if (dt_type == NTFS_DT_DIR && opts.classify)
+ sprintf(filename + strlen(filename), "/");
+
+ if (dt_type == NTFS_DT_DIR && opts.recursive
+ && strcmp(filename, ".") && strcmp(filename, "./")
+ && strcmp(filename, "..") && strcmp(filename, "../"))
+ {
+ dir = (struct dir *)calloc(1, sizeof(struct dir));
+
+ if (!dir) {
+ ntfs_log_error("Failed to allocate for subdir.\n");
+ result = -1;
+ goto free;
+ }
+
+ strcpy(dir->name, filename);
+ dir->ni = NULL;
+ dir->depth = depth;
+ }
+
+ if (!opts.lng) {
+ if (!opts.inode)
+ printf("%s\n", filename);
+ else
+ printf("%7llu %s\n", (unsigned long long)MREF(mref),
+ filename);
+ result = 0;
+ } else {
+ s64 filesize = 0;
+ ntfs_inode *ni;
+ ntfs_attr_search_ctx *ctx = NULL;
+ FILE_NAME_ATTR *file_name_attr;
+ ATTR_RECORD *attr;
+ struct timespec change_time;
+ char t_buf[26];
+
+ result = -1; // Everything else is bad
+
+ ni = ntfs_inode_open(dirent->vol, mref);
+ if (!ni)
+ goto release;
+
+ ctx = ntfs_attr_get_search_ctx(ni, NULL);
+ if (!ctx)
+ goto release;
+
+ if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL,
+ 0, ctx))
+ goto release;
+ attr = ctx->attr;
+
+ file_name_attr = (FILE_NAME_ATTR *)((char *)attr +
+ le16_to_cpu(attr->value_offset));
+ if (!file_name_attr)
+ goto release;
+
+ change_time = ntfs2timespec(file_name_attr->last_data_change_time);
+ strcpy(t_buf, ctime(&change_time.tv_sec));
+ memmove(t_buf+16, t_buf+19, 5);
+ t_buf[21] = '\0';
+
+ if (dt_type != NTFS_DT_DIR) {
+ if (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0,
+ NULL, 0, ctx))
+ filesize = ntfs_get_attribute_value_length(
+ ctx->attr);
+ }
+
+ if (opts.inode)
+ printf("%7llu %8lld %s %s\n",
+ (unsigned long long)MREF(mref),
+ (long long)filesize, t_buf + 4,
+ filename);
+ else
+ printf("%8lld %s %s\n", (long long)filesize, t_buf + 4,
+ filename);
+
+ if (dir) {
+ dir->ni = ni;
+ ni = NULL; /* so release does not close inode */
+ }
+
+ result = 0;
+release:
+ /* Release attribute search context and close the inode. */
+ if (ctx)
+ ntfs_attr_put_search_ctx(ctx);
+ if (ni)
+ ntfs_inode_close(ni);
+ }
+
+ if (dir) {
+ if (result == 0) {
+ ntfs_list_add(&dir->list, dir_list_insert_pos);
+ dir_list_insert_pos = &dir->list;
+ } else {
+ free(dir);
+ dir = NULL;
+ }
+ }
+
+free:
+ free(filename);
+ return result;
+}
+
+/**
+ * main - Begin here
+ *
+ * Start from here.
+ *
+ * Return: 0 Success, the program worked
+ * 1 Error, parsing mount options failed
+ * 2 Error, mount attempt failed
+ * 3 Error, failed to open root directory
+ * 4 Error, failed to open directory in search path
+ */
+int main(int argc, char **argv)
+{
+ s64 pos;
+ ntfs_volume *vol;
+ ntfs_inode *ni;
+ ntfsls_dirent dirent;
+
+ ntfs_log_set_handler(ntfs_log_handler_outerr);
+
+ if (!parse_options(argc, argv)) {
+ // FIXME: Print error... (AIA)
+ return 1;
+ }
+
+ utils_set_locale();
+
+ vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY |
+ (opts.force ? NTFS_MNT_RECOVER : 0));
+ if (!vol) {
+ // FIXME: Print error... (AIA)
+ return 2;
+ }
+
+ ni = ntfs_pathname_to_inode(vol, NULL, opts.path);
+ if (!ni) {
+ // FIXME: Print error... (AIA)
+ ntfs_umount(vol, FALSE);
+ return 3;
+ }
+
+ /*
+ * We now are at the final path component. If it is a file just
+ * list it. If it is a directory, list its contents.
+ */
+ pos = 0;
+ memset(&dirent, 0, sizeof(dirent));
+ dirent.vol = vol;
+ if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
+ if (opts.recursive)
+ readdir_recursive(ni, &pos, &dirent);
+ else
+ ntfs_readdir(ni, &pos, &dirent,
+ (ntfs_filldir_t) list_dir_entry);
+ // FIXME: error checking... (AIA)
+ } else {
+ ATTR_RECORD *rec;
+ FILE_NAME_ATTR *attr;
+ ntfs_attr_search_ctx *ctx;
+ int space = 4;
+ ntfschar *name = NULL;
+ int name_len = 0;;
+
+ ctx = ntfs_attr_get_search_ctx(ni, NULL);
+ if (!ctx)
+ return -1;
+
+ while ((rec = find_attribute(AT_FILE_NAME, ctx))) {
+ /* We know this will always be resident. */
+ attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset));
+
+ if (attr->file_name_type < space) {
+ name = attr->file_name;
+ name_len = attr->file_name_length;
+ space = attr->file_name_type;
+ }
+ }
+
+ list_dir_entry(&dirent, name, name_len, space, pos, ni->mft_no,
+ NTFS_DT_REG);
+ // FIXME: error checking... (AIA)
+
+ ntfs_attr_put_search_ctx(ctx);
+ }
+
+ /* Finished with the inode; release it. */
+ ntfs_inode_close(ni);
+
+ ntfs_umount(vol, FALSE);
+ return 0;
+}
+