X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fxml.c;h=db0b3b4daefe8fbde7268fa9a2c490869a48c304;hp=4b1d708da1bd03e01d8c0358f2ef09dbcfdbf0e4;hb=00a775dc256d1fc8254d4f055e362e67f25b66d8;hpb=650997e4865a090b6856c7ca34b02f42994e8e29 diff --git a/src/xml.c b/src/xml.c index 4b1d708d..db0b3b4d 100644 --- a/src/xml.c +++ b/src/xml.c @@ -23,18 +23,26 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ -#include "dentry.h" -#include "lookup_table.h" -#include "timestamp.h" -#include "wimlib_internal.h" -#include "xml.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include +#include "wimlib/dentry.h" +#include "wimlib/encoding.h" +#include "wimlib/error.h" +#include "wimlib/file_io.h" +#include "wimlib/lookup_table.h" +#include "wimlib/metadata.h" +#include "wimlib/resource.h" +#include "wimlib/timestamp.h" +#include "wimlib/xml.h" + +#include #include #include #include -#include #include +#include /* Structures used to form an in-memory representation of the XML data (other * than the raw parse tree from libxml). */ @@ -78,7 +86,7 @@ struct image_info { tchar *display_name; tchar *display_description; tchar *flags; - struct wim_lookup_table *lookup_table; /* Temporary field only */ + struct wim_lookup_table *lookup_table; /* temporary field */ }; struct xml_string_spec { @@ -439,8 +447,8 @@ xml_read_image_info(xmlNode *image_node, struct image_info *image_info) } if (!image_info->name) { tchar *empty_name; - WARNING("Image with index %d has no name", image_info->index); - empty_name = TMALLOC(1); + /*WARNING("Image with index %d has no name", image_info->index);*/ + empty_name = MALLOC(sizeof(tchar)); if (!empty_name) return WIMLIB_ERR_NOMEM; *empty_name = T('\0'); @@ -1006,12 +1014,12 @@ xml_delete_image(struct wim_info **wim_info_p, int image) } size_t -xml_get_max_image_name_len(const WIMStruct *w) +xml_get_max_image_name_len(const WIMStruct *wim) { size_t max_len = 0; - if (w->wim_info) { - for (int i = 0; i < w->wim_info->num_images; i++) { - size_t len = tstrlen(w->wim_info->images[i].name); + if (wim->wim_info) { + for (int i = 0; i < wim->wim_info->num_images; i++) { + size_t len = tstrlen(wim->wim_info->images[i].name); if (len > max_len) max_len = len; } @@ -1033,7 +1041,6 @@ static int calculate_dentry_statistics(struct wim_dentry *dentry, void *arg) { struct image_info *info = arg; - struct wim_lookup_table *lookup_table = info->lookup_table; const struct wim_inode *inode = dentry->d_inode; struct wim_lookup_table_entry *lte; @@ -1090,7 +1097,7 @@ calculate_dentry_statistics(struct wim_dentry *dentry, void *arg) if (inode->i_nlink >= 2 && dentry_is_first_in_inode(dentry)) { for (unsigned i = 0; i < inode->i_num_ads; i++) { if (inode->i_ads_entries[i].stream_name_nbytes) { - lte = inode_stream_lte(inode, i + 1, lookup_table); + lte = inode_stream_lte(inode, i + 1, info->lookup_table); if (lte) { info->hard_link_bytes += inode->i_nlink * wim_resource_size(lte); @@ -1109,21 +1116,21 @@ calculate_dentry_statistics(struct wim_dentry *dentry, void *arg) * But, see calculate_dentry_statistics(). */ void -xml_update_image_info(WIMStruct *w, int image) +xml_update_image_info(WIMStruct *wim, int image) { struct image_info *image_info; DEBUG("Updating the image info for image %d", image); - image_info = &w->wim_info->images[image - 1]; + image_info = &wim->wim_info->images[image - 1]; image_info->file_count = 0; image_info->dir_count = 0; image_info->total_bytes = 0; image_info->hard_link_bytes = 0; - image_info->lookup_table = w->lookup_table; + image_info->lookup_table = wim->lookup_table; - for_dentry_in_tree(w->image_metadata[image - 1].root_dentry, + for_dentry_in_tree(wim->image_metadata[image - 1]->root_dentry, calculate_dentry_statistics, image_info); image_info->last_modification_time = get_wim_timestamp(); @@ -1131,7 +1138,7 @@ xml_update_image_info(WIMStruct *w, int image) /* Adds an image to the XML information. */ int -xml_add_image(WIMStruct *w, const tchar *name) +xml_add_image(WIMStruct *wim, const tchar *name) { struct wim_info *wim_info; struct image_info *image_info; @@ -1140,8 +1147,8 @@ xml_add_image(WIMStruct *w, const tchar *name) /* If this is the first image, allocate the struct wim_info. Otherwise * use the existing struct wim_info. */ - if (w->wim_info) { - wim_info = w->wim_info; + if (wim->wim_info) { + wim_info = wim->wim_info; } else { wim_info = CALLOC(1, sizeof(struct wim_info)); if (!wim_info) @@ -1155,17 +1162,17 @@ xml_add_image(WIMStruct *w, const tchar *name) if (!(image_info->name = TSTRDUP(name))) goto out_destroy_image_info; - w->wim_info = wim_info; + wim->wim_info = wim_info; image_info->index = wim_info->num_images; image_info->creation_time = get_wim_timestamp(); - xml_update_image_info(w, image_info->index); + xml_update_image_info(wim, image_info->index); return 0; out_destroy_image_info: destroy_image_info(image_info); wim_info->num_images--; out_free_wim_info: - if (wim_info != w->wim_info) + if (wim_info != wim->wim_info) FREE(wim_info); return WIMLIB_ERR_NOMEM; } @@ -1212,7 +1219,7 @@ print_image_info(const struct wim_info *wim_info, int image) wim_timestamp_to_str(image_info->creation_time, buf, sizeof(buf)); tprintf(T("Creation Time: %"TS"\n"), buf); - wim_timestamp_to_str(image_info->creation_time, buf, sizeof(buf)); + wim_timestamp_to_str(image_info->last_modification_time, buf, sizeof(buf)); tprintf(T("Last Modification Time: %"TS"\n"), buf); if (image_info->windows_info_exists) print_windows_info(&image_info->windows_info); @@ -1222,14 +1229,14 @@ print_image_info(const struct wim_info *wim_info, int image) } void -libxml_global_init() +libxml_global_init(void) { xmlInitParser(); xmlInitCharEncodingHandlers(); } void -libxml_global_cleanup() +libxml_global_cleanup(void) { xmlCleanupParser(); xmlCleanupCharEncodingHandlers(); @@ -1239,8 +1246,9 @@ libxml_global_cleanup() * Reads the XML data from a WIM file. */ int -read_xml_data(FILE *fp, const struct resource_entry *res_entry, - utf16lechar **xml_data_ret, struct wim_info **info_ret) +read_xml_data(int in_fd, + const struct resource_entry *res_entry, + struct wim_info **info_ret) { utf16lechar *xml_data; xmlDoc *doc; @@ -1268,10 +1276,13 @@ read_xml_data(FILE *fp, const struct resource_entry *res_entry, goto out; } - ret = read_uncompressed_resource(fp, res_entry->offset, - res_entry->size, xml_data); - if (ret != 0) + if (full_pread(in_fd, xml_data, + res_entry->size, res_entry->offset) != res_entry->size) + { + ERROR_WITH_ERRNO("Error reading XML data"); + ret = WIMLIB_ERR_READ; goto out_free_xml_data; + } /* Null-terminate just in case */ ((u8*)xml_data)[res_entry->size] = 0; @@ -1303,13 +1314,7 @@ read_xml_data(FILE *fp, const struct resource_entry *res_entry, ret = WIMLIB_ERR_XML; goto out_free_doc; } - ret = xml_read_wim_info(root, info_ret); - if (ret != 0) - goto out_free_doc; - - *xml_data_ret = xml_data; - xml_data = NULL; out_free_doc: DEBUG("Freeing XML tree."); xmlFreeDoc(doc); @@ -1319,12 +1324,6 @@ out: return ret; } -#define CHECK_RET ({ if (ret < 0) { \ - ERROR("Error writing XML data"); \ - ret = WIMLIB_ERR_WRITE; \ - goto out_free_text_writer; \ - } }) - /* * Writes XML data to a WIM file. * @@ -1333,7 +1332,7 @@ out: * the offset of the XML data. */ int -write_xml_data(const struct wim_info *wim_info, int image, FILE *out, +write_xml_data(const struct wim_info *wim_info, int image, int out_fd, u64 total_bytes, struct resource_entry *out_res_entry) { xmlCharEncodingHandler *encoding_handler; @@ -1347,7 +1346,7 @@ write_xml_data(const struct wim_info *wim_info, int image, FILE *out, (wim_info != NULL && image >= 1 && image <= wim_info->num_images)); - start_offset = ftello(out); + start_offset = filedes_offset(out_fd); if (start_offset == -1) return WIMLIB_ERR_WRITE; @@ -1356,7 +1355,8 @@ write_xml_data(const struct wim_info *wim_info, int image, FILE *out, /* 2 bytes endianness marker for UTF-16LE. This is _required_ for WIM * XML data. */ - if ((putc(0xff, out)) == EOF || (putc(0xfe, out) == EOF)) { + static u8 bom[2] = {0xff, 0xfe}; + if (full_write(out_fd, bom, 2) != 2) { ERROR_WITH_ERRNO("Error writing XML data"); return WIMLIB_ERR_WRITE; } @@ -1382,7 +1382,7 @@ write_xml_data(const struct wim_info *wim_info, int image, FILE *out, goto out; } - out_buffer = xmlOutputBufferCreateFile(out, encoding_handler); + out_buffer = xmlOutputBufferCreateFd(out_fd, encoding_handler); if (!out_buffer) { ERROR("Failed to allocate xmlOutputBuffer"); ret = WIMLIB_ERR_NOMEM; @@ -1399,11 +1399,13 @@ write_xml_data(const struct wim_info *wim_info, int image, FILE *out, DEBUG("Writing element"); ret = xmlTextWriterStartElement(writer, "WIM"); - CHECK_RET; + if (ret < 0) + goto out_write_error; ret = xmlTextWriterWriteFormatElement(writer, "TOTALBYTES", "%"PRIu64, total_bytes); - CHECK_RET; + if (ret < 0) + goto out_write_error; if (wim_info != NULL) { int first, last; @@ -1418,26 +1420,28 @@ write_xml_data(const struct wim_info *wim_info, int image, FILE *out, for (int i = first; i <= last; i++) { ret = xml_write_image_info(writer, &wim_info->images[i - 1]); if (ret) { - CHECK_RET; + if (ret < 0) + goto out_write_error; goto out_free_text_writer; } } } ret = xmlTextWriterEndElement(writer); - CHECK_RET; + if (ret < 0) + goto out_write_error; ret = xmlTextWriterEndDocument(writer); - CHECK_RET; + if (ret < 0) + goto out_write_error; - DEBUG("Ended XML document"); + ret = xmlTextWriterFlush(writer); + if (ret < 0) + goto out_write_error; - /* Call xmlFreeTextWriter() before ftello() because the former will - * flush the file stream. */ - xmlFreeTextWriter(writer); - writer = NULL; + DEBUG("Ended XML document"); - end_offset = ftello(out); + end_offset = filedes_offset(out_fd); if (end_offset == -1) { ret = WIMLIB_ERR_WRITE; } else { @@ -1450,42 +1454,45 @@ write_xml_data(const struct wim_info *wim_info, int image, FILE *out, out_free_text_writer: /* xmlFreeTextWriter will free the attached xmlOutputBuffer. */ xmlFreeTextWriter(writer); - out_buffer = NULL; + goto out; out_output_buffer_close: - if (out_buffer != NULL) - xmlOutputBufferClose(out_buffer); + xmlOutputBufferClose(out_buffer); out: if (ret == 0) DEBUG("Successfully wrote XML data"); return ret; +out_write_error: + ERROR("Error writing XML data"); + ret = WIMLIB_ERR_WRITE; + goto out_free_text_writer; } /* Returns the name of the specified image. */ WIMLIBAPI const tchar * -wimlib_get_image_name(const WIMStruct *w, int image) +wimlib_get_image_name(const WIMStruct *wim, int image) { - if (image < 1 || image > w->hdr.image_count) + if (image < 1 || image > wim->hdr.image_count) return NULL; - return w->wim_info->images[image - 1].name; + return wim->wim_info->images[image - 1].name; } /* Returns the description of the specified image. */ WIMLIBAPI const tchar * -wimlib_get_image_description(const WIMStruct *w, int image) +wimlib_get_image_description(const WIMStruct *wim, int image) { - if (image < 1 || image > w->hdr.image_count) + if (image < 1 || image > wim->hdr.image_count) return NULL; - return w->wim_info->images[image - 1].description; + return wim->wim_info->images[image - 1].description; } /* Determines if an image name is already used by some image in the WIM. */ WIMLIBAPI bool -wimlib_image_name_in_use(const WIMStruct *w, const tchar *name) +wimlib_image_name_in_use(const WIMStruct *wim, const tchar *name) { if (!name || !*name) return false; - for (int i = 1; i <= w->hdr.image_count; i++) - if (!tstrcmp(w->wim_info->images[i - 1].name, name)) + for (int i = 1; i <= wim->hdr.image_count; i++) + if (!tstrcmp(wim->wim_info->images[i - 1].name, name)) return true; return false; } @@ -1493,43 +1500,68 @@ wimlib_image_name_in_use(const WIMStruct *w, const tchar *name) /* Extracts the raw XML data to a file stream. */ WIMLIBAPI int -wimlib_extract_xml_data(WIMStruct *w, FILE *fp) +wimlib_extract_xml_data(WIMStruct *wim, FILE *fp) { - size_t bytes_written; + size_t size; + void *buf; + int ret; + + size = wim->hdr.xml_res_entry.size; + if (sizeof(size_t) < sizeof(u64)) + if (size != wim->hdr.xml_res_entry.size) + return WIMLIB_ERR_INVALID_PARAM; - if (!w->xml_data) - return WIMLIB_ERR_INVALID_PARAM; - bytes_written = fwrite(w->xml_data, 1, w->hdr.xml_res_entry.size, fp); - if (bytes_written != w->hdr.xml_res_entry.size) { + buf = MALLOC(size); + if (!buf) + return WIMLIB_ERR_NOMEM; + + if (full_pread(wim->in_fd, + buf, + wim->hdr.xml_res_entry.size, + wim->hdr.xml_res_entry.offset) != wim->hdr.xml_res_entry.size) + { + ERROR_WITH_ERRNO("Error reading XML data"); + ret = WIMLIB_ERR_READ; + goto out_free_buf; + } + + if (fwrite(buf, 1, size, fp) != size) { ERROR_WITH_ERRNO("Failed to extract XML data"); - return WIMLIB_ERR_WRITE; + ret = WIMLIB_ERR_WRITE; + } else { + ret = 0; } - return 0; +out_free_buf: + FREE(buf); + return ret; } /* Sets the name of an image in the WIM. */ WIMLIBAPI int -wimlib_set_image_name(WIMStruct *w, int image, const tchar *name) +wimlib_set_image_name(WIMStruct *wim, int image, const tchar *name) { tchar *p; int i; + int ret; DEBUG("Setting the name of image %d to %"TS, image, name); - if (!name || !*name) { - ERROR("Must specify a non-empty string for the image name"); - return WIMLIB_ERR_INVALID_PARAM; - } + ret = can_modify_wim(wim); + if (ret) + return ret; + + if (name == NULL) + name = T(""); - if (image < 1 || image > w->hdr.image_count) { + if (image < 1 || image > wim->hdr.image_count) { ERROR("%d is not a valid image", image); return WIMLIB_ERR_INVALID_IMAGE; } - for (i = 1; i <= w->hdr.image_count; i++) { + for (i = 1; i <= wim->hdr.image_count; i++) { if (i == image) continue; - if (tstrcmp(w->wim_info->images[i - 1].name, name) == 0) { + if (!tstrcmp(wim->wim_info->images[i - 1].name, name)) { ERROR("The name \"%"TS"\" is already in use in the WIM!", name); return WIMLIB_ERR_IMAGE_NAME_COLLISION; @@ -1540,19 +1572,24 @@ wimlib_set_image_name(WIMStruct *w, int image, const tchar *name) if (!p) return WIMLIB_ERR_NOMEM; - FREE(w->wim_info->images[image - 1].name); - w->wim_info->images[image - 1].name = p; + FREE(wim->wim_info->images[image - 1].name); + wim->wim_info->images[image - 1].name = p; return 0; } static int -do_set_image_info_str(WIMStruct *w, int image, const tchar *tstr, +do_set_image_info_str(WIMStruct *wim, int image, const tchar *tstr, size_t offset) { tchar *tstr_copy; tchar **dest_tstr_p; + int ret; + + ret = can_modify_wim(wim); + if (ret) + return ret; - if (image < 1 || image > w->hdr.image_count) { + if (image < 1 || image > wim->hdr.image_count) { ERROR("%d is not a valid image", image); return WIMLIB_ERR_INVALID_IMAGE; } @@ -1563,7 +1600,7 @@ do_set_image_info_str(WIMStruct *w, int image, const tchar *tstr, } else { tstr_copy = NULL; } - dest_tstr_p = (tchar**)((void*)&w->wim_info->images[image - 1] + offset); + dest_tstr_p = (tchar**)((void*)&wim->wim_info->images[image - 1] + offset); FREE(*dest_tstr_p); *dest_tstr_p = tstr_copy; @@ -1572,17 +1609,17 @@ do_set_image_info_str(WIMStruct *w, int image, const tchar *tstr, /* Sets the description of an image in the WIM. */ WIMLIBAPI int -wimlib_set_image_descripton(WIMStruct *w, int image, +wimlib_set_image_descripton(WIMStruct *wim, int image, const tchar *description) { - return do_set_image_info_str(w, image, description, + return do_set_image_info_str(wim, image, description, offsetof(struct image_info, description)); } /* Set the element of a WIM image */ WIMLIBAPI int -wimlib_set_image_flags(WIMStruct *w, int image, const tchar *flags) +wimlib_set_image_flags(WIMStruct *wim, int image, const tchar *flags) { - return do_set_image_info_str(w, image, flags, + return do_set_image_info_str(wim, image, flags, offsetof(struct image_info, flags)); }