/*
* Copyright (C) 2012, 2013 Eric Biggers
*
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
*
- * wimlib 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 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib 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
+ * This file 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 Lesser General Public License for more
* details.
*
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+#include <errno.h>
+
+#include "wimlib/alloca.h"
#include "wimlib/assert.h"
+#include "wimlib/blob_table.h"
#include "wimlib/compiler.h"
#include "wimlib/endianness.h"
#include "wimlib/encoding.h"
#include "wimlib/error.h"
#include "wimlib/inode.h"
-#include "wimlib/lookup_table.h"
#include "wimlib/reparse.h"
#include "wimlib/resource.h"
-#ifdef HAVE_ALLOCA_H
-# include <alloca.h>
-#endif
-#include <errno.h>
-#include <stdlib.h>
-
/*
* Read the data from a symbolic link, junction, or mount point reparse point
* buffer into a `struct reparse_data'.
data = mempcpy(data, rpdata->print_name, rpdata->print_name_nbytes);
*(utf16lechar*)data = cpu_to_le16(0);
data += 2;
- rpbuf_disk->rpdatalen = cpu_to_le16(data - rpbuf - 8);
+ rpbuf_disk->rpdatalen = cpu_to_le16(data - rpbuf - REPARSE_DATA_OFFSET);
*rpbuflen_ret = data - rpbuf;
return 0;
}
*
* Note: in the WIM format, the first 8 bytes of the reparse point data buffer
* are omitted, presumably because we already know the reparse tag from the
- * dentry, and we already know the reparse tag length from the lookup table
- * entry resource length. However, we reconstruct the first 8 bytes in the
- * buffer returned by this function.
+ * dentry, and we already know the reparse tag length from the blob length.
+ * However, we reconstruct the first 8 bytes in the buffer returned by this
+ * function.
*/
-int
+static int
wim_inode_get_reparse_data(const struct wim_inode * restrict inode,
u8 * restrict rpbuf,
u16 * restrict rpbuflen_ret,
- struct wim_lookup_table_entry *lte_override)
+ struct blob_descriptor *blob_override)
{
- struct wim_lookup_table_entry *lte;
+ struct blob_descriptor *blob;
int ret;
struct reparse_buffer_disk *rpbuf_disk;
u16 rpdatalen;
wimlib_assert(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT);
- if (!lte_override) {
- lte = inode_unnamed_lte_resolved(inode);
- if (!lte) {
+ if (blob_override) {
+ blob = blob_override;
+ } else {
+ struct wim_inode_stream *strm;
+
+ strm = inode_get_unnamed_stream(inode, STREAM_TYPE_REPARSE_POINT);
+ if (strm)
+ blob = stream_blob_resolved(strm);
+ else
+ blob = NULL;
+ if (!blob) {
ERROR("Reparse point has no reparse data!");
return WIMLIB_ERR_INVALID_REPARSE_DATA;
}
- } else {
- lte = lte_override;
}
- if (lte->size > REPARSE_POINT_MAX_SIZE - 8) {
+ if (blob->size > REPARSE_DATA_MAX_SIZE) {
ERROR("Reparse data is too long!");
return WIMLIB_ERR_INVALID_REPARSE_DATA;
}
- rpdatalen = lte->size;
+ rpdatalen = blob->size;
- /* Read the data from the WIM file */
- ret = read_full_stream_into_buf(lte, rpbuf + 8);
+ /* Read the reparse data from blob */
+ ret = read_full_blob_into_buf(blob, rpbuf + REPARSE_DATA_OFFSET);
if (ret)
return ret;
* XXX this could be one of the unknown fields in the WIM dentry. */
rpbuf_disk->rpreserved = cpu_to_le16(0);
- *rpbuflen_ret = rpdatalen + 8;
+ *rpbuflen_ret = rpdatalen + REPARSE_DATA_OFFSET;
return 0;
}
/*
* Get the UNIX-style symlink target from the WIM inode for a reparse point.
* Specifically, this translates the target from UTF-16 to the current multibyte
- * encoding, strips the drive prefix if present, and replaces backslashes with
+ * encoding, strips the drive prefix if present, and swaps backslashes and
* forward slashes.
*
* @inode
* @bufsize
* Available space in @buf, in bytes.
*
- * @lte_override
- * If not NULL, the stream from which to read the reparse data. Otherwise,
- * the reparse data will be read from the unnamed stream of @inode.
+ * @blob_override
+ * If not NULL, the blob from which to read the reparse data. Otherwise,
+ * the reparse data will be read from the reparse point stream of @inode.
*
* If the entire symbolic link target was placed in the buffer, returns the
* number of bytes written. The resulting string is not null-terminated. If
ssize_t
wim_inode_readlink(const struct wim_inode * restrict inode,
char * restrict buf, size_t bufsize,
- struct wim_lookup_table_entry *lte_override)
+ struct blob_descriptor *blob_override)
{
int ret;
struct reparse_buffer_disk rpbuf_disk _aligned_attribute(8);
wimlib_assert(inode_is_symlink(inode));
if (wim_inode_get_reparse_data(inode, (u8*)&rpbuf_disk, &rpbuflen,
- lte_override))
+ blob_override))
return -EIO;
if (parse_reparse_data((const u8*)&rpbuf_disk, rpbuflen, &rpdata))
}
out_translate_slashes:
- for (size_t i = 0; i < link_target_len; i++)
+ for (size_t i = 0; i < link_target_len; i++) {
if (translated_target[i] == '\\')
translated_target[i] = '/';
+ else if (translated_target[i] == '/')
+ translated_target[i] = '\\';
+ }
out_have_link:
if (link_target_len > bufsize) {
link_target_len = bufsize;
return ret;
}
+/* Given a UNIX-style symbolic link target, create a Windows-style reparse point
+ * buffer and assign it to the specified inode. */
int
-wim_inode_set_symlink(struct wim_inode *inode,
- const char *target,
- struct wim_lookup_table *lookup_table)
+wim_inode_set_symlink(struct wim_inode *inode, const char *target,
+ struct blob_table *blob_table)
{
struct reparse_buffer_disk rpbuf_disk _aligned_attribute(8);
ret = tstr_to_utf16le(target, strlen(target),
&name_utf16le, &name_utf16le_nbytes);
if (ret)
- return ret;
+ goto out;
- for (size_t i = 0; i < name_utf16le_nbytes / 2; i++)
+ for (size_t i = 0; i < name_utf16le_nbytes / 2; i++) {
if (name_utf16le[i] == cpu_to_le16('/'))
name_utf16le[i] = cpu_to_le16('\\');
+ else if (name_utf16le[i] == cpu_to_le16('\\'))
+ name_utf16le[i] = cpu_to_le16('/');
+ }
/* Compatability notes:
*
* is a relative symbolic link. (Quite simple compared to the various
* ways to provide Windows paths.)
*
- * To change a UNIX relative symbolic link to Windows format, we only
- * need to translate it to UTF-16LE and replace forward slashes with
- * backslashes. We do not make any attempt to handle filename character
- * problems, such as a link target that itself contains backslashes on
- * UNIX. Then, for these relative links, we set the reparse header
- * @flags field to SYMBOLIC_LINK_RELATIVE.
+ * To change a UNIX relative symbolic link to Windows format, we need to
+ * translate it to UTF-16LE, swap forward slashes and backslashes, and
+ * set 'rpflags' to SYMBOLIC_LINK_RELATIVE.
*
* For UNIX absolute symbolic links, we must set the @flags field to 0.
* Then, there are multiple options as to actually represent the
}
ret = make_reparse_buffer(&rpdata, (u8*)&rpbuf_disk, &rpbuflen);
- if (ret == 0) {
- ret = inode_set_unnamed_stream(inode,
- (u8*)&rpbuf_disk + 8,
- rpbuflen - 8,
- lookup_table);
- }
+ if (ret)
+ goto out_free_name;
+
+ ret = WIMLIB_ERR_NOMEM;
+ if (!inode_add_stream_with_data(inode,
+ STREAM_TYPE_REPARSE_POINT,
+ NO_STREAM_NAME,
+ (u8*)&rpbuf_disk + REPARSE_DATA_OFFSET,
+ rpbuflen - REPARSE_DATA_OFFSET,
+ blob_table))
+ goto out_free_name;
+
+ ret = 0;
+out_free_name:
FREE(name_utf16le);
+out:
return ret;
}