X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;ds=sidebyside;f=src%2Fextract_image.c;h=a24f0ab551358192d01f9286e8f219de1a373205;hb=9e2571b03cd9c71d11b3dad9ea5dcfa43f50deb4;hp=199d20b27ee50362959aa1062e29130e39a40aef;hpb=14baa6ae892debbaa18dba8119931580efd0e517;p=wimlib diff --git a/src/extract_image.c b/src/extract_image.c index 199d20b2..a24f0ab5 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -58,9 +58,36 @@ #endif #ifndef __WIN32__ + +/* Returns the number of components of @path. */ +static unsigned +get_num_path_components(const char *path) +{ + unsigned num_components = 0; + while (*path) { + while (*path == '/') + path++; + if (*path) + num_components++; + while (*path && *path != '/') + path++; + } + return num_components; +} + +static const char * +path_next_part(const char *path) +{ + while (*path && *path != '/') + path++; + while (*path && *path == '/') + path++; + return path; +} + static int extract_regular_file_linked(struct wim_dentry *dentry, - const mbchar *output_path, + const char *output_path, struct apply_args *args, struct wim_lookup_table_entry *lte) { @@ -80,8 +107,8 @@ extract_regular_file_linked(struct wim_dentry *dentry, int num_path_components; int num_output_dir_path_components; size_t extracted_file_len; - mbchar *p; - const mbchar *p2; + char *p; + const char *p2; size_t i; num_path_components = @@ -95,7 +122,7 @@ extract_regular_file_linked(struct wim_dentry *dentry, } extracted_file_len = strlen(lte->extracted_file); - mbchar buf[extracted_file_len + 3 * num_path_components + 1]; + char buf[extracted_file_len + 3 * num_path_components + 1]; p = &buf[0]; for (i = 0; i < num_path_components; i++) { @@ -106,8 +133,10 @@ extract_regular_file_linked(struct wim_dentry *dentry, p2 = lte->extracted_file; while (*p2 == '/') p2++; - while (num_output_dir_path_components--) - p2 = path_next_part(p2, NULL); + while (num_output_dir_path_components > 0) { + p2 = path_next_part(p2); + num_output_dir_path_components--; + } strcpy(p, p2); if (symlink(buf, output_path) != 0) { ERROR_WITH_ERRNO("Failed to symlink `%s' to `%s'", @@ -119,7 +148,7 @@ extract_regular_file_linked(struct wim_dentry *dentry, } static int -symlink_apply_unix_data(const mbchar *link, +symlink_apply_unix_data(const char *link, const struct wimlib_unix_data *unix_data) { if (lchown(link, unix_data->uid, unix_data->gid)) { @@ -160,7 +189,7 @@ fd_apply_unix_data(int fd, const struct wimlib_unix_data *unix_data) } static int -dir_apply_unix_data(const mbchar *dir, const struct wimlib_unix_data *unix_data) +dir_apply_unix_data(const char *dir, const struct wimlib_unix_data *unix_data) { int dfd = open(dir, O_RDONLY); int ret; @@ -180,7 +209,7 @@ dir_apply_unix_data(const mbchar *dir, const struct wimlib_unix_data *unix_data) static int extract_regular_file_unlinked(struct wim_dentry *dentry, struct apply_args *args, - const mbchar *output_path, + const char *output_path, struct wim_lookup_table_entry *lte) { /* Normal mode of extraction. Regular files and hard links are @@ -271,7 +300,7 @@ out: static int extract_regular_file(struct wim_dentry *dentry, struct apply_args *args, - const mbchar *output_path) + const char *output_path) { struct wim_lookup_table_entry *lte; const struct wim_inode *inode = dentry->d_inode; @@ -295,11 +324,11 @@ extract_regular_file(struct wim_dentry *dentry, static int extract_symlink(struct wim_dentry *dentry, struct apply_args *args, - const mbchar *output_path) + const char *output_path) { - mbchar target[4096]; + char target[4096]; ssize_t ret = inode_readlink(dentry->d_inode, target, - sizeof(target), args->w, 0); + sizeof(target), args->w, false); struct wim_lookup_table_entry *lte; if (ret <= 0) { @@ -335,31 +364,31 @@ extract_symlink(struct wim_dentry *dentry, static int extract_directory(struct wim_dentry *dentry, - const mbchar *output_path, bool is_root) + const tchar *output_path, bool is_root) { int ret; struct stat stbuf; - ret = stat(output_path, &stbuf); + ret = tstat(output_path, &stbuf); if (ret == 0) { if (S_ISDIR(stbuf.st_mode)) { /*if (!is_root)*/ /*WARNING("`%s' already exists", output_path);*/ goto dir_exists; } else { - ERROR("`%s' is not a directory", output_path); + ERROR("`%"TS"' is not a directory", output_path); return WIMLIB_ERR_MKDIR; } } else { if (errno != ENOENT) { - ERROR_WITH_ERRNO("Failed to stat `%s'", output_path); + ERROR_WITH_ERRNO("Failed to stat `%"TS"'", output_path); return WIMLIB_ERR_STAT; } } - if (mkdir(output_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) + if (tmkdir(output_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { - ERROR_WITH_ERRNO("Cannot create directory `%s'", output_path); + ERROR_WITH_ERRNO("Cannot create directory `%"TS"'", output_path); return WIMLIB_ERR_MKDIR; } dir_exists: @@ -380,7 +409,7 @@ dir_exists: } #ifndef __WIN32__ -static int unix_do_apply_dentry(const mbchar *output_path, +static int unix_do_apply_dentry(const char *output_path, size_t output_path_len, struct wim_dentry *dentry, struct apply_args *args) @@ -398,7 +427,7 @@ static int unix_do_apply_dentry(const mbchar *output_path, } static int -unix_do_apply_dentry_timestamps(const mbchar *output_path, +unix_do_apply_dentry_timestamps(const char *output_path, size_t output_path_len, const struct wim_dentry *dentry, struct apply_args *args) @@ -463,18 +492,19 @@ static int apply_dentry_normal(struct wim_dentry *dentry, void *arg) { struct apply_args *args = arg; + tchar *output_path; size_t len; - mbchar *output_path; - len = strlen(args->target); + len = tstrlen(args->target); if (dentry_is_root(dentry)) { - output_path = (mbchar*)args->target; + output_path = (tchar*)args->target; } else { - output_path = alloca(len + dentry->full_path_nbytes + 1); - memcpy(output_path, args->target, len); + output_path = alloca(len * sizeof(tchar) + dentry->full_path_nbytes + + sizeof(tchar)); + memcpy(output_path, args->target, len * sizeof(tchar)); memcpy(output_path + len, dentry->full_path, dentry->full_path_nbytes); - output_path[len + dentry->full_path_nbytes] = '\0'; - len += dentry->full_path_nbytes; + len += dentry->full_path_nbytes / sizeof(tchar); + output_path[len] = T('\0'); } #ifdef __WIN32__ return win32_do_apply_dentry(output_path, len, dentry, args); @@ -490,19 +520,21 @@ apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg) { struct apply_args *args = arg; size_t len; - mbchar *output_path; + tchar *output_path; - len = strlen(args->target); + len = tstrlen(args->target); if (dentry_is_root(dentry)) { - output_path = (mbchar*)args->target; + output_path = (tchar*)args->target; } else { - output_path = alloca(len + dentry->full_path_nbytes + 1); - memcpy(output_path, args->target, len); + output_path = alloca(len * sizeof(tchar) + dentry->full_path_nbytes + + sizeof(tchar)); + memcpy(output_path, args->target, len * sizeof(tchar)); memcpy(output_path + len, dentry->full_path, dentry->full_path_nbytes); - output_path[len + dentry->full_path_nbytes] = '\0'; - len += dentry->full_path_nbytes; + len += dentry->full_path_nbytes / sizeof(tchar); + output_path[len] = T('\0'); } + #ifdef __WIN32__ return win32_do_apply_dentry_timestamps(output_path, len, dentry, args); #else @@ -537,54 +569,6 @@ maybe_apply_dentry(struct wim_dentry *dentry, void *arg) return ret; } -static int -cmp_streams_by_wim_position(const void *p1, const void *p2) -{ - const struct wim_lookup_table_entry *lte1, *lte2; - lte1 = *(const struct wim_lookup_table_entry**)p1; - lte2 = *(const struct wim_lookup_table_entry**)p2; - if (lte1->resource_entry.offset < lte2->resource_entry.offset) - return -1; - else if (lte1->resource_entry.offset > lte2->resource_entry.offset) - return 1; - else - return 0; -} - -static int -sort_stream_list_by_wim_position(struct list_head *stream_list) -{ - struct list_head *cur; - size_t num_streams; - struct wim_lookup_table_entry **array; - size_t i; - size_t array_size; - - num_streams = 0; - list_for_each(cur, stream_list) - num_streams++; - array_size = num_streams * sizeof(array[0]); - array = MALLOC(array_size); - if (!array) { - ERROR("Failed to allocate %zu bytes to sort stream entries", - array_size); - return WIMLIB_ERR_NOMEM; - } - cur = stream_list->next; - for (i = 0; i < num_streams; i++) { - array[i] = container_of(cur, struct wim_lookup_table_entry, staging_list); - cur = cur->next; - } - - qsort(array, num_streams, sizeof(array[0]), cmp_streams_by_wim_position); - - INIT_LIST_HEAD(stream_list); - for (i = 0; i < num_streams; i++) - list_add_tail(&array[i]->staging_list, stream_list); - FREE(array); - return 0; -} - static void calculate_bytes_to_extract(struct list_head *stream_list, int extract_flags, @@ -758,7 +742,7 @@ apply_stream_list(struct list_head *stream_list, * @target. */ static int extract_single_image(WIMStruct *w, int image, - const mbchar *target, int extract_flags, + const tchar *target, int extract_flags, wimlib_progress_func_t progress_func) { int ret; @@ -768,11 +752,11 @@ extract_single_image(WIMStruct *w, int image, struct apply_args args; const struct apply_operations *ops; + memset(&args, 0, sizeof(args)); + args.w = w; args.target = target; args.extract_flags = extract_flags; - args.num_utime_warnings = 0; - args.stream_list = &stream_list; args.progress_func = progress_func; if (progress_func) { @@ -788,7 +772,8 @@ extract_single_image(WIMStruct *w, int image, if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) { args.vol = ntfs_mount(target, 0); if (!args.vol) { - ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s'", target); + ERROR_WITH_ERRNO("Failed to mount NTFS volume `%"TS"'", + target); return WIMLIB_ERR_NTFS_3G; } ops = &ntfs_apply_operations; @@ -869,7 +854,8 @@ out: /* Unmount the NTFS volume */ if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) { if (ntfs_umount(args.vol, FALSE) != 0) { - ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", args.target); + ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%"TS"'", + args.target); if (ret == 0) ret = WIMLIB_ERR_NTFS_3G; } @@ -878,39 +864,53 @@ out: return ret; } +static const tchar *filename_forbidden_chars = +T( +#ifdef __WIN32__ +"<>:\"/\\|?*" +#else +"/" +#endif +); + +/* This function checks if it is okay to use a WIM image's name as a directory + * name. */ +static bool +image_name_ok_as_dir(const tchar *image_name) +{ + return image_name && *image_name && + !tstrpbrk(image_name, filename_forbidden_chars); +} /* Extracts all images from the WIM to the directory @target, with the images * placed in subdirectories named by their image names. */ static int -extract_all_images(WIMStruct *w, const mbchar *target, +extract_all_images(WIMStruct *w, + const tchar *target, int extract_flags, wimlib_progress_func_t progress_func) { size_t image_name_max_len = max(xml_get_max_image_name_len(w), 20); - size_t output_path_len = strlen(target); - mbchar buf[output_path_len + 1 + image_name_max_len + 1]; + size_t output_path_len = tstrlen(target); + tchar buf[output_path_len + 1 + image_name_max_len + 1]; int ret; int image; - const utf8char *image_name; + const tchar *image_name; ret = extract_directory(NULL, target, true); - if (ret != 0) + if (ret) return ret; - memcpy(buf, target, output_path_len); - buf[output_path_len] = '/'; + tmemcpy(buf, target, output_path_len); + buf[output_path_len] = T('/'); for (image = 1; image <= w->hdr.image_count; image++) { image_name = wimlib_get_image_name(w, image); - if (image_name && *image_name && - (wimlib_mbs_is_utf8 || !utf8_str_contains_nonascii_chars(image_name)) - && strchr(image_name, '/') == NULL) - { - strcpy(buf + output_path_len + 1, image_name); + if (image_name_ok_as_dir(image_name)) { + tstrcpy(buf + output_path_len + 1, image_name); } else { - /* Image name is empty, or may not be representable in - * the current locale, or contains path separators. Use - * the image number instead. */ - sprintf(buf + output_path_len + 1, "%d", image); + /* Image name is empty, or contains forbidden + * characters. */ + tsprintf(buf + output_path_len + 1, T("%d"), image); } ret = extract_single_image(w, image, buf, extract_flags, progress_func); @@ -922,13 +922,14 @@ extract_all_images(WIMStruct *w, const mbchar *target, /* Extracts a single image or all images from a WIM file to a directory or NTFS * volume. */ -WIMLIBAPI int wimlib_extract_image(WIMStruct *w, - int image, - const char *target, - int extract_flags, - WIMStruct **additional_swms, - unsigned num_additional_swms, - wimlib_progress_func_t progress_func) +WIMLIBAPI int +wimlib_extract_image(WIMStruct *w, + int image, + const tchar *target, + int extract_flags, + WIMStruct **additional_swms, + unsigned num_additional_swms, + wimlib_progress_func_t progress_func) { struct wim_lookup_table *joined_tab, *w_tab_save; int ret; @@ -989,9 +990,6 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, w->lookup_table = joined_tab; } -#ifdef __WIN32__ - win32_acquire_restore_privileges(); -#endif if (image == WIMLIB_ALL_IMAGES) { extract_flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE; ret = extract_all_images(w, target, extract_flags, @@ -1001,9 +999,6 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, ret = extract_single_image(w, image, target, extract_flags, progress_func); } -#ifdef __WIN32__ - win32_release_restore_privileges(); -#endif if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))