+/*
+ * Copyright (C) 2012 Eric Biggers
+ *
+ * This file is part of wimlib, a library for working with WIM files.
+ *
+ * wimlib 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 2.1 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ */
+
#include "dentry.h"
#include "io.h"
#include "lookup_table.h"
#include "sha1.h"
+#include <errno.h>
/*
* Find the symlink target of a symbolic link or junction point in the WIM.
void *buf = MALLOC(len);
if (!buf)
goto out;
+ /* XXX Fix absolute paths */
u8 *p = buf;
p = put_u16(p, 0); /* Substitute name offset */
p = put_u16(p, utf16_len); /* Substitute name length */
p = put_u16(p, utf16_len); /* Print name offset */
p = put_u16(p, utf16_len); /* Print name length */
- p = put_u32(p, (symlink_target[0] == '/') ? 0 : 1);
+ p = put_u32(p, 1);
p = put_bytes(p, utf16_len, name_utf16);
p = put_bytes(p, utf16_len, name_utf16);
/*DEBUG("utf16_len = %zu, len = %zu", utf16_len, len);*/
return buf;
}
+static const struct lookup_table_entry *
+dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table)
+{
+ const struct lookup_table_entry *lte;
+ if (dentry->resolved) {
+ if (dentry->lte)
+ return dentry->lte;
+ for (u16 i = 0; i < dentry->num_ads; i++)
+ if (dentry->ads_entries[i].lte)
+ return dentry->ads_entries[i].lte;
+ } else {
+ const u8 *hash = dentry->hash;
+ u16 i = 0;
+ while (1) {
+ if ((lte = __lookup_resource(table, hash)))
+ break;
+ if (i == dentry->num_ads)
+ return NULL;
+ hash = dentry->ads_entries[i].hash;
+ i++;
+ }
+ }
+ return NULL;
+}
+
/* Get the symlink target from a dentry that's already checked to be either a
* "real" symlink or a junction point. */
ssize_t dentry_readlink(const struct dentry *dentry, char *buf, size_t buf_len,
const WIMStruct *w)
{
- struct resource_entry *res_entry;
- struct lookup_table_entry *lte;
- u16 i = 0;
- const u8 *hash = dentry->hash;
+ const struct resource_entry *res_entry;
+ const struct lookup_table_entry *lte;
wimlib_assert(dentry_is_symlink(dentry));
- while (1) {
- if ((lte = __lookup_resource(w->lookup_table, hash)))
- break;
- if (i == dentry->num_ads)
- return -EIO;
- hash = dentry->ads_entries[i].hash;
- i++;
- }
+ lte = dentry_first_lte(dentry, w->lookup_table);
+ if (!lte)
+ return -EIO;
+
res_entry = <e->resource_entry;
if (res_entry->original_size > 10000)
return -EIO;
- char res_buf[res_entry->original_size];
- if (read_full_resource(w->fp, res_entry->size,
- res_entry->original_size,
- res_entry->offset,
- wim_resource_compression_type(w, res_entry),
- res_buf) != 0)
- return -EIO;
+ char __res_buf[res_entry->original_size];
+ const char *res_buf;
+ if (lte->is_symlink && lte->symlink_buf) {
+ res_buf = lte->symlink_buf;
+ } else {
+ res_buf = __res_buf;
+ if (read_full_resource(w->fp, res_entry->size,
+ res_entry->original_size,
+ res_entry->offset,
+ wim_resource_compression_type(w, res_entry),
+ __res_buf) != 0)
+ return -EIO;
+ res_buf = __res_buf;
+ }
return get_symlink_name(res_buf, res_entry->original_size, buf,
buf_len, dentry->reparse_tag);
}
if (!ads_entries)
return WIMLIB_ERR_NOMEM;
memcpy(ads_entries[1].hash, symlink_buf_hash, WIM_HASH_SIZE);
- dentry_free_ads_entries(dentry);
+ wimlib_assert(dentry->num_ads == 0);
+ wimlib_assert(!dentry->ads_entries);
+ /*dentry_free_ads_entries(dentry);*/
dentry->num_ads = 2;
dentry->ads_entries = ads_entries;
return 0;
}
int dentry_set_symlink(struct dentry *dentry, const char *target,
- struct lookup_table *lookup_table)
+ struct lookup_table *lookup_table,
+ struct lookup_table_entry **lte_ret)
{
int ret;
if (existing_lte) {
existing_lte->refcnt++;
+ lte = existing_lte;
} else {
DEBUG("Creating new lookup table entry for symlink buf");
lte = new_lookup_table_entry();
if (!existing_lte)
lookup_table_insert(lookup_table, lte);
+ if (lte_ret)
+ *lte_ret = lte;
return 0;
out_free_lte:
- FREE(lte);
+ if (lte != existing_lte)
+ FREE(lte);
out_free_symlink_buf:
FREE(symlink_buf);
return ret;