#ifdef WITH_NTFS_3G
+#include <errno.h>
#include <locale.h>
+#include <stdlib.h>
#include <string.h>
-#include <time.h> /* NTFS-3g headers are missing <time.h> include */
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/reparse.h>
#include <ntfs-3g/security.h>
-#include <errno.h>
-
-#ifdef HAVE_ALLOCA_H
-# include <alloca.h>
-#else
-# include <stdlib.h>
-#endif
#include "wimlib/apply.h"
#include "wimlib/encoding.h"
}
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;
vol = ntfs_3g_apply_ctx_get_volume(ctx);
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_OPEN;
dir_ni = ntfs_3g_open_parent_inode(path, vol);
if (!dir_ni)
goto out;
if (ret)
goto out_close_dir_ni;
- ret = 0;
+ ret = WIMLIB_ERR_OPEN;
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))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
out:
return ret;
}
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
vol = ntfs_3g_apply_ctx_get_volume(ctx);
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_OPEN;
ni = ntfs_pathname_to_inode(vol, NULL, oldpath);
if (!ni)
goto out;
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_OPEN;
dir_ni = ntfs_3g_open_parent_inode(newpath, vol);
if (!dir_ni)
goto out_close_ni;
goto out_close_dir_ni;
ret = 0;
if (ntfs_link(ni, dir_ni, name_utf16le, name_utf16le_nbytes / 2))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_LINK;
FREE(name_utf16le);
out_close_dir_ni:
if (ntfs_inode_close(dir_ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
out_close_ni:
if (ntfs_inode_close(ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
out:
return ret;
}
* 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)
{
if (!stream_name_nchars && !lte)
goto out;
- /* Look up NTFS inode to which to extract the stream. */
- ret = WIMLIB_ERR_NTFS_3G;
- ni = ntfs_3g_apply_pathname_to_inode(path, ctx);
+ /* Open NTFS inode to which to extract the stream. */
+ ret = WIMLIB_ERR_OPEN;
+ ni = ntfs_inode_open(ntfs_3g_apply_ctx_get_volume(ctx), file.cookie);
if (!ni)
goto out;
/* Add the stream if it's not the default (unnamed) stream. */
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_OPEN;
if (stream_name_nchars)
if (ntfs_attr_add(ni, AT_DATA, stream_name,
stream_name_nchars, NULL, 0))
goto out_close;
/* Open the stream (NTFS attribute). */
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_OPEN;
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_nchars);
if (!na)
goto out_close;
- /* (Optional) Immediately resize attribute to size of stream. */
- ret = WIMLIB_ERR_NTFS_3G;
+ /* (Optional) Immediately resize attribute to size of stream.
+ *
+ * This dramatically speeds up extraction, as demonstrated with the
+ * following timing results:
+ *
+ * 18 mins. 27 sec. to apply Windows 7 image (with resize)
+ * 32 mins. 45 sec. to apply Windows 7 image (no resize)
+ *
+ * It probably would speed things up even more if we could get NTFS-3g
+ * to skip even more useless work (for example it fills resized
+ * attributes with 0's, then we just override it.) */
+ ret = WIMLIB_ERR_WRITE;
if (ntfs_attr_truncate_solid(na, wim_resource_size(lte)))
goto out_attr_close;
ntfs_attr_close(na);
out_close:
if (ntfs_inode_close(ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
out:
if (ret && !errno)
errno = -1;
}
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);
}
static int
ntfs_3g_set_file_attributes(const char *path, u32 attributes,
- struct apply_ctx *ctx)
+ struct apply_ctx *ctx, unsigned pass)
{
ntfs_inode *ni;
int ret = 0;
ni = ntfs_3g_apply_pathname_to_inode(path, ctx);
if (!ni)
- return WIMLIB_ERR_NTFS_3G;
+ return WIMLIB_ERR_OPEN;
if (ntfs_set_ntfs_attrib(ni, (const char*)&attributes, sizeof(u32), 0))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_SET_ATTRIBUTES;
if (ntfs_inode_close(ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
return ret;
}
ni = ntfs_3g_apply_pathname_to_inode(path, ctx);
if (!ni)
- return WIMLIB_ERR_NTFS_3G;
+ return WIMLIB_ERR_OPEN;
if (ntfs_set_ntfs_reparse_data(ni, rpbuf, rpbuflen, 0))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_SET_REPARSE_DATA;
if (ntfs_inode_close(ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
return ret;
}
vol = ntfs_3g_apply_ctx_get_volume(ctx);
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_OPEN;
dir_ni = ntfs_3g_open_parent_inode(path, vol);
if (!dir_ni)
goto out;
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_OPEN;
ni = ntfs_pathname_to_inode(vol, NULL, path);
if (!ni)
goto out_close_dir_ni;
ret = 0;
if (ntfs_set_ntfs_dos_name(ni, dir_ni, dosname,
dosname_nbytes, 0))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_SET_SHORT_NAME;
/* ntfs_set_ntfs_dos_name() always closes the inodes. */
FREE(dosname);
goto out;
out_close_ni:
if (ntfs_inode_close_in_dir(ni, dir_ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
out_close_dir_ni:
if (ntfs_inode_close(dir_ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
out:
return ret;
}
ni = ntfs_pathname_to_inode(vol, NULL, path);
if (!ni)
- return WIMLIB_ERR_NTFS_3G;
+ return WIMLIB_ERR_OPEN;
memset(&sec_ctx, 0, sizeof(sec_ctx));
sec_ctx.vol = vol;
if (ntfs_set_ntfs_acl(&sec_ctx, ni, desc, desc_size, 0))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_SET_SECURITY;
if (ntfs_inode_close(ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
return ret;
}
ni = ntfs_3g_apply_pathname_to_inode(path, ctx);
if (!ni)
- return WIMLIB_ERR_NTFS_3G;
+ return WIMLIB_ERR_OPEN;
/* Note: ntfs_inode_set_times() expects the times in native byte order,
* not little endian. */
if (ntfs_inode_set_times(ni, (const char*)ntfs_timestamps,
sizeof(ntfs_timestamps), 0))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_SET_TIMESTAMPS;
if (ntfs_inode_close(ni))
- ret = WIMLIB_ERR_NTFS_3G;
+ ret = WIMLIB_ERR_WRITE;
return ret;
}
vol = ntfs_mount(ctx->target, 0);
if (!vol) {
ERROR_WITH_ERRNO("Failed to mount \"%"TS"\" with NTFS-3g", ctx->target);
- return WIMLIB_ERR_NTFS_3G;
+ return WIMLIB_ERR_OPEN;
}
ntfs_3g_apply_ctx_set_volume(ctx, vol);
if (ntfs_umount(vol, FALSE)) {
ERROR_WITH_ERRNO("Failed to unmount \"%"TS"\" with NTFS-3g",
ctx->target);
- return WIMLIB_ERR_NTFS_3G;
+ return WIMLIB_ERR_WRITE;
}
return 0;
}
.path_separator = '/',
.path_max = 32768,
+ /* By default, NTFS-3g creates names in the NTFS POSIX namespace, which
+ * is case-sensitive. */
.supports_case_sensitive_filenames = 1,
+
+ /* The root directory of the NTFS volume should not be created
+ * explicitly. */
.root_directory_is_special = 1,
+
+ /* NTFS-3g can open files by MFT reference. */
+ .uses_cookies = 1,
+
+ /*
+ * With NTFS-3g, the extraction order of the names of a file that has a
+ * short name needs to be:
+ *
+ * 1. Create file using the long name that has an associated short name.
+ * This long name is temporarily placed in the POSIX namespace.
+ * 2. Set the short name on the file. This will either change the POSIX
+ * name to Win32 and create a new DOS name, or replace the POSIX name
+ * with a Win32+DOS name.
+ * 3. Create additional long names (links) of the file, which are placed
+ * in the POSIX namespace.
+ *
+ * The reason for this is that two issues can come up when the
+ * extraction is done otherwise:
+ *
+ * - If a DOS name is set on a file in a directory with several long
+ * names, it is ambiguous which long name to use (at least with the
+ * exported ntfs_set_ntfs_dos_name() function).
+ * - NTFS-3g 2013.1.13 will no longer allow even setting the DOS name on
+ * a file with multiple existing long names, even if those long names
+ * are in different directories and the ntfs_set_ntfs_dos_name() call
+ * is therefore unambiguous. (This was apparently changed with the
+ * FUSE interface in mind.)
+ */
+ .requires_short_name_reordering = 1,
};
#endif /* WITH_NTFS_3G */