]> wimlib.net Git - wimlib/blobdiff - src/ntfs-3g_capture.c
x86_cpu_features.c: cpuid fix for x86_32 PIC with old GCC versions
[wimlib] / src / ntfs-3g_capture.c
index f9825f73946ca6c629690d587dc3d74c2af25a8e..fe1fbf55a37989f1a0de5a708229e1f46c266669 100644 (file)
 #include "wimlib/reparse.h"
 #include "wimlib/security.h"
 
+/* NTFS-3g 2013 renamed MS_RDONLY to NTFS_MNT_RDONLY.  We can't check for the
+ * existence of NTFS_MNT_RDONLY at compilation time because it's an enum.  We
+ * also can't check for MS_RDONLY being missing because it's also a system
+ * constant.  So check if the NTFS-3g specific MS_IGNORE_HIBERFILE is defined;
+ * if yes, then we need to use the old MS_RDONLY.  */
+#ifdef MS_IGNORE_HIBERFILE
+#  define NTFS_MNT_RDONLY MS_RDONLY
+#endif
+
 /* A reference-counted NTFS volume than is automatically unmounted when the
  * reference count reaches 0  */
 struct ntfs_volume_wrapper {
@@ -256,6 +265,44 @@ set_attr_sort_key(ntfs_inode *ni, struct ntfs_location *loc)
        return 0;
 }
 
+/*
+ * Add a new stream to the specified inode, with duplicate checking.
+ *
+ * This works around a problem where NTFS-3g can list multiple unnamed data
+ * streams for a single file.  In this case we can only keep one.  We'll prefer
+ * one that is nonempty.
+ */
+static int
+add_stream(struct wim_inode *inode, const char *path, int stream_type,
+          const utf16lechar *stream_name, struct blob_descriptor **blob_p,
+          struct list_head *unhashed_blobs)
+{
+       struct blob_descriptor *blob = *blob_p;
+       struct wim_inode_stream *strm;
+
+       strm = inode_get_stream(inode, stream_type, stream_name);
+       if (unlikely(strm)) {
+               /* Stream already existed.  */
+               if (!blob)
+                       return 0;
+               if (stream_blob_resolved(strm)) {
+                       WARNING("\"%s\" has multiple nonempty streams "
+                               "with the same type and name!  Only the first "
+                               "will be saved.", path);
+                       return 0;
+               }
+               inode_replace_stream_blob(inode, strm, blob, NULL);
+       } else {
+               strm = inode_add_stream(inode, stream_type, stream_name, blob);
+               if (unlikely(!strm))
+                       return WIMLIB_ERR_NOMEM;
+       }
+       prepare_unhashed_blob(blob, inode, strm->stream_id, unhashed_blobs);
+       *blob_p = NULL;
+       return 0;
+
+}
+
 /* Save information about an NTFS attribute (stream) to a WIM inode.  */
 static int
 scan_ntfs_attr(struct wim_inode *inode,
@@ -270,7 +317,6 @@ scan_ntfs_attr(struct wim_inode *inode,
        const u32 name_nchars = record->name_length;
        struct blob_descriptor *blob = NULL;
        utf16lechar *stream_name = NULL;
-       struct wim_inode_stream *strm;
        int ret;
 
        if (unlikely(name_nchars)) {
@@ -334,17 +380,9 @@ scan_ntfs_attr(struct wim_inode *inode,
                        goto out_cleanup;
        }
 
-       strm = inode_add_stream(inode,
-                               attr_type_to_wimlib_stream_type(type),
-                               stream_name ? stream_name : NO_STREAM_NAME,
-                               blob);
-       if (unlikely(!strm)) {
-               ret = WIMLIB_ERR_NOMEM;
-               goto out_cleanup;
-       }
-       prepare_unhashed_blob(blob, inode, strm->stream_id, unhashed_blobs);
-       blob = NULL;
-       ret = 0;
+       ret = add_stream(inode, path, attr_type_to_wimlib_stream_type(type),
+                        stream_name ? stream_name : NO_STREAM_NAME,
+                        &blob, unhashed_blobs);
 out_cleanup:
        free_blob_descriptor(blob);
        FREE(stream_name);
@@ -800,23 +838,7 @@ ntfs_3g_build_dentry_tree(struct wim_dentry **root_ret,
        if (!volume)
                return WIMLIB_ERR_NOMEM;
 
-       /* NTFS-3g 2013 renamed the "read-only" mount flag from MS_RDONLY to
-        * NTFS_MNT_RDONLY.
-        *
-        * Unfortunately we can't check for defined(NTFS_MNT_RDONLY) because
-        * NTFS_MNT_RDONLY is an enumerated constant.  Also, the NTFS-3g headers
-        * don't seem to contain any explicit version information.  So we have
-        * to rely on a test done at configure time to detect whether
-        * NTFS_MNT_RDONLY should be used.  */
-#ifdef HAVE_NTFS_MNT_RDONLY
-       /* NTFS-3g 2013 */
        vol = ntfs_mount(device, NTFS_MNT_RDONLY);
-#elif defined(MS_RDONLY)
-       /* NTFS-3g 2011, 2012 */
-       vol = ntfs_mount(device, MS_RDONLY);
-#else
-  #error "Can't find NTFS_MNT_RDONLY or MS_RDONLY flags"
-#endif
        if (!vol) {
                ERROR_WITH_ERRNO("Failed to mount NTFS volume \"%s\" read-only",
                                 device);