Mail Archives: djgpp-workers/2000/08/15/14:35:02
It makes open() recognize symlinks, adds two new mode flags for
it (O_NOLINK and O_NOFOLLOW), updates docs and adds testsuite.
Any comments?
Laurynas
Index: djgpp/include/fcntl.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/fcntl.h,v
retrieving revision 1.3
diff -u -r1.3 fcntl.h
--- fcntl.h 1998/06/28 22:27:10 1.3
+++ fcntl.h 2000/08/15 18:32:41
@@ -60,6 +60,11 @@
#ifndef _POSIX_SOURCE
+/* Additional non-POSIX flags for open(). */
+/* They are present on GNU libc. */
+#define O_NOLINK 0x4000
+#define O_NOFOLLOW 0x8000
+
#define SH_COMPAT 0x0000
#define SH_DENYRW 0x0010
#define SH_DENYWR 0x0020
Index: djgpp/src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.19
diff -u -r1.19 wc204.txi
--- wc204.txi 2000/08/15 17:38:40 1.19
+++ wc204.txi 2000/08/15 18:32:42
@@ -102,6 +102,10 @@
new functions @code{__solve_symlinks}, @code{lstat} and @code{readlink};
new macros @code{S_ISLNK} and @code{S_IFLNK} have been added to library.
+@findex open AT r{, changed behaviour}
+@code{open} now follows symlinks when opening file. Also, it honors two new
+mode flags: @code{O_NOLINK} and @code{O_NOFOLLOW}.
+
@findex symlink AT r{, changed behaviour}
As a part of symlink emulation, @code{symlink} no longer emulates symlinks
to executables by creating stubs. It creates symlinks to all files instead.
Index: djgpp/src/libc/posix/fcntl/open.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/fcntl/open.c,v
retrieving revision 1.5
diff -u -r1.5 open.c
--- open.c 1999/06/03 17:27:37 1.5
+++ open.c 2000/08/15 18:32:52
@@ -1,9 +1,13 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#include <libc/stubs.h>
+#include <libc/symlink.h>
+#include <libc/unconst.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -18,15 +22,62 @@
/* Extra share flags that can be indicated by the user */
int __djgpp_share_flags;
+/* Helper function for O_NOFOLLOW handling. */
+static char *find_last_sep(const char * str);
+
int
open(const char* filename, int oflag, ...)
{
int fd, dmode, bintext, dont_have_share;
+ char real_name[FILENAME_MAX + 1];
int should_create = (oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
+ /* Solve symlinks and honor O_NOLINK flag */
+ if (oflag & O_NOLINK)
+ strcpy(real_name, filename);
+ else
+ {
+ if (!__solve_symlinks(filename, real_name))
+ return -1; /* errno from from __solve_symlinks() */
+ }
+
+ /* Honor O_NOFOLLOW flag. */
+ if (oflag & O_NOFOLLOW)
+ {
+ /* O_NOFOLLOW, as defined in glibc, requires open() to fail if the
+ * last path component is a symlink. However, it still requires to
+ * resolve all other path components.
+ * We check if there were any symlinks by comparing __solve_symlinks()
+ * input and output. That function does not perform any path
+ * canonicalization so it should be safe. */
+ if (strcmp(filename, real_name))
+ {
+ /* Yes, there were symlinks in the path. Now take all but the last
+ * path component from `real_name', add last path component from
+ * `filename', and try to resolve that mess.
+ */
+ char temp[FILENAME_MAX + 1];
+ char resolved[2];
+ char * last_separator;
+ int old_errno = errno;
+ strcpy(temp, real_name);
+ last_separator = find_last_sep(temp);
+ *last_separator = '\0';
+ last_separator = find_last_sep(filename);
+ strcat(temp, last_separator);
+ if ((readlink(temp, resolved, 1) != -1) || (errno != EINVAL))
+ {
+ /* Yes, the last path component was a symlink. */
+ errno = ELOOP;
+ return -1;
+ }
+ errno = old_errno;
+ }
+ }
+
/* Check this up front, to reduce cost and minimize effect */
if (should_create)
- if (__file_exists(filename))
+ if (__file_exists(real_name))
{
/* file exists and we didn't want it to */
errno = EEXIST;
@@ -55,10 +106,10 @@
}
if (should_create)
- fd = _creatnew(filename, dmode, oflag & 0xff);
+ fd = _creatnew(real_name, dmode, oflag & 0xff);
else
{
- fd = _open(filename, oflag);
+ fd = _open(real_name, oflag);
if (fd == -1)
{
@@ -67,7 +118,7 @@
if (errno == EMFILE || errno == ENFILE)
return fd;
- if (__file_exists(filename))
+ if (__file_exists(real_name))
{
/* Under multi-taskers, such as Windows, our file might be
open by some other program with DENY-NONE sharing bit,
@@ -75,12 +126,12 @@
DENY-NONE bit set, unless some sharing bits were already
set in the initial call. */
if (dont_have_share)
- fd = _open(filename, oflag | SH_DENYNO);
+ fd = _open(real_name, oflag | SH_DENYNO);
}
/* Don't call _creat on existing files for which _open fails,
since the file could be truncated as a result. */
else if ((oflag & O_CREAT))
- fd = _creat(filename, dmode);
+ fd = _creat(real_name, dmode);
}
}
@@ -101,4 +152,14 @@
lseek(fd, 0, SEEK_END);
return fd;
+}
+
+static char *find_last_sep(const char * str)
+{
+ char * res = strrchr(str, '/');
+ if (!res)
+ res = strrchr(str, '\\');
+ if (!res)
+ res = unconst(str, char*);
+ return res;
}
Index: djgpp/src/libc/posix/fcntl/open.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/fcntl/open.txh,v
retrieving revision 1.3
diff -u -r1.3 open.txh
--- open.txh 1998/09/27 15:22:12 1.3
+++ open.txh 2000/08/15 18:32:52
@@ -62,6 +62,16 @@
function (@pxref{__djgpp_set_ctrl_c}) if you want @kbd{Ctrl-C} to
generate interrupts while console is read in binary mode.
+@item O_NOFOLLOW
+
+@code{open} will fail with errno set to ELOOP, if the last patch component
+in @var{file} is symlink.
+
+@item O_NOLINK
+
+If @var{file} is a symlink, @code{open} will open symlink file itself instead
+of referred file.
+
@end table
If the file is created by this call, it will be given the read/write
Index: djgpp/tests/libc/posix/fcntl/file1
===================================================================
RCS file: file1
diff -N file1
--- /dev/null Tue May 5 16:32:27 1998
+++ file1 Tue Aug 15 14:32:58 2000
@@ -0,0 +1 @@
+file1
Index: djgpp/tests/libc/posix/fcntl/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/posix/fcntl/makefile,v
retrieving revision 1.1
diff -u -r1.1 makefile
--- makefile 1995/08/27 07:25:44 1.1
+++ makefile 2000/08/15 18:32:58
@@ -2,6 +2,7 @@
SRC += binpr.c
SRC += bt.c
+SRC += open.c
SRC += trunc.c
include $(TOP)/../makefile.inc
Index: djgpp/tests/libc/posix/fcntl/open.c
===================================================================
RCS file: open.c
diff -N open.c
--- /dev/null Tue May 5 16:32:27 1998
+++ open.c Tue Aug 15 14:32:58 2000
@@ -0,0 +1,89 @@
+/* Testsuite for open()
+ * TODO: only symlink handling aspect is checked. Other things should be
+ * checked too.
+ * Currently there are following tests:
+ * 1. Open a symlink. Check if we really have opened a referred file.
+ * 2. Open a symlink with O_NOLINK flag. Check if we really have opened a
+ * symlink file itself.
+ * 3. Open simple file in a symlink subdir with O_NOFOLLOW flag. Check if
+ * we really have opened a referred file.
+ * 4. Open symlink in a symlink subdir with O_NOFOLLOW flag. Should fail with ELOOP.
+ * ELOOP.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void test_success(int testnum, const char * fn, int flags,
+ int data_size, const char * data);
+
+int main(void)
+{
+ int fd;
+ if (!__file_exists("file1") || !__file_exists("test1") ||
+ !__file_exists("test2") || !__file_exists("dir/file1"))
+ {
+ fprintf(stderr, "Required data file is missing\n");
+ exit(1);
+ }
+ test_success(1, "test1", O_RDONLY, 5, "file1");
+ test_success(2, "test1", O_RDONLY | O_NOLINK, 10, "!<symlink>");
+ test_success(3, "test2/file1", O_RDONLY | O_NOFOLLOW, 5, "file1");
+ fd = open("test2/test1", O_RDONLY | O_NOFOLLOW);
+ if (fd != -1)
+ {
+ fprintf(stderr, "Test 4 failed - unexpected open() success.\n");
+ exit(1);
+ }
+ if (errno != ELOOP)
+ {
+ perror("Test 4 failed - wrong errno returned ");
+ exit(1);
+ }
+ printf("Test 4 passed\n");
+ return 0;
+}
+
+static void test_success(int testnum, const char * fn, int flags,
+ int data_size, const char * data)
+{
+ char err_buf[50];
+ int bytes_read;
+ char buffer[100];
+ int fd = open(fn, flags);
+ if (fd == -1)
+ {
+ sprintf(err_buf, "Test %d failed - unexpected open() failure ", testnum);
+ perror(err_buf);
+ exit(1);
+ }
+ bytes_read = read(fd, buffer, data_size);
+ if (bytes_read == -1)
+ {
+ sprintf(err_buf, "Test %d failed - unexpected read() failure ", testnum);
+ perror(err_buf);
+ close(fd);
+ exit(1);
+ }
+ if (bytes_read != data_size)
+ {
+ fprintf(stderr,
+ "Test %d failed - read() returned less bytes than expected.\n", testnum);
+ buffer[bytes_read] = '\0';
+ printf("buffer = %s\n", buffer);
+ close(fd);
+ exit(1);
+ }
+ if (strncmp(buffer, data, data_size))
+ {
+ fprintf(stderr, "Test %d failed - read() returned wrong file data.\n",
+ testnum);
+ close(fd);
+ exit(1);
+ }
+ close(fd);
+ printf("Test %d passed\n", testnum);
+}
Index: djgpp/tests/libc/posix/fcntl/test1
===================================================================
RCS file: test1
diff -N test1
--- /dev/null Tue May 5 16:32:27 1998
+++ test1 Tue Aug 15 14:32:58 2000
@@ -0,0 +1,12 @@
+!<symlink>file1
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Index: djgpp/tests/libc/posix/fcntl/test2
===================================================================
RCS file: test2
diff -N test2
--- /dev/null Tue May 5 16:32:27 1998
+++ test2 Tue Aug 15 14:32:59 2000
@@ -0,0 +1,12 @@
+!<symlink>dir
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Index: djgpp/tests/libc/posix/fcntl/dir/file1
===================================================================
RCS file: file1
diff -N file1
--- /dev/null Tue May 5 16:32:27 1998
+++ file1 Tue Aug 15 14:32:59 2000
@@ -0,0 +1 @@
+file1
Index: djgpp/tests/libc/posix/fcntl/dir/test1
===================================================================
RCS file: test1
diff -N test1
--- /dev/null Tue May 5 16:32:27 1998
+++ test1 Tue Aug 15 14:32:59 2000
@@ -0,0 +1,12 @@
+!<symlink>file1
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
- Raw text -