Message-ID: <399D80E1.716E69CF@softhome.net> Date: Fri, 18 Aug 2000 20:30:57 +0200 From: Laurynas Biveinis X-Mailer: Mozilla 4.74 [en] (Win98; U) X-Accept-Language: lt,en MIME-Version: 1.0 To: djgpp-workers AT delorie DOT com Subject: Re: Patch: __internal_readlink() v2 References: <399C2FC5 DOT A12ECAA3 AT softhome DOT net> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com 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 + +__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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +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 -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #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); }