X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fdentry.c;h=1f0fd86c7e047a4121757ed12c84318aa21e99c6;hp=4d3fc6825e41c726e6a3e8d09644d2b49557a89f;hb=d4b9c90b4979c07c049b06be709187a60c17112b;hpb=b6fa6d370a09247a608e6a46a3d9e761d10a8a39 diff --git a/src/dentry.c b/src/dentry.c index 4d3fc682..1f0fd86c 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -10,24 +10,21 @@ */ /* - * - * Copyright (C) 2010 Carl Thijssen * 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. + * 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 Lesser General Public License for more - * details. + * A PARTICULAR PURPOSE. See the GNU 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/. + * You should have received a copy of the GNU General Public License along with + * wimlib; if not, see http://www.gnu.org/licenses/. */ #include @@ -110,9 +107,9 @@ void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry) dentry->attributes = FILE_ATTRIBUTE_NORMAL; } if (sizeof(ino_t) >= 8) - dentry->hard_link = (u64)stbuf->st_ino; + dentry->link_group_id = (u64)stbuf->st_ino; else - dentry->hard_link = (u64)stbuf->st_ino | + dentry->link_group_id = (u64)stbuf->st_ino | ((u64)stbuf->st_dev << (sizeof(ino_t) * 8)); /* Set timestamps */ dentry->creation_time = timespec_to_wim_timestamp(&stbuf->st_mtim); @@ -170,19 +167,51 @@ struct ads_entry *dentry_add_ads(struct dentry *dentry, const char *stream_name) DEBUG("Add alternate data stream %s:%s", dentry->file_name_utf8, stream_name); - if (dentry->num_ads == 0xffff) + if (dentry->num_ads == 0xffff) { + ERROR("Too many alternate data streams in one dentry!"); return NULL; + } num_ads = dentry->num_ads + 1; ads_entries = REALLOC(dentry->ads_entries, - num_ads * sizeof(struct ads_entry)); - if (!ads_entries) + num_ads * sizeof(dentry->ads_entries[0])); + if (!ads_entries) { + ERROR("Failed to allocate memory for new alternate data stream"); return NULL; + } + wimlib_assert(ads_entries == dentry->ads_entries || + ads_entries < dentry->ads_entries || + ads_entries > dentry->ads_entries + dentry->num_ads); if (ads_entries != dentry->ads_entries) { /* We moved the ADS entries. Adjust the stream lists. */ for (u16 i = 0; i < dentry->num_ads; i++) { struct list_head *cur = &ads_entries[i].lte_group_list.list; - cur->prev->next = cur; - cur->next->prev = cur; + struct list_head *prev = cur->prev; + struct list_head *next = cur->next; + if ((u8*)prev >= (u8*)dentry->ads_entries + && (u8*)prev < (u8*)(dentry->ads_entries + dentry->num_ads)) { + /* Previous entry was located in the same ads_entries + * array! Adjust our own prev pointer. */ + u16 idx = (struct ads_entry*)prev - + (struct ads_entry*)&dentry->ads_entries[0].lte_group_list.list; + cur->prev = &ads_entries[idx].lte_group_list.list; + } else { + /* Previous entry is located in a different ads_entries + * array. Adjust its next pointer. */ + prev->next = cur; + } + next = cur->next; + if ((u8*)next >= (u8*)dentry->ads_entries + && (u8*)next < (u8*)(dentry->ads_entries + dentry->num_ads)) { + /* Next entry was located in the same ads_entries array! + * Adjust our own next pointer. */ + u16 idx = (struct ads_entry*)next - + (struct ads_entry*)&dentry->ads_entries[0].lte_group_list.list; + cur->next = &ads_entries[idx].lte_group_list.list; + } else { + /* Next entry is located in a different ads_entries + * array. Adjust its prev pointer. */ + next->prev = cur; + } } } @@ -479,6 +508,8 @@ int print_dentry(struct dentry *dentry, void *lookup_table) { const u8 *hash; struct lookup_table_entry *lte; + time_t time; + char *p; printf("[DENTRY]\n"); printf("Length = %"PRIu64"\n", dentry->length); @@ -500,15 +531,23 @@ int print_dentry(struct dentry *dentry, void *lookup_table) #endif /* Translate the timestamps into something readable */ - time_t creat_time = wim_timestamp_to_unix(dentry->creation_time); - time_t access_time = wim_timestamp_to_unix(dentry->last_access_time); - time_t mod_time = wim_timestamp_to_unix(dentry->last_write_time); - printf("Creation Time = %s", asctime(gmtime(&creat_time))); - printf("Last Access Time = %s", asctime(gmtime(&access_time))); - printf("Last Write Time = %s", asctime(gmtime(&mod_time))); + time = wim_timestamp_to_unix(dentry->creation_time); + p = asctime(gmtime(&time)); + *(strrchr(p, '\n')) = '\0'; + printf("Creation Time = %s UTC\n", p); + + time = wim_timestamp_to_unix(dentry->last_access_time); + p = asctime(gmtime(&time)); + *(strrchr(p, '\n')) = '\0'; + printf("Last Access Time = %s UTC\n", p); + + time = wim_timestamp_to_unix(dentry->last_write_time); + p = asctime(gmtime(&time)); + *(strrchr(p, '\n')) = '\0'; + printf("Last Write Time = %s UTC\n", p); printf("Reparse Tag = 0x%"PRIx32"\n", dentry->reparse_tag); - printf("Hard Link Group = 0x%"PRIx64"\n", dentry->hard_link); + printf("Hard Link Group = 0x%"PRIx64"\n", dentry->link_group_id); printf("Number of Alternate Data Streams = %hu\n", dentry->num_ads); printf("Filename = \""); print_string(dentry->file_name, dentry->file_name_len); @@ -584,6 +623,7 @@ struct dentry *new_dentry(const char *name) dentry->prev = dentry; dentry->parent = dentry; INIT_LIST_HEAD(&dentry->link_group_list); + INIT_LIST_HEAD(&dentry->lte_group_list.list); return dentry; err: FREE(dentry); @@ -606,7 +646,8 @@ static void __destroy_dentry(struct dentry *dentry) FREE(dentry->file_name_utf8); FREE(dentry->short_name); FREE(dentry->full_path_utf8); - FREE(dentry->extracted_file); + if (dentry->extracted_file != dentry->full_path_utf8) + FREE(dentry->extracted_file); } /* Frees a WIM dentry. */ @@ -637,7 +678,6 @@ void put_dentry(struct dentry *dentry) } dentry->ads_entries_status = ADS_ENTRIES_USER; } - struct list_head *next; list_del(&dentry->link_group_list); free_dentry(dentry); } @@ -798,6 +838,8 @@ int change_dentry_name(struct dentry *dentry, const char *new_name) ret = get_names(&dentry->file_name, &dentry->file_name_utf8, &dentry->file_name_len, &dentry->file_name_utf8_len, new_name); + FREE(dentry->short_name); + dentry->short_name_len = 0; if (ret == 0) dentry->length = dentry_correct_length(dentry); return ret; @@ -927,7 +969,7 @@ static int read_ads_entries(const u8 *p, struct dentry *dentry, u64 length_no_padding; u64 total_length; size_t utf8_len; - const char *p_save = p; + const u8 *p_save = p; /* Read the base stream entry, excluding the stream name. */ if (remaining_size < WIM_ADS_ENTRY_DISK_SIZE) { @@ -958,7 +1000,7 @@ static int read_ads_entries(const u8 *p, struct dentry *dentry, if (remaining_size < length_no_padding) { ERROR("Stream entries go past end of metadata resource"); ERROR("(remaining_size = %"PRIu64" bytes, " - "length_no_padding = %"PRIu16" bytes)", + "length_no_padding = %"PRIu64" bytes)", remaining_size, length_no_padding); ret = WIMLIB_ERR_INVALID_DENTRY; goto out_free_ads_entries; @@ -1048,7 +1090,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, char *short_name = NULL; u16 short_name_len; u16 file_name_len; - size_t file_name_utf8_len; + size_t file_name_utf8_len = 0; int ret; dentry_common_init(dentry); @@ -1122,7 +1164,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, p += 4; } else { p = get_u32(p, &dentry->reparse_tag); - p = get_u64(p, &dentry->hard_link); + p = get_u64(p, &dentry->link_group_id); } /* By the way, the reparse_reserved field does not actually exist (at @@ -1205,9 +1247,9 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, * u64 reserved1; (always 0) * u64 reserved2; (always 0) * };*/ - WARNING("Dentry for file or directory `%s' has %zu extra " - "bytes of data", - file_name_utf8, dentry->length - calculated_size); + DEBUG("Dentry for file or directory `%s' has %zu extra " + "bytes of data", + file_name_utf8, dentry->length - calculated_size); } /* Read the short filename if present. Note: if there is no short @@ -1310,14 +1352,11 @@ int verify_dentry(struct dentry *dentry, void *wim) /* Make sure there is only one un-named stream. */ unsigned num_unnamed_streams = 0; - unsigned unnamed_stream_idx; for (unsigned i = 0; i <= dentry->num_ads; i++) { const u8 *hash; hash = dentry_stream_hash_unresolved(dentry, i); - if (!dentry_stream_name_len(dentry, i) && !is_zero_hash(hash)) { + if (!dentry_stream_name_len(dentry, i) && !is_zero_hash(hash)) num_unnamed_streams++; - unnamed_stream_idx = i; - } } if (num_unnamed_streams > 1) { ERROR("Dentry `%s' has multiple (%u) un-named streams", @@ -1325,6 +1364,22 @@ int verify_dentry(struct dentry *dentry, void *wim) goto out; } + /* Cannot have a short name but no long name */ + if (dentry->short_name_len && !dentry->file_name_len) { + ERROR("Dentry `%s' has a short name but no long name", + dentry->full_path_utf8); + goto out; + } + + /* Make sure root dentry is unnamed */ + if (dentry_is_root(dentry)) { + if (dentry->file_name_len) { + ERROR("The root dentry is named `%s', but it must " + "be unnamed", dentry->file_name_utf8); + goto out; + } + } + #if 0 /* Check timestamps */ if (dentry->last_access_time < dentry->creation_time || @@ -1350,7 +1405,6 @@ out: static u8 *write_dentry(const struct dentry *dentry, u8 *p) { u8 *orig_p = p; - unsigned padding; const u8 *hash; /* We calculate the correct length of the dentry ourselves because the @@ -1368,23 +1422,20 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p) p = put_u64(p, dentry->creation_time); p = put_u64(p, dentry->last_access_time); p = put_u64(p, dentry->last_write_time); - if (dentry->resolved && dentry->lte) - hash = dentry->lte->hash; - else - hash = dentry->hash; + hash = dentry_stream_hash(dentry, 0); p = put_bytes(p, SHA1_HASH_SIZE, hash); if (dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT) { p = put_zeroes(p, 4); p = put_u32(p, dentry->reparse_tag); p = put_zeroes(p, 4); } else { - u64 hard_link; + u64 link_group_id; p = put_u32(p, 0); if (dentry->link_group_list.next == &dentry->link_group_list) - hard_link = 0; + link_group_id = 0; else - hard_link = dentry->hard_link; - p = put_u64(p, hard_link); + link_group_id = dentry->link_group_id; + p = put_u64(p, link_group_id); } p = put_u16(p, dentry->num_ads); p = put_u16(p, dentry->short_name_len); @@ -1409,10 +1460,7 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p) for (u16 i = 0; i < dentry->num_ads; i++) { p = put_u64(p, ads_entry_total_length(&dentry->ads_entries[i])); p = put_u64(p, 0); /* Unused */ - if (dentry->resolved && dentry->ads_entries[i].lte) - hash = dentry->ads_entries[i].lte->hash; - else - hash = dentry->ads_entries[i].hash; + hash = dentry_stream_hash(dentry, i + 1); p = put_bytes(p, SHA1_HASH_SIZE, hash); p = put_u16(p, dentry->ads_entries[i].stream_name_len); if (dentry->ads_entries[i].stream_name_len) {