Skip to content

Commit 94f4081

Browse files
Add error handling for gzipped file decompression and external command failures in fread() (#7097)
* improve error handling in fread() for cmd exe and decompression * trailing ws * added tests * Update test no. * more crptd file in 2nd test * improved error mssg in 2nd test * enhance test 2 * explained meaning of these numbers * wrng instead of error in test 2 * also catch warning; clean-up * windows-only warning --------- Co-authored-by: Michael Chirico <[email protected]>
1 parent 172c0a7 commit 94f4081

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

R/fread.R

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,13 @@ yaml=FALSE, tmpdir=tempdir(), tz="UTC")
7070
}
7171
}
7272
if (!is.null(cmd)) {
73-
(if (.Platform$OS.type == "unix") system else shell)(paste0('(', cmd, ') > ', tmpFile<-tempfile(tmpdir=tmpdir)))
74-
file = tmpFile
73+
tmpFile = tempfile(tmpdir=tmpdir)
7574
on.exit(unlink(tmpFile), add=TRUE)
75+
status = (if (.Platform$OS.type == "unix") system else shell)(paste0('(', cmd, ') > ', tmpFile))
76+
if (status != 0) {
77+
stopf("External command failed with exit code %d. This can happen when the disk is full in the temporary directory ('%s'). See ?fread for the tmpdir argument.", status, tmpdir)
78+
}
79+
file = tmpFile
7680
}
7781
if (!is.null(file)) {
7882
if (!is.character(file) || length(file)!=1L)
@@ -116,9 +120,14 @@ yaml=FALSE, tmpdir=tempdir(), tz="UTC")
116120
if (!requireNamespace("R.utils", quietly = TRUE))
117121
stopf("To read %s files directly, fread() requires 'R.utils' package which cannot be found. Please install 'R.utils' using 'install.packages('R.utils')'.", if (w<=2L || gzsig) "gz" else "bz2") # nocov
118122
FUN = if (w<=2L || gzsig) gzfile else bzfile
119-
R.utils::decompressFile(file, decompFile<-tempfile(tmpdir=tmpdir), ext=NULL, FUN=FUN, remove=FALSE) # ext is not used by decompressFile when destname is supplied, but isn't optional
120-
file = decompFile # don't use 'tmpFile' symbol again, as tmpFile might be the http://domain.org/file.csv.gz download
123+
decompFile = tempfile(tmpdir=tmpdir)
121124
on.exit(unlink(decompFile), add=TRUE)
125+
tryCatch({
126+
R.utils::decompressFile(file, decompFile, ext=NULL, FUN=FUN, remove=FALSE) # ext is not used by decompressFile when destname is supplied, but isn't optional
127+
}, error = function(e) {
128+
stopf("R.utils::decompressFile failed to decompress file '%s':\n %s\n. This can happen when the disk is full in the temporary directory ('%s'). See ?fread for the tmpdir argument.", file, conditionMessage(e), tmpdir)
129+
})
130+
file = decompFile # don't use 'tmpFile' symbol again, as tmpFile might be the http://domain.org/file.csv.gz download
122131
}
123132
file = enc2native(file) # CfreadR cannot handle UTF-8 if that is not the native encoding, see #3078.
124133

inst/tests/tests.Rraw

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21215,3 +21215,16 @@ test(2319.1, !is.null(attr(dt_get, ".internal.selfref")))
2121521215
dt_get0 = data.frame(a = 1:3, b = letters[1:3])
2121621216
setDT(get0("dt_get0"))
2121721217
test(2319.2, !is.null(attr(dt_get0, ".internal.selfref")))
21218+
21219+
# Improved fread error handling for cmd exe and decompression #5415
21220+
test(2320.1, fread(cmd="false"), error="External command failed with exit code", warning = if (.Platform$OS.type=="windows") "execution failed")
21221+
21222+
if (test_R.utils) local({
21223+
tmp <- tempfile(fileext=".gz")
21224+
file.create(tmp); on.exit(unlink(tmp))
21225+
local({
21226+
conn <- file(tmp, 'wb'); on.exit(close(conn))
21227+
writeBin(as.raw(c(31L, 139L)), conn) # Gzip header magic numbers to trigger that read path
21228+
})
21229+
test(2320.2, fread(tmp), error="R.utils::decompressFile failed to decompress", warning="invalid")
21230+
})

0 commit comments

Comments
 (0)