From p@@|@h@@p@korv@ @end|ng |rom gm@||@com  Thu Apr 25 16:37:06 2019
From: p@@|@h@@p@korv@ @end|ng |rom gm@||@com (Pasi Haapakorva)
Date: Thu, 25 Apr 2019 17:37:06 +0300
Subject: [Rd] A bug in file.copy(), deletes file contents
Message-ID: <CAC1Ymy1Sza4DwjwRHq-2iv2Y9eBv6mkxZfW4A_0qaU2GoSHDtQ@mail.gmail.com>

Hi,

I've discovered a way to accidentally delete all your files with
file.copy(). This involves copying a directory to itself by bypassing
the check `if (recursive && to %in% from)` by pointing to a directory
with two differing ways.

Here I'm copying the directory foo to itself:

dir.create("foo")
cat(file = "foo/bar.txt", "baz\n")
readLines("foo/bar.txt")
#> [1] "baz"

file.copy("foo", ".", recursive = TRUE)
#> [1] TRUE
readLines("foo/bar.txt")
#> character(0)

Since "foo" is not ".", the directory is copied to itself and the
function calls file.create() to delete the file contents.

A simple fix would be to use `if (recursive && (to %in% from || from
%in% list.files(to)))` instead, I think. This could be slow if there
are a lot of files, so maybe this could be faster:

if (recursive && (to %in% from ||
normalizePath(dirname(normalizePath(from))) == normalizePath(to)))

There I'm looking if the parent dir of `from` matches the dir of `to`.
At least on my machine dirname() gives different path syntax than
normalizePath() so both input and output of dirname() needs to be put
though normalizePath().

There is a related bug in file.create(): it doesn't check if the file
already exists and goes on to delete contents of existing files.

Pasi Haapakorva



[Rd] A bug in file.copy(), deletes file contents
Pasi Haapakorva