Discussion:
errno from open(<directory>) ?
(too old to reply)
Tim Rühsen
2017-05-22 10:58:59 UTC
Permalink
Raw Message
Hi,

on GNU/Linux open() on a directory returns -1 and sets errno to EISDIR.

Built on MinGW / Win32 the same open sets errno to EACCES.


We currently use a work-around like
+ int rc = open(pathname, flags, mode);
+#ifdef _WIN32
+ if (rc < 0 && errno == EACCES) {
+ DWORD attrs = GetFileAttributes(pathname);
+ if (attrs & FILE_ATTRIBUTE_DIRECTORY)
+ errno = EISDIR;
+ }
+#endif

Could you consider to adjust the behavior of gnulib's open() similarly,
or is there any reason against it ?


With Best Regards, Tim
Tim Rühsen
2017-05-22 11:02:29 UTC
Permalink
Raw Message
Post by Tim Rühsen
Hi,
on GNU/Linux open() on a directory returns -1 and sets errno to EISDIR.
Built on MinGW / Win32 the same open sets errno to EACCES.
We currently use a work-around like
+ int rc = open(pathname, flags, mode);
+#ifdef _WIN32
+ if (rc < 0 && errno == EACCES) {
+ DWORD attrs = GetFileAttributes(pathname);
+ if (attrs & FILE_ATTRIBUTE_DIRECTORY)
+ errno = EISDIR;
+ }
+#endif
Could you consider to adjust the behavior of gnulib's open() similarly,
or is there any reason against it ?
And if you apply something like that, please be so kind and mention
Akash Rawal, one of our GSOC students who came up with this code.

With Best Regards, Tim
Gisle Vanem
2017-05-22 12:04:58 UTC
Permalink
Raw Message
Post by Tim Rühsen
Built on MinGW / Win32 the same open sets errno to EACCES.
We currently use a work-around like
+ int rc = open(pathname, flags, mode);
+#ifdef _WIN32
+ if (rc < 0 && errno == EACCES) {
+ DWORD attrs = GetFileAttributes(pathname);
+ if (attrs & FILE_ATTRIBUTE_DIRECTORY)
+ errno = EISDIR;
+ }
+#endif
MSDN says:
If the function fails, the return value is INVALID_FILE_ATTRIBUTES.

which is ((DWORD)-1). So the test should better be:

if (attr != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
errno = EISDIR;
--
--gv
Tim Rühsen
2017-05-22 13:04:48 UTC
Permalink
Raw Message
Post by Gisle Vanem
Post by Tim Rühsen
Built on MinGW / Win32 the same open sets errno to EACCES.
We currently use a work-around like
+ int rc = open(pathname, flags, mode);
+#ifdef _WIN32
+ if (rc < 0 && errno == EACCES) {
+ DWORD attrs = GetFileAttributes(pathname);
+ if (attrs & FILE_ATTRIBUTE_DIRECTORY)
+ errno = EISDIR;
+ }
+#endif
If the function fails, the return value is INVALID_FILE_ATTRIBUTES.
if (attr != INVALID_FILE_ATTRIBUTES && (attrs &
FILE_ATTRIBUTE_DIRECTORY))
errno = EISDIR;
Thanks for your correction. I'll amend the code for Wget2 respectively.

With Best Regards, Tim
Paul Eggert
2017-05-22 15:00:14 UTC
Permalink
Raw Message
Post by Tim Rühsen
on GNU/Linux open() on a directory returns -1 and sets errno to EISDIR.
No, for example on my platform (Fedora 25 x86-64), 'strace cat .'
outputs the line 'open(".", O_RDONLY) = 3'.
Tim Rühsen
2017-05-22 19:30:56 UTC
Permalink
Raw Message
Post by Paul Eggert
Post by Tim Rühsen
on GNU/Linux open() on a directory returns -1 and sets errno to EISDIR.
No, for example on my platform (Fedora 25 x86-64), 'strace cat .'
outputs the line 'open(".", O_RDONLY) = 3'.
Same here on Debian unstable.
What you want to say is, that it depends on the flags.
And you are right, I wasn't very precise in that point.

Here we use
fd = open(fname, O_WRONLY | flag | O_CREAT | O_NONBLOCK | O_BINARY, S_IRUSR |
S_IWUSR | S_IRGRP | S_IROTH);

'flag' might be one of O_TRUNC, O_APPEND or O_EXCL.

A test with different flags for open(<existing directory>) shows failure +
errno EISDIR when opening for writing.

With Best Regards, Tim
Bruno Haible
2017-05-22 20:38:07 UTC
Permalink
Raw Message
Post by Tim Rühsen
Post by Paul Eggert
Post by Tim Rühsen
on GNU/Linux open() on a directory returns -1 and sets errno to EISDIR.
No, for example on my platform (Fedora 25 x86-64), 'strace cat .'
outputs the line 'open(".", O_RDONLY) = 3'.
Same here on Debian unstable.
What you want to say is, that it depends on the flags.
And you are right, I wasn't very precise in that point.
Here we use
fd = open(fname, O_WRONLY | flag | O_CREAT | O_NONBLOCK | O_BINARY, S_IRUSR |
S_IWUSR | S_IRGRP | S_IROTH);
'flag' might be one of O_TRUNC, O_APPEND or O_EXCL.
A test with different flags for open(<existing directory>) shows failure +
errno EISDIR when opening for writing.
This portability issue is an ideal "skills ramp up" for someone who has only done
smaller contributions to gnulib so far.

Steps:
1) Consider the standards: What does POSIX:2008 say about the issue?
2) Extend the unit test of module 'open'.
3) Ask us to test these extended unit tests on various platforms (Mac OS X, Solaris,
FreeBSD, HP-UX, etc.).
4) Mention the issue in the doc section about 'open'.
5) Extend the Autoconf test to recognize this case and arrange to override the
'open' function when the Autoconf test fails.
6) Extend the workaround (lib/open.c) and make sure the unit test now succeeds
on the relevant platform(s).

Any takers? Tim? Gisle?

Bruno
Tim Rühsen
2017-05-23 07:58:57 UTC
Permalink
Raw Message
Post by Bruno Haible
Post by Tim Rühsen
Post by Paul Eggert
Post by Tim Rühsen
on GNU/Linux open() on a directory returns -1 and sets errno to EISDIR.
No, for example on my platform (Fedora 25 x86-64), 'strace cat .'
outputs the line 'open(".", O_RDONLY) = 3'.
Same here on Debian unstable.
What you want to say is, that it depends on the flags.
And you are right, I wasn't very precise in that point.
Here we use
fd = open(fname, O_WRONLY | flag | O_CREAT | O_NONBLOCK | O_BINARY, S_IRUSR |
S_IWUSR | S_IRGRP | S_IROTH);
'flag' might be one of O_TRUNC, O_APPEND or O_EXCL.
A test with different flags for open(<existing directory>) shows failure +
errno EISDIR when opening for writing.
This portability issue is an ideal "skills ramp up" for someone who has only done
smaller contributions to gnulib so far.
1) Consider the standards: What does POSIX:2008 say about the issue?
2) Extend the unit test of module 'open'.
3) Ask us to test these extended unit tests on various platforms (Mac OS X, Solaris,
FreeBSD, HP-UX, etc.).
4) Mention the issue in the doc section about 'open'.
5) Extend the Autoconf test to recognize this case and arrange to override the
'open' function when the Autoconf test fails.
6) Extend the workaround (lib/open.c) and make sure the unit test now succeeds
on the relevant platform(s).
Any takers? Tim? Gisle?
Basically a very good idea. But I am really busy working on
wget2/libwget, maintaining projects and mentoring GSOC students.

I just created a Wiki[1] page describing this issue. Maybe we can get
one (or more) of our students to work on this - it is still 'community
bonding' time.

Thanks for providing the detailed steps.
Post by Bruno Haible
Bruno
[1]
https://gitlab.com/gnuwget/wget2/wikis/enhancing-gnulib-module-'open'-to-return-eisdir-regarding-posix.2008

With Best Regards, Tim

Loading...