extern int
wim_inode_get_reparse_data(const struct wim_inode * restrict inode,
- u8 * restrict rpbuf);
+ u8 * restrict rpbuf,
+ u16 * restrict rpbuflen_ret);
#ifndef __WIN32__
ssize_t
#include <ntfs-3g/xattrs.h>
#include "wimlib/apply.h"
-#include "wimlib/buffer_io.h"
+#include "wimlib/compiler.h"
#include "wimlib/dentry.h"
#include "wimlib/encoding.h"
#include "wimlib/error.h"
apply_reparse_data(ntfs_inode *ni, struct wim_dentry *dentry,
union wimlib_progress_info *progress_info)
{
- struct wim_lookup_table_entry *lte;
int ret;
-
- lte = inode_unnamed_lte_resolved(dentry->d_inode);
+ u8 rpbuf[REPARSE_POINT_MAX_SIZE] _aligned_attribute(8);
+ u16 rpbuflen;
DEBUG("Applying reparse data to `%s'", dentry->_full_path);
- if (!lte) {
- ERROR("Could not find reparse data for `%s'",
- dentry->_full_path);
- return WIMLIB_ERR_INVALID_DENTRY;
- }
-
- /* "Reparse point data, including the tag and optional GUID, cannot
- * exceed 16 kilobytes." - MSDN */
- if (wim_resource_size(lte) > REPARSE_POINT_MAX_SIZE - 8) {
- ERROR("Reparse data of `%s' is too long (%"PRIu64" bytes)",
- dentry->_full_path, wim_resource_size(lte));
- return WIMLIB_ERR_INVALID_DENTRY;
- }
-
- u8 reparse_data_buf[8 + wim_resource_size(lte)];
- u8 *p = reparse_data_buf;
- p = put_u32(p, dentry->d_inode->i_reparse_tag); /* ReparseTag */
- DEBUG("ReparseTag = %#x", dentry->d_inode->i_reparse_tag);
- p = put_u16(p, wim_resource_size(lte)); /* ReparseDataLength */
- p = put_u16(p, 0); /* Reserved */
-
- ret = read_full_resource_into_buf(lte, p);
+ ret = wim_inode_get_reparse_data(dentry->d_inode, rpbuf, &rpbuflen);
if (ret)
return ret;
- ret = ntfs_set_ntfs_reparse_data(ni, (char*)reparse_data_buf,
- wim_resource_size(lte) + 8, 0);
+ ret = ntfs_set_ntfs_reparse_data(ni, rpbuf, rpbuflen, 0);
if (ret) {
ERROR_WITH_ERRNO("Failed to set NTFS reparse data on `%s'",
dentry->_full_path);
return WIMLIB_ERR_NTFS_3G;
- } else {
- progress_info->extract.completed_bytes += wim_resource_size(lte);
}
- return ret;
+
+ progress_info->extract.completed_bytes += rpbuflen - 8;
+ return 0;
}
/*
{
struct apply_args *args = arg;
ntfs_volume *vol = args->vol;
- u8 *p;
- u8 buf[24];
+ u64 ntfs_timestamps[3];
ntfs_inode *ni;
int ret;
return WIMLIB_ERR_NTFS_3G;
}
- p = buf;
- p = put_u64(p, dentry->d_inode->i_creation_time);
- p = put_u64(p, dentry->d_inode->i_last_write_time);
- p = put_u64(p, dentry->d_inode->i_last_access_time);
- ret = ntfs_inode_set_times(ni, (const char*)buf, 3 * sizeof(u64), 0);
+ /* Note: ntfs_inode_set_times() expects the times in native byte order,
+ * not little endian. */
+ ntfs_timestamps[0] = dentry->d_inode->i_creation_time;
+ ntfs_timestamps[1] = dentry->d_inode->i_last_write_time;
+ ntfs_timestamps[2] = dentry->d_inode->i_last_access_time;
+ ret = ntfs_inode_set_times(ni, (const char*)ntfs_timestamps,
+ sizeof(ntfs_timestamps), 0);
if (ret != 0) {
ERROR_WITH_ERRNO("Failed to set NTFS timestamps on `%s'",
dentry->_full_path);
#include <errno.h>
#include <stdlib.h>
+struct reparse_buffer_disk {
+ le32 rptag;
+ le16 rpdatalen;
+ le16 rpreserved;
+ le16 substitute_name_offset;
+ le16 substitute_name_nbytes;
+ le16 print_name_offset;
+ le16 print_name_nbytes;
+ union {
+ struct {
+ le32 rpflags;
+ u8 data[REPARSE_POINT_MAX_SIZE - 20];
+ } _packed_attribute symlink;
+ struct {
+ u8 data[REPARSE_POINT_MAX_SIZE - 16];
+ } _packed_attribute junction;
+ };
+} _packed_attribute;
+
static const utf16lechar volume_junction_prefix[11] = {
cpu_to_le16('\\'),
cpu_to_le16('\\'),
}
}
-struct reparse_buffer_disk {
- le32 rptag;
- le16 rpdatalen;
- le16 rpreserved;
- le16 substitute_name_offset;
- le16 substitute_name_nbytes;
- le16 print_name_offset;
- le16 print_name_nbytes;
- union {
- struct {
- le32 rpflags;
- u8 data[REPARSE_POINT_MAX_SIZE - 20];
- } _packed_attribute symlink;
- struct {
- u8 data[REPARSE_POINT_MAX_SIZE - 16];
- } _packed_attribute junction;
- };
-} _packed_attribute;
-
/*
* Read the data from a symbolic link, junction, or mount point reparse point
* buffer into a `struct reparse_data'.
*/
int
wim_inode_get_reparse_data(const struct wim_inode * restrict inode,
- u8 * restrict rpbuf)
+ u8 * restrict rpbuf,
+ u16 * restrict rpbuflen_ret)
{
struct wim_lookup_table_entry *lte;
int ret;
struct reparse_buffer_disk *rpbuf_disk;
+ u16 rpdatalen;
wimlib_assert(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT);
ERROR("Reparse point has no reparse data!");
return WIMLIB_ERR_INVALID_REPARSE_DATA;
}
+
if (wim_resource_size(lte) > REPARSE_POINT_MAX_SIZE - 8) {
ERROR("Reparse data is too long!");
return WIMLIB_ERR_INVALID_REPARSE_DATA;
}
+ rpdatalen = wim_resource_size(lte);
/* Read the data from the WIM file */
ret = read_full_resource_into_buf(lte, rpbuf + 8);
rpbuf_disk->rptag = cpu_to_le32(inode->i_reparse_tag);
/* ReparseDataLength */
- rpbuf_disk->rpdatalen = cpu_to_le16(wim_resource_size(lte));
+ rpbuf_disk->rpdatalen = cpu_to_le16(rpdatalen);
/* ReparseReserved
* XXX this could be one of the unknown fields in the WIM dentry. */
rpbuf_disk->rpreserved = cpu_to_le16(0);
+
+ *rpbuflen_ret = rpdatalen + 8;
return 0;
}
{
int ret;
struct reparse_buffer_disk rpbuf_disk _aligned_attribute(8);
- u16 rpdatalen;
struct reparse_data rpdata;
char *link_target;
char *translated_target;
size_t link_target_len;
+ u16 rpbuflen;
wimlib_assert(inode_is_symlink(inode));
- if (wim_inode_get_reparse_data(inode, (u8*)&rpbuf_disk))
+ if (wim_inode_get_reparse_data(inode, (u8*)&rpbuf_disk, &rpbuflen))
return -EIO;
- if (parse_reparse_data((const u8*)&rpbuf_disk,
- le16_to_cpu(rpbuf_disk.rpdatalen) + 8, &rpdata))
+ if (parse_reparse_data((const u8*)&rpbuf_disk, rpbuflen, &rpdata))
return -EIO;
ret = utf16le_to_tstr(rpdata.substitute_name,
case SUBST_NAME_IS_UNKNOWN:
ERROR("Can't understand reparse point "
"substitute name \"%s\"", link_target);
- return -EIO;
+ ret = -EIO;
+ goto out_free_link_target;
default:
translated_target += ret;
link_target_len -= ret;
ret = link_target_len;
}
memcpy(buf, translated_target, link_target_len);
+out_free_link_target:
FREE(link_target);
return ret;
}
int ret;
u8 rpbuf[REPARSE_POINT_MAX_SIZE];
DWORD bytesReturned;
+ u16 rpbuflen;
DEBUG("Setting reparse data on \"%ls\"", path);
- ret = wim_inode_get_reparse_data(inode, rpbuf);
+ ret = wim_inode_get_reparse_data(inode, rpbuf, &rpbuflen);
if (ret)
return ret;
* "Not used with this operation; set to NULL."
*/
if (!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, rpbuf,
- 8 + le16_to_cpu(*(u16*)(rpbuf + 4)),
+ rpbuflen,
NULL, 0,
&bytesReturned /* lpBytesReturned */,
NULL /* lpOverlapped */))