From 3497201ce66f35401bd02109c06c110671493ad8 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Mon, 18 Nov 2019 15:09:31 +0100 Subject: Make rdsquashfs unpack work on Windows AFAIK the only thing we can actually unpack on Windows is regular files and directories, so only do that. Furthermore, we have no way of setting Unix file attributes, so skip that. Signed-off-by: David Oberhollenzer --- unpack/rdsquashfs.h | 4 ++ unpack/restore_fstree.c | 134 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 98 insertions(+), 40 deletions(-) diff --git a/unpack/rdsquashfs.h b/unpack/rdsquashfs.h index a36d283..9e21050 100644 --- a/unpack/rdsquashfs.h +++ b/unpack/rdsquashfs.h @@ -12,6 +12,10 @@ #include "fstree.h" #include "util/util.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif #ifdef HAVE_SYS_XATTR_H #include #endif diff --git a/unpack/restore_fstree.c b/unpack/restore_fstree.c index dac1a8c..dbcebfa 100644 --- a/unpack/restore_fstree.c +++ b/unpack/restore_fstree.c @@ -6,45 +6,64 @@ */ #include "rdsquashfs.h" -static int create_node(const sqfs_tree_node_t *n, int flags) +#ifdef _WIN32 +static int create_node(const sqfs_tree_node_t *n, const char *name) { - const sqfs_tree_node_t *c; - int fd, ret; - char *name; + WCHAR *wpath = NULL; + DWORD length; + HANDLE fh; - if (!is_filename_sane((const char *)n->name)) { - fprintf(stderr, "Found an entry named '%s', skipping.\n", - n->name); - return 0; - } + length = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) + 1; + if (length <= 0) + goto fail; - name = sqfs_tree_node_get_path(n); - if (name == NULL) { - fprintf(stderr, "Constructing full path for '%s': %s\n", - (const char *)n->name, strerror(errno)); + wpath = alloc_array(sizeof(wpath[0]), length); + if (wpath == NULL) { + perror(name); return -1; } - ret = canonicalize_name(name); - assert(ret == 0); + MultiByteToWideChar(CP_UTF8, 0, name, -1, wpath, length); + wpath[length - 1] = '\0'; - if (!(flags & UNPACK_QUIET)) - printf("creating %s\n", name); + switch (n->inode->base.mode & S_IFMT) { + case S_IFDIR: + if (!CreateDirectoryW(wpath, NULL)) + goto fail; + break; + case S_IFREG: + fh = CreateFileW(wpath, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_NEW, 0, NULL); + + if (fh == INVALID_HANDLE_VALUE) + goto fail; + + CloseHandle(fh); + break; + default: + break; + } + + free(wpath); + return 0; +fail: + fprintf(stderr, "Creating %s: %ld\n", name, GetLastError()); + free(wpath); + return -1; +} +#else +static int create_node(const sqfs_tree_node_t *n, const char *name) +{ + sqfs_u32 devno; + int fd; switch (n->inode->base.mode & S_IFMT) { case S_IFDIR: if (mkdir(name, 0755) && errno != EEXIST) { fprintf(stderr, "mkdir %s: %s\n", name, strerror(errno)); - goto fail; - } - - free(name); - name = NULL; - - for (c = n->children; c != NULL; c = c->next) { - if (create_node(c, flags)) - goto fail; + return -1; } break; case S_IFLNK: @@ -52,7 +71,7 @@ static int create_node(const sqfs_tree_node_t *n, int flags) fprintf(stderr, "ln -s %s %s: %s\n", n->inode->slink_target, name, strerror(errno)); - goto fail; + return -1; } break; case S_IFSOCK: @@ -60,13 +79,11 @@ static int create_node(const sqfs_tree_node_t *n, int flags) if (mknod(name, (n->inode->base.mode & S_IFMT) | 0700, 0)) { fprintf(stderr, "creating %s: %s\n", name, strerror(errno)); - goto fail; + return -1; } break; case S_IFBLK: - case S_IFCHR: { - sqfs_u32 devno; - + case S_IFCHR: if (n->inode->base.type == SQFS_INODE_EXT_BDEV || n->inode->base.type == SQFS_INODE_EXT_CDEV) { devno = n->inode->data.dev_ext.devno; @@ -77,16 +94,16 @@ static int create_node(const sqfs_tree_node_t *n, int flags) if (mknod(name, n->inode->base.mode & S_IFMT, devno)) { fprintf(stderr, "creating device %s: %s\n", name, strerror(errno)); - goto fail; + return -1; } break; - } case S_IFREG: fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) { fprintf(stderr, "creating %s: %s\n", name, strerror(errno)); - goto fail; + return -1; } close(fd); @@ -95,11 +112,47 @@ static int create_node(const sqfs_tree_node_t *n, int flags) break; } - free(name); return 0; -fail: +} +#endif + +static int create_node_dfs(const sqfs_tree_node_t *n, int flags) +{ + const sqfs_tree_node_t *c; + char *name; + int ret; + + if (!is_filename_sane((const char *)n->name)) { + fprintf(stderr, "Found an entry named '%s', skipping.\n", + n->name); + return 0; + } + + name = sqfs_tree_node_get_path(n); + if (name == NULL) { + fprintf(stderr, "Constructing full path for '%s': %s\n", + (const char *)n->name, strerror(errno)); + return -1; + } + + ret = canonicalize_name(name); + assert(ret == 0); + + if (!(flags & UNPACK_QUIET)) + printf("creating %s\n", name); + + ret = create_node(n, name); free(name); - return -1; + if (ret) + return -1; + + if (S_ISDIR(n->inode->base.mode)) { + for (c = n->children; c != NULL; c = c->next) { + if (create_node_dfs(c, flags)) + return -1; + } + } + return 0; } #ifdef HAVE_SYS_XATTR_H @@ -191,6 +244,7 @@ static int set_attribs(sqfs_xattr_reader_t *xattr, } #endif +#ifndef _WIN32 if (flags & UNPACK_SET_TIMES) { struct timespec times[2]; @@ -222,7 +276,7 @@ static int set_attribs(sqfs_xattr_reader_t *xattr, goto fail; } } - +#endif free(path); return 0; fail: @@ -240,11 +294,11 @@ int restore_fstree(sqfs_tree_node_t *root, int flags) if (S_ISDIR(root->inode->base.mode)) { for (n = root->children; n != NULL; n = n->next) { - if (create_node(n, flags)) + if (create_node_dfs(n, flags)) return -1; } } else { - if (create_node(root, flags)) + if (create_node_dfs(root, flags)) return -1; } -- cgit v1.2.3