Document which supported feature requires which operations. Document when stat fields need to be valid.
diff --git a/lib/zip_source_file.h b/lib/zip_source_file.h
index 07e6cfe..479686d 100644
--- a/lib/zip_source_file.h
+++ b/lib/zip_source_file.h
@@ -33,9 +33,9 @@
struct zip_source_file_stat {
zip_uint64_t size; /* must be valid for regular files */
- time_t mtime;
- bool exists;
- bool regular_file;
+ time_t mtime; /* must always be valid, is initialized to current time */
+ bool exists; /* must always be vaild */
+ bool regular_file; /* must always be valid */
};
typedef struct zip_source_file_context zip_source_file_context_t;
@@ -63,6 +63,13 @@
zip_source_file_operations_t *ops;
};
+
+/* The following methods must be implemented to support each feature:
+ - close, read, seek, and stat must always be implemented.
+ - To support specifying the file by name, open, and strupd must be implemented.
+ - For write support, the file must be specified by name and close, commit_write, create_temp_output, remove, rollback_write, and tell must be implemented.
+ - create_temp_output_cloning is always optional. */
+
struct zip_source_file_operations {
void (*close)(zip_source_file_context_t *ctx);
zip_int64_t (*commit_write)(zip_source_file_context_t *ctx);
diff --git a/lib/zip_source_file_common.c b/lib/zip_source_file_common.c
index c3a8fd4..8d0c599 100644
--- a/lib/zip_source_file_common.c
+++ b/lib/zip_source_file_common.c
@@ -60,10 +60,26 @@
zip_error_set(error, ZIP_ER_INVAL, 0);
return NULL;
}
-
- if (file == NULL && fname == NULL) {
- zip_error_set(error, ZIP_ER_INVAL, 0);
- return NULL;
+
+ if (ops->close == NULL || ops->read == NULL || ops->seek == NULL || ops->stat == NULL) {
+ zip_error_set(error, ZIP_ER_INTERNAL, 0);
+ return NULL;
+ }
+
+ if (ops->write != NULL && (ops->commit_write == NULL || ops->create_temp_output == NULL || ops->remove == NULL || ops->rollback_write == NULL || ops->tell == NULL)) {
+ zip_error_set(error, ZIP_ER_INTERNAL, 0);
+ return NULL;
+ }
+
+ if (fname != NULL) {
+ if (ops->close == NULL || ops->open == NULL || ops->strdup == NULL) {
+ zip_error_set(error, ZIP_ER_INTERNAL, 0);
+ return NULL;
+ }
+ }
+ else if (file == NULL) {
+ zip_error_set(error, ZIP_ER_INVAL, 0);
+ return NULL;
}
if (len < 0) {
@@ -119,20 +135,18 @@
zip_source_file_stat_init(&sb);
stat_valid = ops->stat(ctx, &sb);
- if (ctx->fname && !stat_valid) {
- if (ctx->start == 0 && ctx->len == 0) {
- ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
- }
+ if (ctx->fname && !stat_valid && ctx->start == 0 && ctx->len == 0 && ops->write != NULL) {
+ ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
}
if (!stat_valid) {
- zip_error_set(&ctx->stat_error, ZIP_ER_READ, errno);
+ zip_error_set(&ctx->stat_error, ZIP_ER_READ, errno);
}
else {
- if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) {
- ctx->st.mtime = sb.mtime;
+ if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) {
+ ctx->st.mtime = sb.mtime;
ctx->st.valid |= ZIP_STAT_MTIME;
- }
+ }
if (sb.regular_file) {
ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
@@ -248,7 +262,7 @@
}
}
- if (ctx->start > 0) {
+ if (ctx->start > 0) { // TODO: rewind on re-open
if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)ctx->start, SEEK_SET) == false) {
/* TODO: skip by reading */
return -1;