delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2000/08/16/15:39:50

Message-ID: <399AED46.7E53A0BB@softhome.net>
Date: Wed, 16 Aug 2000 21:36:38 +0200
From: Laurynas Biveinis <lauras AT softhome DOT net>
X-Mailer: Mozilla 4.74 [en] (Win98; U)
X-Accept-Language: lt,en
MIME-Version: 1.0
To: DJGPP Workers <djgpp-workers AT delorie DOT com>
Subject: open() patch (2nd try)
Reply-To: djgpp-workers AT delorie DOT com

Converted to use basename(), documentation nit fixed.

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/16 19:37:56
@@ -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/16 19:37:57
@@ -102,6 +102,12 @@
 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 symlink AT r{, changed behaviour}
+@findex O_NOLINK AT r{, new flag accepted by @code{open}}
+@findex O_NOFOLLOW AT r{, new flag accepted by @code{open}}
+@findex open AT r{, supports symlinks}
+@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{, supports symlinks}
 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/16 19:38:05
@@ -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>
@@ -22,11 +26,56 @@
 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 = basename(temp);
+         *last_separator = '\0';
+         last_separator = basename(filename);
+         strcat(temp, "/");
+         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 +104,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 +116,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 +124,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);
     }
   }
 
@@ -102,3 +151,4 @@
 
   return fd;
 }
+
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/16 19:38:06
@@ -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 @code{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	Wed Aug 16 15:38:13 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/16 19:38:13
@@ -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	Wed Aug 16 15:38:13 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	Wed Aug 16 15:38:13 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	Wed Aug 16 15:38:13 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	Wed Aug 16 15:38:13 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	Wed Aug 16 15:38:13 2000
@@ -0,0 +1,12 @@
+!<symlink>file1
+                                                              
+                                                  
+                                                   
+                                                  
+                                                   
+                                                 
+                                                  
+                                                  
+                                                   
+         
+           
\ No newline at end of file

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019