Recursive dir.create() on Windows shares

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Recursive dir.create() on Windows shares

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.

--
Evan Cortens, PhD
Institutional Analyst - Office of Institutional Analysis
Mount Royal University
403-440-6529

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Recursive dir.create() on Windows shares

Duncan Murdoch-2
On 26/09/2016 5:27 PM, Evan Cortens wrote:

> 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.
>

Presumably someone from Microsoft will respond to this.

Duncan Murdoch

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Recursive dir.create() on Windows shares

Evan Cortens
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 <[hidden email]>
wrote:

> On 26/09/2016 5:27 PM, Evan Cortens wrote:
>
>> 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.
>>
>>
> Presumably someone from Microsoft will respond to this.
>
> Duncan Murdoch
>
>


--
Evan Cortens, PhD
Institutional Analyst - Office of Institutional Analysis
Mount Royal University
403-440-6529

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel