Skip to content

Commit

Permalink
Added ability to declare empty directory (#86)
Browse files Browse the repository at this point in the history
* Added an ability to declare empty directories

* Added test cases to cover packaging of empty directories
  • Loading branch information
devgs committed Nov 18, 2021
1 parent bff10ba commit 51cf45d
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 61 deletions.
5 changes: 5 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,18 @@ and is what will be extracted from the ZIP file. Example:

1034ab38 428 /foo.txt My Document1.txt
83e8110b 100339 /bar.txt My Other Document1.txt
0 0 @directory My empty directory

Files are retrieved and encoded in order. If a file cannot be found or the file
request returns any sort of error, the download is aborted.

The CRC-32 is optional. Put "-" if you don't know the CRC-32; note that in this
case mod_zip will disable support for the `Range` header.

A special URL marker `@directory` can be used to declare a directory entry
within an archive. This is very convenient when you have to package a tree of
files, including some empty directories. As they have to be declared explicitly.


Re-encoding filenames
---
Expand Down
7 changes: 6 additions & 1 deletion ngx_http_zip_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ ngx_http_zip_generate_pieces(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx)
header_piece->range.end = offset;

file_piece = &ctx->pieces[piece_i++];
file_piece->type = zip_file_piece;
file_piece->type = file->is_directory ? zip_dir_piece : zip_file_piece;
file_piece->file = file;
file_piece->range.start = offset;
file_piece->range.end = offset += file->size; //!note: (sizeless chunks): we need file size here / or mark it and modify ranges after
Expand Down Expand Up @@ -683,6 +683,11 @@ ngx_http_zip_write_central_directory_entry(u_char *p, ngx_http_zip_file_t *file,
central_directory_file_header.version_made_by = htole16(central_directory_file_header.version_made_by);
central_directory_file_header.version_needed = htole16(central_directory_file_header.version_needed);
central_directory_file_header.flags = htole16(central_directory_file_header.flags);

if (file->is_directory) {
central_directory_file_header.attr_external = zip_directory_attr_external;
}

central_directory_file_header.attr_external = htole32(central_directory_file_header.attr_external);
central_directory_file_header.mtime = htole32(file->dos_time);
central_directory_file_header.crc32 = htole32(file->crc32);
Expand Down
3 changes: 3 additions & 0 deletions ngx_http_zip_file_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#define zip_version_zip64 45
#define zip_utf8_flag 0x0800
#define zip_missing_crc32_flag 0x08
#define zip_directory_attr_external 0x41ED0010
// Unix dir bit -^ ^- DOS dir bit
// Unix permission bits (0755) -^^^

typedef struct {
uint16_t tag; //0x5455
Expand Down
11 changes: 11 additions & 0 deletions ngx_http_zip_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ static ngx_int_t ngx_http_zip_send_header_piece(ngx_http_request_t *r,
ngx_http_zip_ctx_t *ctx, ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *req_range);
static ngx_int_t ngx_http_zip_send_file_piece(ngx_http_request_t *r,
ngx_http_zip_ctx_t *ctx, ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *req_range);
static ngx_int_t ngx_http_zip_send_directory_piece(ngx_http_request_t *r,
ngx_http_zip_ctx_t *ctx, ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *req_range);
static ngx_int_t ngx_http_zip_send_trailer_piece(ngx_http_request_t *r,
ngx_http_zip_ctx_t *ctx, ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *req_range);
static ngx_int_t ngx_http_zip_send_central_directory_piece(ngx_http_request_t *r,
Expand Down Expand Up @@ -576,6 +578,13 @@ ngx_http_zip_send_file_piece(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx,
return NGX_AGAIN; // must be NGX_AGAIN
}

static ngx_int_t ngx_http_zip_send_directory_piece(ngx_http_request_t *r,
ngx_http_zip_ctx_t *ctx, ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *req_range)
{
// Directory has no data.
return NGX_OK;
}

static ngx_int_t
ngx_http_zip_send_trailer_piece(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx,
ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *req_range)
Expand Down Expand Up @@ -621,6 +630,8 @@ ngx_http_zip_send_piece(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx,
rc = ngx_http_zip_send_header_piece(r, ctx, piece, req_range);
} else if (piece->type == zip_file_piece) {
rc = ngx_http_zip_send_file_piece(r, ctx, piece, req_range);
} else if (piece->type == zip_dir_piece) {
rc = ngx_http_zip_send_directory_piece(r, ctx, piece, req_range);
} else if (piece->type == zip_trailer_piece) {
rc = ngx_http_zip_send_trailer_piece(r, ctx, piece, req_range);
} else if (piece->type == zip_central_directory_piece) {
Expand Down
2 changes: 2 additions & 0 deletions ngx_http_zip_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ typedef struct {
unsigned missing_crc32:1;
unsigned need_zip64:1;
unsigned need_zip64_offset:1;
unsigned is_directory:1;
} ngx_http_zip_file_t;

typedef struct {
Expand All @@ -41,6 +42,7 @@ typedef struct {
typedef enum {
zip_header_piece, //local file header
zip_file_piece, // file data
zip_dir_piece, // directory data
zip_trailer_piece, // data descriptor (for files without CRC, exists if bit 3 of GP flag is set),
zip_trailer_piece64, // the same but for zip64 (if zip64 extended information extra field is in file header)
zip_central_directory_piece,
Expand Down
Loading

0 comments on commit 51cf45d

Please sign in to comment.