Skip to content

Recursive dir.create() on Windows shares

3 messages · Duncan Murdoch, Evan Cortens

#
Hi folks,

I've noticed that there's an issue with the recursive creation of
directories that reside on network shares. For example:
dir.create('\\\\SERVERNAME\\Empl\\Home1\\active\\e\\ecortens\\thisisatest',
recursive = TRUE)
Warning message:
In
dir.create("\\\\SERVERNAME\\Empl\\Home1\\active\\e\\ecortens\\thisisatest",
 :
  cannot create dir '\\SERVERNAME\Empl', reason 'Permission denied'

The issue is that dir.create() is skipping the server name, but it's not
skipping the share name. So, in the above example, it's trying to create
"Empl", which fails, setting errno to the code for "Permission denied",
instead of EEXIST, the code for "file already exists", because it's not
actually a file, and therefore can't exist as one. (Incidentally, the same
challenge arises with the system call _wstat(), which also will return a
-1, telling you that the share name doesn't exist.)

The solution to this issue, then, is to skip not only the server name, but
the share name as well, which is easily done with one more line of code:

C:\Users\ecortens\Software\R-devel\src>svn diff
Index: main/platform.c
===================================================================
--- main/platform.c     (revision 71366)
+++ main/platform.c     (working copy)
@@ -2159,10 +2159,11 @@
     while (*p == L'\\' && wcslen(dir) > 1 && *(p-1) != L':') *p-- = L'\0';
     if (recursive) {
        p = dir;
-       /* skip leading \\share */
+       /* skip leading \\server\share */
        if (*p == L'\\' && *(p+1) == L'\\') {
            p += 2;
            p = wcschr(p, L'\\');
+           p = wcschr(p+1, L'\\');
        }
        while ((p = wcschr(p+1, L'\\'))) {
            *p = L'\0';

This fixes the issue for me, and I can create directories no problem.
However, I'm a little worried, as the code in platform.c has been this way
since 2008--surely this can't have been a bug since then. Yet I can't find
any indication that the UNC naming convention has changed, and I can't find
any way that will let you test the pathname to see if it's "\\server\share"
or "\\share".

I've also filed this on bugzilla, and have updated it there.  See
https://bugs.r-project.org/bugzilla/show_bug.cgi?id=1715

Thanks for an amazing piece of software!

Best,

Evan

P. S. I'm new to the mailing list, so I apologize in advance if I'm
violating any conventions I'm unaware of.
#
On 26/09/2016 5:27 PM, Evan Cortens wrote:
Presumably someone from Microsoft will respond to this.

Duncan Murdoch
#
One more comment on this. In Python, there is a function,
os.path.splitdrive(), that performs path splitting in the same way my patch
does. Here's a quote from the Python docs:

"If the path contains a UNC path, drive will contain the host name and
share, up to but not including the fourth separator. e.g.
splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")" (see
https://docs.python.org/3/library/os.path.html#os.path.splitdrive )

The now-deprecated (as of Python 3.1) os.path.splitunc() treated UNC paths
in a similar way.

So this to say I believe the correct behaviour is to skip the first two
parts of a path beginning with \\ before attempting to create a directory
in a call to dir.create() with recursive = TRUE.

On Mon, Sep 26, 2016 at 3:46 PM, Duncan Murdoch <murdoch.duncan at gmail.com>
wrote: