unzip: add option to insist on a zip archive
The fact that a non-zip archive has always been silently ignored seems bad, but adding an error might break code that (probably accidentally) relies on the behavior. This change makes sane behavior at least available by adding a `#:must-unzip?` option. Relevant to #3613
This commit is contained in:
parent
71b7f21fdb
commit
a5b61f7ac8
|
@ -13,11 +13,15 @@ a function to extract items from a @exec{zip} archive.}
|
|||
. -> . any)
|
||||
(bytes? boolean? input-port? . -> . any))
|
||||
(make-filesystem-entry-reader)]
|
||||
[#:must-unzip? must-unzip? any/c #f]
|
||||
[#:preserve-timestamps? preserve-timestamps? any/c #f]
|
||||
[#:utc-timestamps? utc-timestamps? any/c #f])
|
||||
void?]{
|
||||
|
||||
Unzips an entire @exec{zip} archive from @racket[in].
|
||||
Unzips an entire @exec{zip} archive from @racket[in]. If @racket[in]
|
||||
does not start with @exec{zip}-archive magic bytes, an error is
|
||||
reported only if @racket[must-unzip?] is true, otherwise the result is
|
||||
@racket[(void)] with no bytes consumed from @racket[in].
|
||||
|
||||
For each entry in the archive, the @racket[entry-reader] procedure is
|
||||
called with three or four arguments: the byte string representing the entry
|
||||
|
@ -33,18 +37,24 @@ but if @racket[utc-timestamps?] is true, then the time in the archive
|
|||
is interpreted as UTC.
|
||||
|
||||
@history[#:changed "6.0.0.3" @elem{Added the @racket[#:preserve-timestamps?] argument.}
|
||||
#:changed "6.0.1.12" @elem{Added the @racket[#:utc-timestamps?] argument.}]}
|
||||
#:changed "6.0.1.12" @elem{Added the @racket[#:utc-timestamps?] argument.}
|
||||
#:changed "8.0.0.10" @elem{Added the @racket[#:must-unzip?] argument.}]}
|
||||
|
||||
|
||||
@defproc[(call-with-unzip [in (or/c path-string? input-port?)]
|
||||
[proc (-> path-string? any)])
|
||||
[proc (-> path-string? any)]
|
||||
[#:must-unzip? must-unzip? any/c #f])
|
||||
any]{
|
||||
|
||||
Unpacks @racket[in] to a temporary directory, calls @racket[proc] on
|
||||
the temporary directory's path, and then deletes the temporary
|
||||
directory while returning the result of @racket[proc].
|
||||
|
||||
@history[#:added "6.0.1.6"]}
|
||||
Like @racket[unzip], no error is reported in the case @racket[in] is
|
||||
not a @exec{zip} archive, unless @racket[must-unzip?] is true.
|
||||
|
||||
@history[#:added "6.0.1.6"
|
||||
#:changed "8.0.0.10" @elem{Added the @racket[#:must-unzip?] argument.}]}
|
||||
|
||||
|
||||
@defproc[(make-filesystem-entry-reader
|
||||
|
|
|
@ -62,7 +62,14 @@
|
|||
(break-thread t)
|
||||
(sync t)
|
||||
'done))
|
||||
=> 'done))
|
||||
=> 'done)
|
||||
|
||||
(test (call-with-unzip (open-input-bytes #"not a zip stream") void)
|
||||
=> (void))
|
||||
(test (call-with-unzip (open-input-bytes #"not a zip stream")
|
||||
void
|
||||
#:must-unzip? #t)
|
||||
=error> "input does not appear to be an archive"))
|
||||
|
||||
|
||||
(provide tests)
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
(or/c (bytes? boolean? input-port? (or/c #f exact-integer?) . -> . any)
|
||||
(bytes? boolean? input-port? . -> . any))
|
||||
#:preserve-timestamps? any/c
|
||||
#:utc-timestamps? any/c)
|
||||
#:utc-timestamps? any/c
|
||||
#:must-unzip? any/c)
|
||||
. ->* . any)]
|
||||
|
||||
[make-filesystem-entry-reader (() (#:dest
|
||||
|
@ -48,9 +49,10 @@
|
|||
. ->* .
|
||||
any)]
|
||||
|
||||
[call-with-unzip (-> (or/c path-string? input-port?)
|
||||
(-> path-string? any)
|
||||
any)]
|
||||
[call-with-unzip (((or/c path-string? input-port?)
|
||||
(-> path-string? any))
|
||||
(#:must-unzip? any/c)
|
||||
. ->* . any)]
|
||||
[call-with-unzip-entry (-> (or/c path-string? input-port?)
|
||||
path-string?
|
||||
(-> path-string? any)
|
||||
|
@ -309,17 +311,22 @@
|
|||
|
||||
;; unzip : [(or/c path-string? input-port) (bytes boolean input-port -> any)] -> any
|
||||
(define unzip
|
||||
(lambda (in [read-entry (make-filesystem-entry-reader)]
|
||||
#:preserve-timestamps? [preserve-timestamps? #f]
|
||||
#:utc-timestamps? [utc? #f])
|
||||
(lambda (orig-in [read-entry (make-filesystem-entry-reader)]
|
||||
#:must-unzip? [must-unzip? #f]
|
||||
#:preserve-timestamps? [preserve-timestamps? #f]
|
||||
#:utc-timestamps? [utc? #f])
|
||||
(call-with-input
|
||||
in
|
||||
orig-in
|
||||
(lambda (in)
|
||||
(when (= (peek-integer 4 #f in #f) *local-file-header*)
|
||||
(unzip-one-entry in read-entry preserve-timestamps? utc?)
|
||||
(unzip in read-entry
|
||||
#:preserve-timestamps? preserve-timestamps?
|
||||
#:utc-timestamps? utc?))))))
|
||||
(cond
|
||||
[(= (peek-integer 4 #f in #f) *local-file-header*)
|
||||
(unzip-one-entry in read-entry preserve-timestamps? utc?)
|
||||
(unzip in read-entry
|
||||
#:preserve-timestamps? preserve-timestamps?
|
||||
#:utc-timestamps? utc?)]
|
||||
[must-unzip?
|
||||
(error 'unzip "input does not appear to be an archive\n input: ~e" orig-in)]
|
||||
[else (void)])))))
|
||||
|
||||
(define (input-size in)
|
||||
(file-position in eof)
|
||||
|
@ -403,13 +410,17 @@
|
|||
(lambda ()
|
||||
(delete-directory/files temp-dir)))))
|
||||
|
||||
(define (call-with-unzip zip-file user-proc)
|
||||
(define (call-with-unzip zip-file user-proc
|
||||
#:must-unzip? [must-unzip? #f])
|
||||
(let ([temp-dir #f])
|
||||
(dynamic-wind
|
||||
(lambda ()
|
||||
(set! temp-dir (make-temporary-file "ziptmp~a" 'directory)))
|
||||
(lambda ()
|
||||
(unzip zip-file (make-filesystem-entry-reader #:dest temp-dir #:exists 'replace))
|
||||
(unzip zip-file (make-filesystem-entry-reader
|
||||
#:dest temp-dir
|
||||
#:exists 'replace)
|
||||
#:must-unzip? must-unzip?)
|
||||
(user-proc temp-dir))
|
||||
(lambda ()
|
||||
(delete-directory/files temp-dir)))))
|
||||
|
|
Loading…
Reference in New Issue
Block a user