Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ meson setup build
meson compile -C build
```

### Build options

libzip is only needed for zip container support - flashing directly from
zip archives and the `create-zip` subcommand. To build a leaner QDL
without it, disable the `zip-container` feature:

```bash
meson setup build -Dzip-container=disabled
```

## Use QDL

### EDL mode
Expand Down
16 changes: 13 additions & 3 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ endif
# Dependencies
libusb_dep = dependency('libusb-1.0')
libxml_dep = dependency('libxml-2.0')
libzip_dep = dependency('libzip')
libzip_dep = dependency('libzip', required: get_option('zip-container'))
help2man = find_program('help2man', required: false)
cmocka_dep = dependency('cmocka', required: get_option('tests'))

Expand All @@ -43,14 +43,24 @@ if host_machine.system() == 'windows'
]
endif

common_dep = [libusb_dep, libxml_dep, libzip_dep, ws2_dep, setupapi_dep]
common_dep = [libusb_dep, libxml_dep, ws2_dep, setupapi_dep]
compile_view_deps = [libusb_dep, libxml_dep]

# Zip container support is optional; sources gate zip-specific code on
# HAVE_ZIP_CONTAINER and src/meson.build drops the libzip-backed sources
# when it is disabled.
if libzip_dep.found()
add_project_arguments('-DHAVE_ZIP_CONTAINER', language: 'c')
common_dep += libzip_dep
compile_view_deps += libzip_dep
endif

# Compile-only view of common_dep (includes + cflags, no link args).
# Used on executables so their own sources see the headers, while link
# args propagate exactly once through the static library below, avoiding
# duplicate "-l..." entries on the link line.
common_compile_dep = []
foreach d : [libusb_dep, libxml_dep, libzip_dep]
foreach d : compile_view_deps
common_compile_dep += d.partial_dependency(compile_args: true, includes: true)
endforeach

Expand Down
1 change: 1 addition & 0 deletions meson.options
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
option('VERSION', type: 'string', value: '', description: 'Project version')
option('tests', type: 'feature', value: 'auto', description: 'Build unit tests (requires cmocka)')
option('nbdkit', type: 'feature', value: 'auto', description: 'Build the nbdkit plugin (requires nbdkit)')
option('zip-container', type: 'feature', value: 'auto', description: 'Flash from and create zip archives (requires libzip)')
113 changes: 31 additions & 82 deletions src/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,71 +5,38 @@
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <zip.h>

#include "oscompat.h"
#include "qdl.h"
#include "file.h"

struct qdl_zip {
zip_t *zip;
unsigned int refcount;
};

int qdl_file_open(struct qdl_zip *qdl_zip, const char *filename, struct qdl_file *file)
{
struct zip_stat st;
zip_int64_t idx;
zip_file_t *zf;
off_t len;
zip_t *zip;
int fd;

if (qdl_zip) {
zip = qdl_zip->zip;

idx = zip_name_locate(zip, filename, 0);
if (idx < 0) {
ux_err("unable to locate \"%s\" in zip archive\n", filename);
return -1;
}

if (zip_stat_index(zip, idx, 0, &st) < 0) {
ux_err("unable to stat \"%s\" in zip archive\n", filename);
return -1;
}

zf = zip_fopen_index(zip, idx, 0);
if (!zf) {
ux_err("unable to open \"%s\" in zip archive\n", filename);
return -1;
}
if (qdl_zip)
return qdl_zip_file_open(qdl_zip, filename, file);

file->type = QDL_FILE_TYPE_ZIP;
file->fd = -1;
file->size = st.size;
file->zip_file = zf;
} else {
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) {
ux_err("failed to open \"%s\" for reading\n", filename);
return -1;
}
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) {
ux_err("failed to open \"%s\" for reading\n", filename);
return -1;
}

len = lseek(fd, 0, SEEK_END);
if (len < 0) {
ux_err("failed to find end of \"%s\"\n", filename);
close(fd);
return -1;
}
len = lseek(fd, 0, SEEK_END);
if (len < 0) {
ux_err("failed to find end of \"%s\"\n", filename);
close(fd);
return -1;
}

lseek(fd, 0, SEEK_SET);
lseek(fd, 0, SEEK_SET);

file->type = QDL_FILE_TYPE_POSIX;
file->fd = fd;
file->size = len;
file->zip_file = NULL;
}
file->type = QDL_FILE_TYPE_POSIX;
file->fd = fd;
file->size = len;
file->zip_file = NULL;

return 0;
}
Expand Down Expand Up @@ -97,7 +64,7 @@ void *qdl_file_load(struct qdl_file *file, size_t *len)
}
break;
case QDL_FILE_TYPE_ZIP:
n = zip_fread(file->zip_file, buf, file->size);
n = qdl_zip_file_read(file, buf, file->size);
if ((size_t)n != file->size) {
ux_err("failed to load zip file member\n");
goto err_free_buf;
Expand All @@ -124,8 +91,7 @@ void qdl_file_close(struct qdl_file *file)
file->fd = -1;
break;
case QDL_FILE_TYPE_ZIP:
zip_fclose(file->zip_file);
file->zip_file = NULL;
qdl_zip_file_close(file);
break;
};

Expand All @@ -145,7 +111,7 @@ ssize_t qdl_file_read(struct qdl_file *file, void *buf, size_t len)
case QDL_FILE_TYPE_POSIX:
return read(file->fd, buf, len);
case QDL_FILE_TYPE_ZIP:
return zip_fread(file->zip_file, buf, len);
return qdl_zip_file_read(file, buf, len);
};

return -1;
Expand Down Expand Up @@ -197,45 +163,28 @@ off_t qdl_file_seek(struct qdl_file *file, off_t offset, int whence)
return -1;
}

#ifndef HAVE_ZIP_CONTAINER
/*
* Built without zip-container support: qdl_zip_open() reports "not a
* zip archive" for every input, so the plain contents.xml and
* flashmap.json flows work unchanged and no zip handle ever exists.
*/
int qdl_zip_open(const char *filename, struct qdl_zip **__qdl_zip)
{
struct qdl_zip *qdl_zip;
zip_t *zip;

zip = zip_open(filename, ZIP_RDONLY, NULL);
if (!zip) {
*__qdl_zip = NULL;
return 0;
}
(void)filename;

qdl_zip = calloc(1, sizeof(*qdl_zip));
if (!qdl_zip) {
zip_close(zip);
return -1;
}

qdl_zip->zip = zip;
qdl_zip->refcount = 1;

*__qdl_zip = qdl_zip;
*__qdl_zip = NULL;

return 0;
}

struct qdl_zip *qdl_zip_get(struct qdl_zip *qdl_zip)
{
if (qdl_zip)
qdl_zip->refcount++;

return qdl_zip;
}

void qdl_zip_put(struct qdl_zip *qdl_zip)
{
if (qdl_zip) {
if (--qdl_zip->refcount == 0) {
zip_close(qdl_zip->zip);
free(qdl_zip);
}
}
(void)qdl_zip;
}
#endif
47 changes: 47 additions & 0 deletions src/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef __QDL_FILE_H__
#define __QDL_FILE_H__

#include <stdbool.h>
#include <sys/types.h>

struct zip_file;
Expand Down Expand Up @@ -37,4 +38,50 @@ off_t qdl_file_seek(struct qdl_file *file, off_t offset, int whence);
int qdl_zip_open(const char *filename, struct qdl_zip **__qdl_zip);
struct qdl_zip *qdl_zip_get(struct qdl_zip *qzip);
void qdl_zip_put(struct qdl_zip *qzip);

/*
* Internal libzip-backed helpers, implemented in file_zip.c. Builds
* without zip-container support get inert stubs; they are unreachable
* there, as qdl_zip_open() then never produces a zip handle and no
* qdl_file ever becomes QDL_FILE_TYPE_ZIP.
*/
#ifdef HAVE_ZIP_CONTAINER
static inline bool qdl_zip_supported(void)
{
return true;
}

int qdl_zip_file_open(struct qdl_zip *qzip, const char *filename, struct qdl_file *file);
ssize_t qdl_zip_file_read(struct qdl_file *file, void *buf, size_t len);
void qdl_zip_file_close(struct qdl_file *file);
#else
static inline bool qdl_zip_supported(void)
{
return false;
}

static inline int qdl_zip_file_open(struct qdl_zip *qzip, const char *filename,
struct qdl_file *file)
{
(void)qzip;
(void)filename;
(void)file;

return -1;
}

static inline ssize_t qdl_zip_file_read(struct qdl_file *file, void *buf, size_t len)
{
(void)file;
(void)buf;
(void)len;

return -1;
}

static inline void qdl_zip_file_close(struct qdl_file *file)
{
(void)file;
}
#endif
#endif
102 changes: 102 additions & 0 deletions src/file_zip.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <stdlib.h>
#include <zip.h>

#include "qdl.h"
#include "file.h"

struct qdl_zip {
zip_t *zip;
unsigned int refcount;
};

int qdl_zip_file_open(struct qdl_zip *qdl_zip, const char *filename,
struct qdl_file *file)
{
struct zip_stat st;
zip_int64_t idx;
zip_file_t *zf;
zip_t *zip = qdl_zip->zip;

idx = zip_name_locate(zip, filename, 0);
if (idx < 0) {
ux_err("unable to locate \"%s\" in zip archive\n", filename);
return -1;
}

if (zip_stat_index(zip, idx, 0, &st) < 0) {
ux_err("unable to stat \"%s\" in zip archive\n", filename);
return -1;
}

zf = zip_fopen_index(zip, idx, 0);
if (!zf) {
ux_err("unable to open \"%s\" in zip archive\n", filename);
return -1;
}

file->type = QDL_FILE_TYPE_ZIP;
file->fd = -1;
file->size = st.size;
file->zip_file = zf;

return 0;
}

ssize_t qdl_zip_file_read(struct qdl_file *file, void *buf, size_t len)
{
return zip_fread(file->zip_file, buf, len);
}

void qdl_zip_file_close(struct qdl_file *file)
{
zip_fclose(file->zip_file);
file->zip_file = NULL;
}

int qdl_zip_open(const char *filename, struct qdl_zip **__qdl_zip)
{
struct qdl_zip *qdl_zip;
zip_t *zip;

zip = zip_open(filename, ZIP_RDONLY, NULL);
if (!zip) {
*__qdl_zip = NULL;
return 0;
}

qdl_zip = calloc(1, sizeof(*qdl_zip));
if (!qdl_zip) {
zip_close(zip);
return -1;
}

qdl_zip->zip = zip;
qdl_zip->refcount = 1;

*__qdl_zip = qdl_zip;

return 0;
}

struct qdl_zip *qdl_zip_get(struct qdl_zip *qdl_zip)
{
if (qdl_zip)
qdl_zip->refcount++;

return qdl_zip;
}

void qdl_zip_put(struct qdl_zip *qdl_zip)
{
if (!qdl_zip)
return;

if (--qdl_zip->refcount == 0) {
zip_close(qdl_zip->zip);
free(qdl_zip);
}
}
Loading
Loading