NTFS-3g apply: Open extracted files by MFT reference
authorEric Biggers <ebiggers3@gmail.com>
Fri, 16 Aug 2013 19:16:24 +0000 (14:16 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Fri, 16 Aug 2013 19:16:48 +0000 (14:16 -0500)
include/wimlib/apply.h
include/wimlib/dentry.h
src/extract.c
src/ntfs-3g_apply.c
src/unix_apply.c
src/win32_apply.c

index a7fe179..8a55626 100644 (file)
@@ -10,6 +10,13 @@ struct wimlib_unix_data;
 struct wim_dentry;
 struct apply_ctx;
 
+/* Path to extracted file, or "cookie" identifying the file (e.g. inode number).
+ * */
+typedef union {
+       const char *path;
+       u64 cookie;
+} file_spec_t;
+
 /*
  * struct apply_operations -  Callback functions for a specific extraction
  * mode/backend.  These are lower-level functions that are called by the generic
@@ -43,11 +50,11 @@ struct apply_operations {
 
        /* REQUIRED:  Create a file.  */
        int (*create_file)
-               (const tchar *path, struct apply_ctx *ctx);
+               (const tchar *path, struct apply_ctx *ctx, u64 *cookie_ret);
 
        /* REQUIRED:  Create a directory.  */
        int (*create_directory)
-               (const tchar *path, struct apply_ctx *ctx);
+               (const tchar *path, struct apply_ctx *ctx, u64 *cookie_ret);
 
        /* OPTIONAL:  Create a hard link.  In start_extract(), set
         * ctx->supported_features.hard_links if supported.  */
@@ -63,20 +70,20 @@ struct apply_operations {
 
        /* REQUIRED:  Extract unnamed data stream.  */
        int (*extract_unnamed_stream)
-               (const tchar *path, struct wim_lookup_table_entry *lte,
+               (file_spec_t file, struct wim_lookup_table_entry *lte,
                 struct apply_ctx *ctx);
 
        /* OPTIONAL:  Extracted named data stream.  In start_extract(), set
         * ctx->supported_features.alternate_data_streams if supported.  */
        int (*extract_named_stream)
-               (const tchar *path, const utf16lechar *stream_name,
+               (file_spec_t file, const utf16lechar *stream_name,
                 size_t stream_name_nchars, struct wim_lookup_table_entry *lte,
                 struct apply_ctx *ctx);
 
        /* OPTIONAL:  Extracted encrypted stream.  In start_extract(), set
         * ctx->supported_features.encrypted_files if supported.  */
        int (*extract_encrypted_stream)
-               (const tchar *path, struct wim_lookup_table_entry *lte,
+               (file_spec_t file, struct wim_lookup_table_entry *lte,
                 struct apply_ctx *ctx);
 
        /* OPTIONAL:  Set file attributes.  Calling code calls this if non-NULL.
@@ -154,6 +161,12 @@ struct apply_operations {
        /* OPTIONAL:  Set to 1 if the root directory of the volume (see
         * target_is_root() callback) should not be explicitly extracted.  */
        unsigned root_directory_is_special : 1;
+
+       /* OPTIONAL:  Set to 1 if extraction cookie, or inode number, is stored
+        * in create_file() and create_directory() callbacks.  This cookie will
+        * then be passed to callbacks taking a 'file_spec_t', rather than the
+        * path.  */
+       unsigned uses_cookies : 1;
 };
 
 struct wim_features {
index 09de869..8676e8e 100644 (file)
@@ -363,11 +363,20 @@ struct wim_inode {
                 * to 0 otherwise.  */
                u64 i_devno;
 
-               /* Used only during image extraction: pointer to the first path
-                * (malloc()ed buffer) at which this inode has been extracted.
-                * Freed and set to NULL after the extraction is done (either
-                * success or failure).  */
-               tchar *i_extracted_file;
+               struct {
+
+                       /* Used only during image extraction: pointer to the first path
+                        * (malloc()ed buffer) at which this inode has been extracted.
+                        * Freed and set to NULL after the extraction is done (either
+                        * success or failure).  */
+                       tchar *i_extracted_file;
+
+                       /** Used only during image extraction: "cookie" that
+                        * identifies this extracted file (inode), for example
+                        * an inode number.  Only used if supported by the
+                        * extraction mode.  */
+                       u64 extract_cookie;
+               };
 
 #ifdef WITH_FUSE
                /* Used only during image mount:  Table of file descriptors that
index d4efc24..9c460e9 100644 (file)
@@ -333,13 +333,13 @@ extract_inode(const tchar *path, struct apply_ctx *ctx, struct wim_inode *inode)
        } else
 #endif /* !__WIN32__ */
        if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) {
-               ret = ctx->ops->create_directory(path, ctx);
+               ret = ctx->ops->create_directory(path, ctx, &inode->extract_cookie);
                if (ret) {
                        ERROR_WITH_ERRNO("Failed to create the directory "
                                         "\"%"TS"\"", path);
                }
        } else {
-               ret = ctx->ops->create_file(path, ctx);
+               ret = ctx->ops->create_file(path, ctx, &inode->extract_cookie);
                if (ret) {
                        ERROR_WITH_ERRNO("Failed to create the file "
                                         "\"%"TS"\"", path);
@@ -553,6 +553,7 @@ extract_streams(const tchar *path, struct apply_ctx *ctx,
 {
        struct wim_inode *inode = dentry->d_inode;
        struct wim_lookup_table_entry *lte;
+       file_spec_t file_spec;
        int ret;
 
        if (dentry->was_hardlinked)
@@ -571,6 +572,11 @@ extract_streams(const tchar *path, struct apply_ctx *ctx,
        }
 #endif
 
+       if (ctx->ops->uses_cookies)
+               file_spec.cookie = inode->extract_cookie;
+       else
+               file_spec.path = path;
+
        /* Unnamed data stream.  */
        lte = inode_unnamed_lte_resolved(inode);
        if (lte && (!lte_spec || lte == lte_spec)) {
@@ -581,9 +587,9 @@ extract_streams(const tchar *path, struct apply_ctx *ctx,
                {
                        if ((inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) &&
                            ctx->supported_features.encrypted_files)
-                               ret = ctx->ops->extract_encrypted_stream(path, lte, ctx);
+                               ret = ctx->ops->extract_encrypted_stream(file_spec, lte, ctx);
                        else
-                               ret = ctx->ops->extract_unnamed_stream(path, lte, ctx);
+                               ret = ctx->ops->extract_unnamed_stream(file_spec, lte, ctx);
                        if (ret)
                                goto error;
                        update_extract_progress(ctx, lte);
@@ -617,7 +623,7 @@ extract_streams(const tchar *path, struct apply_ctx *ctx,
                                continue;
                        if (lte_spec)
                                lte = lte_override;
-                       ret = ctx->ops->extract_named_stream(path, entry->stream_name,
+                       ret = ctx->ops->extract_named_stream(file_spec, entry->stream_name,
                                                             entry->stream_name_nbytes / 2,
                                                             lte, ctx);
                        if (ret)
@@ -997,13 +1003,18 @@ do_dentry_extract_skeleton(tchar path[], struct wim_dentry *dentry,
        /* Create empty named data streams.  */
        if (can_extract_named_data_streams(ctx)) {
                for (u16 i = 0; i < inode->i_num_ads; i++) {
+                       file_spec_t file_spec;
                        struct wim_ads_entry *entry = &inode->i_ads_entries[i];
 
                        if (!ads_entry_is_named_stream(entry))
                                continue;
                        if (entry->lte)
                                continue;
-                       ret = ctx->ops->extract_named_stream(path,
+                       if (ctx->ops->uses_cookies)
+                               file_spec.cookie = inode->extract_cookie;
+                       else
+                               file_spec.path = path;
+                       ret = ctx->ops->extract_named_stream(file_spec,
                                                             entry->stream_name,
                                                             entry->stream_name_nbytes / 2,
                                                             entry->lte, ctx);
index fe2f24e..c40661b 100644 (file)
@@ -103,7 +103,8 @@ ntfs_3g_open_parent_inode(const char *path, ntfs_volume *vol)
 }
 
 static int
-ntfs_3g_create(const char *path, struct apply_ctx *ctx, mode_t mode)
+ntfs_3g_create(const char *path, struct apply_ctx *ctx, u64 *cookie_ret,
+              mode_t mode)
 {
        ntfs_volume *vol;
        ntfs_inode *dir_ni, *ni;
@@ -125,11 +126,16 @@ ntfs_3g_create(const char *path, struct apply_ctx *ctx, mode_t mode)
        if (ret)
                goto out_close_dir_ni;
 
-       ret = 0;
+       ret = WIMLIB_ERR_NTFS_3G;
        ni = ntfs_create(dir_ni, 0, name_utf16le,
                         name_utf16le_nbytes / 2, mode);
-       if (!ni || ntfs_inode_close_in_dir(ni, dir_ni))
-               ret = WIMLIB_ERR_NTFS_3G;
+       if (!ni)
+               goto out_free_name_utf16le;
+       *cookie_ret = MK_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));
+       if (ntfs_inode_close_in_dir(ni, dir_ni))
+               goto out_free_name_utf16le;
+       ret = 0;
+out_free_name_utf16le:
        FREE(name_utf16le);
 out_close_dir_ni:
        if (ntfs_inode_close(dir_ni))
@@ -139,15 +145,17 @@ out:
 }
 
 static int
-ntfs_3g_create_file(const char *path, struct apply_ctx *ctx)
+ntfs_3g_create_file(const char *path, struct apply_ctx *ctx,
+                   u64 *cookie_ret)
 {
-       return ntfs_3g_create(path, ctx, S_IFREG);
+       return ntfs_3g_create(path, ctx, cookie_ret, S_IFREG);
 }
 
 static int
-ntfs_3g_create_directory(const char *path, struct apply_ctx *ctx)
+ntfs_3g_create_directory(const char *path, struct apply_ctx *ctx,
+                        u64 *cookie_ret)
 {
-       return ntfs_3g_create(path, ctx, S_IFDIR);
+       return ntfs_3g_create(path, ctx, cookie_ret, S_IFDIR);
 }
 
 static int
@@ -196,7 +204,7 @@ out:
  * Extract a stream (default or alternate data) to an attribute of a NTFS file.
  */
 static int
-ntfs_3g_extract_stream(const char *path, const utf16lechar *raw_stream_name,
+ntfs_3g_extract_stream(file_spec_t file, const utf16lechar *raw_stream_name,
                       size_t stream_name_nchars,
                       struct wim_lookup_table_entry *lte, struct apply_ctx *ctx)
 {
@@ -219,9 +227,9 @@ ntfs_3g_extract_stream(const char *path, const utf16lechar *raw_stream_name,
        if (!stream_name_nchars && !lte)
                goto out;
 
-       /* Look up NTFS inode to which to extract the stream.  */
+       /* Open NTFS inode to which to extract the stream.  */
        ret = WIMLIB_ERR_NTFS_3G;
-       ni = ntfs_3g_apply_pathname_to_inode(path, ctx);
+       ni = ntfs_inode_open(ntfs_3g_apply_ctx_get_volume(ctx), file.cookie);
        if (!ni)
                goto out;
 
@@ -266,19 +274,19 @@ out:
 }
 
 static int
-ntfs_3g_extract_unnamed_stream(const char *path,
+ntfs_3g_extract_unnamed_stream(file_spec_t file,
                               struct wim_lookup_table_entry *lte,
                               struct apply_ctx *ctx)
 {
-       return ntfs_3g_extract_stream(path, NULL, 0, lte, ctx);
+       return ntfs_3g_extract_stream(file, NULL, 0, lte, ctx);
 }
 
 static int
-ntfs_3g_extract_named_stream(const char *path, const utf16lechar *stream_name,
+ntfs_3g_extract_named_stream(file_spec_t file, const utf16lechar *stream_name,
                             size_t stream_name_nchars,
                             struct wim_lookup_table_entry *lte, struct apply_ctx *ctx)
 {
-       return ntfs_3g_extract_stream(path, stream_name,
+       return ntfs_3g_extract_stream(file, stream_name,
                                      stream_name_nchars, lte, ctx);
 }
 
@@ -495,6 +503,7 @@ const struct apply_operations ntfs_3g_apply_ops = {
 
        .supports_case_sensitive_filenames = 1,
        .root_directory_is_special = 1,
+       .uses_cookies = 1,
 };
 
 #endif /* WITH_NTFS_3G */
index bd576ef..026042b 100644 (file)
@@ -54,7 +54,7 @@ unix_start_extract(const char *target, struct apply_ctx *ctx)
 }
 
 static int
-unix_create_file(const char *path, struct apply_ctx *ctx)
+unix_create_file(const char *path, struct apply_ctx *ctx, u64 *cookie_ret)
 {
        int fd = open(path, O_TRUNC | O_CREAT | O_WRONLY, 0644);
        if (fd < 0)
@@ -64,7 +64,7 @@ unix_create_file(const char *path, struct apply_ctx *ctx)
 }
 
 static int
-unix_create_directory(const tchar *path, struct apply_ctx *ctx)
+unix_create_directory(const tchar *path, struct apply_ctx *ctx, u64 *cookie_ret)
 {
        struct stat stbuf;
 
@@ -111,10 +111,11 @@ unix_create_symlink(const tchar *oldpath, const tchar *newpath,
 }
 
 static int
-unix_extract_unnamed_stream(const tchar *path,
+unix_extract_unnamed_stream(file_spec_t file,
                            struct wim_lookup_table_entry *lte,
                            struct apply_ctx *ctx)
 {
+       const char *path = file.path;
        struct filedes fd;
        int raw_fd;
        int ret;
index bce897a..00ace99 100644 (file)
@@ -162,19 +162,19 @@ error:
 }
 
 static int
-win32_extract_unnamed_stream(const wchar_t *path,
+win32_extract_unnamed_stream(file_spec_t file,
                             struct wim_lookup_table_entry *lte,
                             struct apply_ctx *ctx)
 {
-       return win32_extract_stream(path, NULL, 0, lte, ctx);
+       return win32_extract_stream(file.path, NULL, 0, lte, ctx);
 }
 
 static int
-win32_extract_named_stream(const wchar_t *path, const wchar_t *stream_name,
+win32_extract_named_stream(file_spec_t file, const wchar_t *stream_name,
                           size_t stream_name_nchars,
                           struct wim_lookup_table_entry *lte, struct apply_ctx *ctx)
 {
-       return win32_extract_stream(path, stream_name,
+       return win32_extract_stream(file.path, stream_name,
                                    stream_name_nchars, lte, ctx);
 }