Mail Archives: djgpp-workers/2000/08/18/14:35:19
During fstat() hacking, I've found few bugs in __internal_readlink(),
so I resubmit the patch.
Any comments?
Laurynas
Index: djgpp/include/libc/symlink.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/libc/symlink.h,v
retrieving revision 1.1
diff -u -r1.1 symlink.h
--- symlink.h 2000/08/14 08:51:28 1.1
+++ symlink.h 2000/08/18 18:32:04
@@ -17,6 +17,19 @@
#ifndef _POSIX_SOURCE
+#include <sys/djtypes.h>
+
+__DJ_size_t
+#undef __DJ_size_t
+#define __DJ_size_t
+
+/* Semi-internal library function which reads symlink contents given */
+/* either a file name or its handle. Used by readlink(), fstat() and */
+/* user supplied (if any) file fstat handler. */
+
+int __internal_readlink(const char * __path, int __fhandle, char * __buf,
+ size_t __max);
+
/* A prototype for internal library function for fully resolving symlink */
/* chain. Standard function readlink() solves only one symlink level. */
/* If path name passed appears to be not a symlink, it is copied to result */
Index: djgpp/include/sys/fsext.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/sys/fsext.h,v
retrieving revision 1.5
diff -u -r1.5 fsext.h
--- fsext.h 2000/08/16 18:28:19 1.5
+++ fsext.h 2000/08/18 18:32:04
@@ -37,6 +37,8 @@
__FSEXT_symlink
} __FSEXT_Fnumber;
+#define __FSEXT_lstat __FSEXT_stat
+
/* _ready gets passed a fd and should return a mask of these,
as if we were emulating "int ready(int fd)" */
#define __FSEXT_ready_read 1
Index: djgpp/src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.20
diff -u -r1.20 wc204.txi
--- wc204.txi 2000/08/17 08:46:09 1.20
+++ wc204.txi 2000/08/18 18:32:05
@@ -93,14 +93,16 @@
as if @code{it_interval.tv_usec} were set to the system clock
granularity (55 AT dmn{msec} by default).
+@findex __internal_readlink AT r{, added to the library}
@findex __solve_symlinks AT r{, added to the library}
@findex lstat AT r{, added to the library}
@findex readlink AT r{, added to the library}
@findex S_ISLNK AT r{, added to the library}
@findex S_IFLNK AT r{, added to the library}
-UNIX-style symbolic links are fully emulated by library. As a part of this,
-new functions @code{__solve_symlinks}, @code{lstat} and @code{readlink};
-new macros @code{S_ISLNK} and @code{S_IFLNK} have been added to library.
+UNIX-style symbolic links are fully emulated by library. As a part of
+this, new functions @code{__internal_readlink}, @code{__solve_symlinks},
+@code{lstat} and @code{readlink}; new macros @code{S_ISLNK} and
+@code{S_IFLNK} have been added to library.
@findex O_NOLINK AT r{, new flag accepted by @code{open}}
@findex O_NOFOLLOW AT r{, new flag accepted by @code{open}}
Index: djgpp/src/libc/compat/unistd/_irdlink.c
===================================================================
RCS file: _irdlink.c
diff -N _irdlink.c
--- /dev/null Tue May 5 16:32:27 1998
+++ _irdlink.c Fri Aug 18 14:32:09 2000
@@ -0,0 +1,135 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
+
+#include <libc/stubs.h>
+#include <libc/symlink.h>
+#include <sys/fsext.h>
+#include <dir.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xsymlink.h"
+
+int __internal_readlink(const char * __path, int __fhandle, char * __buf,
+ size_t __max)
+{
+ ssize_t bytes_read = 0;
+ char buf[_SYMLINK_FILE_LEN];
+ char * data_buf;
+ int fd;
+ int ret;
+ off_t old_pos = 0;
+ long file_size;
+
+ /* Reject NULL and impossible arg combinations */
+ if (!__buf || (__path && __fhandle))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Provide ability to hook symlink support */
+ if (__path)
+ {
+ if (__FSEXT_call_open_handlers(__FSEXT_readlink, &ret, &__path))
+ return ret;
+ }
+ else if (__fhandle)
+ {
+ __FSEXT_Function *func = __FSEXT_get_function(__fhandle);
+ if (func)
+ {
+ int rv;
+ if (func(__FSEXT_readlink, &rv, &__path))
+ return rv;
+ }
+ }
+ else
+ {
+ /* What the ?.. */
+ errno = EINVAL;
+ return -1;
+ }
+
+
+ /* Get file size */
+
+ if (__fhandle)
+ file_size = filelength(__fhandle);
+ else
+ {
+ /* We will check if file exists by the way */
+ struct ffblk file_info;
+ if (findfirst(__path, &file_info, 0))
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ file_size = file_info.ff_fsize;
+ }
+
+ /* Is symlink file size a fixed magic value? */
+ if (file_size != _SYMLINK_FILE_LEN)
+ {
+ errno = EINVAL; /* Sad but true */
+ return -1;
+ }
+
+ /* Now we check for special DJGPP symlink format */
+
+ /* If we have file handle */
+ if (__fhandle)
+ {
+ /* Remember old file pos */
+ old_pos = tell(__fhandle);
+ if (old_pos == -1)
+ return -1;
+ lseek(__fhandle, 0, SEEK_SET);
+ fd = __fhandle;
+ }
+ else
+ {
+ fd = _open(__path, O_RDONLY);
+ if (fd < 0)
+ {
+ /* Retry with DENY-NONE share bit set. It might help in some cases
+ * when symlink file is opened by another program. We don't try with
+ * DENY-NONE set in the first _open() call, because it might fail under
+ * some circumstances. For details, see Ralf Brown's Interrupt List,
+ * description of INT 0x21, function 0x3D.
+ */
+ fd = _open(__path, O_RDONLY | SH_DENYNO);
+ if (fd < 0)
+ return -1; /* errno from _open() call */
+ }
+ }
+
+ bytes_read = read(fd, &buf, _SYMLINK_FILE_LEN);
+
+ if (__fhandle)
+ lseek(__fhandle, old_pos, SEEK_SET);
+ else
+ _close(fd);
+
+ if (bytes_read == -1)
+ return -1; /* Return errno set by _read() (_close() in worse case) */
+
+ /* Check for symlink file header */
+ if (strncmp(buf, _SYMLINK_PREFIX, _SYMLINK_PREFIX_LEN))
+ {
+ close(fd);
+ errno = EINVAL;
+ return -1;
+ }
+
+ data_buf = buf + _SYMLINK_PREFIX_LEN;
+ bytes_read = strchr(data_buf, '\n') - data_buf;
+ bytes_read = ((unsigned)bytes_read > __max) ? __max : bytes_read;
+ memcpy(__buf, data_buf, bytes_read);
+ return bytes_read;
+}
+
Index: djgpp/src/libc/compat/unistd/_irdlink.txh
===================================================================
RCS file: _irdlink.txh
diff -N _irdlink.txh
--- /dev/null Tue May 5 16:32:27 1998
+++ _irdlink.txh Fri Aug 18 14:32:10 2000
@@ -0,0 +1,38 @@
+@node __internal_readlink, io
+@subheading Syntax
+
+@example
+#include <libc/symlink.h>
+
+int __internal_readlink(const char * path, int fhandle, char * buf, size_t max)
+@end example
+
+@subheading Description
+In general applications shouldn't call this function; use @code{readlink}
+instead (@pxref{readlink}). However, there is one exception: if you have
+a @code{FSEXT} @code{fstat} file handler, and do not want do anything special
+about symlinks. In this case you should call this function from your handler
+to set properly @code{S_IFLNK} bit in @code{st_mode}. This function operates
+on either @var{path} @strong{or} @var{fhandle}. In any case, the other arg
+should be set to @code{NULL} or 0.
+
+@subheading Return Value
+
+Number of copied characters; value -1 is returned in case of
+error and @code{errno} is set. When value returned is equal to
+@var{size}, you cannot determine if there was enough room to
+copy whole name. So increase @var{size} and try again.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char buf[FILENAME_MAX + 1];
+if (__internal_readlink(0, "/dev/env/DJDIR/bin/sh.exe", buf, FILENAME_MAX) == -1)
+ if (errno == EINVAL)
+ puts("/dev/env/DJDIR/bin/sh.exe is not a symbolic link.");
+@end example
+
Index: djgpp/src/libc/compat/unistd/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/makefile,v
retrieving revision 1.6
diff -u -r1.6 makefile
--- makefile 2000/08/14 08:51:30 1.6
+++ makefile 2000/08/18 18:32:10
@@ -2,6 +2,7 @@
# Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
TOP=../..
+SRC += _irdlink.c
SRC += basename.c
SRC += dirname.c
SRC += fsync.c
Index: djgpp/src/libc/compat/unistd/readlink.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/readlink.c,v
retrieving revision 1.3
diff -u -r1.3 readlink.c
--- readlink.c 2000/08/16 18:29:37 1.3
+++ readlink.c 2000/08/18 18:32:10
@@ -2,84 +2,13 @@
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
#include <libc/stubs.h>
-#include <sys/fsext.h>
-#include <dir.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <io.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
+#include <libc/symlink.h>
#include <unistd.h>
#include "xsymlink.h"
int readlink(const char * filename, char * buffer, size_t size)
{
- ssize_t bytes_read = 0;
- char buf[_SYMLINK_FILE_LEN];
- char * data_buf;
- int fd;
- struct ffblk file_info;
- int ret;
-
- /* Reject NULLs */
- if (!filename || !buffer)
- {
- errno = EINVAL;
- return -1;
- }
-
- /* Provide ability to hook symlink support */
- if (__FSEXT_call_open_handlers(__FSEXT_readlink, &ret, &filename))
- return ret;
-
- /* Does symlink file exist at all? */
- if (findfirst(filename, &file_info, 0))
- {
- errno = ENOENT;
- return -1;
- }
-
- /* Is symlink file size a fixed magic value? */
- if (file_info.ff_fsize != _SYMLINK_FILE_LEN)
- {
- errno = EINVAL; /* Sad but true */
- return -1;
- }
-
- /* Now we check for special DJGPP symlink format */
- fd = _open(filename, O_RDONLY);
- if (fd < 0)
- {
- /* Retry with DENY-NONE share bit set. It might help in some cases
- * when symlink file is opened by another program. We don't try with
- * DENY-NONE set in the first _open() call, because it might fail under
- * some circumstances. For details, see Ralf Brown's Interrupt List,
- * description of INT 0x21, function 0x3D.
- */
- fd = _open(filename, O_RDONLY | SH_DENYNO);
- if (fd < 0)
- return -1; /* errno from open() call */
- }
-
- bytes_read = read(fd, &buf, _SYMLINK_FILE_LEN);
- _close(fd);
- if (bytes_read == -1)
- return -1; /* Return errno set by _read() (_close() in worse case) */
-
- /* Check for symlink file header */
- if (strncmp(buf, _SYMLINK_PREFIX, _SYMLINK_PREFIX_LEN))
- {
- close(fd);
- errno = EINVAL;
- return -1;
- }
-
- data_buf = buf + _SYMLINK_PREFIX_LEN;
- bytes_read = strchr(data_buf, '\n') - data_buf;
- bytes_read = ((unsigned)bytes_read > size) ? size : bytes_read;
- memcpy(buffer, data_buf, bytes_read);
- return bytes_read;
+ return __internal_readlink(filename, 0, buffer, size);
}
- Raw text -