delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2002/09/20/21:29:36

From: "Mark E." <snowball3 AT softhome DOT net>
To: djgpp-workers AT delorie DOT com
Date: Fri, 20 Sep 2002 21:27:07 -0400
MIME-Version: 1.0
Subject: working toward a realpath implementation
Message-ID: <3D8B92AB.7174.567AAC@localhost>
X-mailer: Pegasus Mail for Windows (v4.02a)
Reply-To: djgpp-workers AT delorie DOT com

Hello,
An implementation of realpath would certainly help in the posix compliance 
department. To help attain a compliant version, I've made some changes to 
fixpath.c to make implementing realpath easier. For example, I changed 
FILENAME_MAX to PATH_MAX.  I also created a new function __canonicalize_path 
with a return type compatible with what realpath returns. This way, 
__canonicalize_path can function as a wrapper for both _fixpath and realpath.

BTW, while realpath mandates more checking than _fixpath, it still has some 
flaws like its _fixpath cousin. For example, you can easily (and 
deliberately) overflow the output buffer if enough space isn't provided for 
it.

Index: fixpath.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/fixpath.c,v
retrieving revision 1.7
diff -c -p -r1.7 fixpath.c
*** fixpath.c	17 Oct 2001 05:08:39 -0000	1.7
--- fixpath.c	21 Sep 2002 01:08:13 -0000
***************
*** 15,20 ****
--- 15,21 ----
  #include <dos.h>		/* For Win NT version check */
  #include <sys/stat.h>
  #include <libc/dosio.h>
+ #include <limits.h>
  
  static unsigned use_lfn;
  
*************** static char *
*** 24,30 ****
  __get_current_directory(char *out, int drive_number)
  {
    __dpmi_regs r;
!   char tmpbuf[FILENAME_MAX];
  
    memset(&r, 0, sizeof(r));
    r.x.flags = 1;		/* Set carry for safety */
--- 25,31 ----
  __get_current_directory(char *out, int drive_number)
  {
    __dpmi_regs r;
!   char tmpbuf[PATH_MAX];
  
    memset(&r, 0, sizeof(r));
    r.x.flags = 1;		/* Set carry for safety */
*************** __get_current_directory(char *out, int d
*** 71,77 ****
    r.x.ax = 0x7160;
    r.x.cx = 0x8002;	/* Get Long Path Name, using subst drive basis */
    r.x.es = __tb_segment;
!   r.x.di = __tb_offset + FILENAME_MAX;
    
    tmpbuf[0] = drive_number + 'A';
    tmpbuf[1] = ':';
--- 72,78 ----
    r.x.ax = 0x7160;
    r.x.cx = 0x8002;	/* Get Long Path Name, using subst drive basis */
    r.x.es = __tb_segment;
!   r.x.di = __tb_offset + PATH_MAX;
    
    tmpbuf[0] = drive_number + 'A';
    tmpbuf[1] = ':';
*************** __get_current_directory(char *out, int d
*** 83,89 ****
  
    if (!(r.x.flags & 1))
    {
!     dosmemget(__tb + FILENAME_MAX, sizeof(tmpbuf), tmpbuf);
  
      /* Validate return form and drive matches what _fixpath expects. */
      if (tmpbuf[0] == (drive_number + 'A') && tmpbuf[1] == ':')
--- 84,90 ----
  
    if (!(r.x.flags & 1))
    {
!     dosmemget(__tb + PATH_MAX, sizeof(tmpbuf), tmpbuf);
  
      /* Validate return form and drive matches what _fixpath expects. */
      if (tmpbuf[0] == (drive_number + 'A') && tmpbuf[1] == ':')
*************** is_term(int c)
*** 117,123 ****
    return c == '/' || c == '\\' || c == '\0';
  }
  
! /* Takes as input an arbitrary path.  Fixes up the path by:
     1. Removing consecutive slashes
     2. Removing trailing slashes
     3. Making the path absolute if it wasn't already
--- 118,125 ----
    return c == '/' || c == '\\' || c == '\0';
  }
  
! /* Wrapper for the functions realpath and _fixpath.
!    Takes as input an arbitrary path.  Fixes up the path by:
     1. Removing consecutive slashes
     2. Removing trailing slashes
     3. Making the path absolute if it wasn't already
*************** is_term(int c)
*** 125,144 ****
     5. Removing ".." entries in the path (and the directory above them)
     6. Adding a drive specification if one wasn't there
     7. Converting all slashes to '/'
!  */
! void
! _fixpath(const char *in, char *out)
  {
    int		drive_number;
!   char		in1[FILENAME_MAX];
    char		*ip;
    char		*op = out;
    int		preserve_case = _preserve_fncase();
    char		*name_start;
    int		mbsize;
  
    use_lfn = _use_lfn(in);
  
    /* Perform the same magic conversions that _put_path does.  */
    _put_path(in);
    dosmemget(__tb, sizeof(in1), in1);
--- 127,150 ----
     5. Removing ".." entries in the path (and the directory above them)
     6. Adding a drive specification if one wasn't there
     7. Converting all slashes to '/'
! */
! 
! char *
! __canonicalize_path(const char *in, char *out)
  {
    int		drive_number;
!   char		in1[PATH_MAX];
    char		*ip;
    char		*op = out;
    int		preserve_case = _preserve_fncase();
    char		*name_start;
    int		mbsize;
+   char		*op_limit;
  
    use_lfn = _use_lfn(in);
  
+   op_limit = op + PATH_MAX;
+ 
    /* Perform the same magic conversions that _put_path does.  */
    _put_path(in);
    dosmemget(__tb, sizeof(in1), in1);
*************** _fixpath(const char *in, char *out)
*** 160,166 ****
        if (*ip <= 'Z')
  	*op++ = drive_number + 'a';
        else
! 	*op++ = *ip;
        ++ip;
      }
      *op++ = *ip++;
--- 166,172 ----
        if (*ip <= 'Z')
  	*op++ = drive_number + 'a';
        else
! 	* op++ = *ip;
        ++ip;
      }
      *op++ = *ip++;
*************** _fixpath(const char *in, char *out)
*** 213,218 ****
--- 219,231 ----
        continue;
      }
  
+     /* Buffer overflow check.  */
+     if (op >= op_limit)
+     {
+       errno = ENAMETOOLONG;
+       return NULL;
+     }
+ 
      /* Copy path component from in to out */
      *op++ = '/';
  #if 0
*************** _fixpath(const char *in, char *out)
*** 229,234 ****
--- 242,254 ----
  	  }
  	else
  	  *op++ = *ip++;
+ 
+         /* Check for buffer overflow.  */
+         if (op >= op_limit)
+         {
+           errno = ENAMETOOLONG;
+           return NULL;
+         }
        }
  #endif
    }
*************** _fixpath(const char *in, char *out)
*** 236,248 ****
    /* If root directory, insert trailing slash */
    if (op == out + 2) *op++ = '/';
  
    /* Null terminate the output */
    *op = '\0';
  
    /* switch FOO\BAR to foo/bar, downcase where appropriate */
    for (op = out + 3, name_start = op - 1; *name_start; op++)
    {
!     char long_name[FILENAME_MAX];
  
  #if 1
      /* skip multibyte character */
--- 256,275 ----
    /* If root directory, insert trailing slash */
    if (op == out + 2) *op++ = '/';
  
+   /* Check for buffer overflow.  */
+   if (op >= op_limit)
+   {
+     errno = ENAMETOOLONG;
+     return NULL;
+   }
+ 
    /* Null terminate the output */
    *op = '\0';
  
    /* switch FOO\BAR to foo/bar, downcase where appropriate */
    for (op = out + 3, name_start = op - 1; *name_start; op++)
    {
!     char long_name[PATH_MAX];
  
  #if 1
      /* skip multibyte character */
*************** _fixpath(const char *in, char *out)
*** 286,298 ****
      else if (*op == '\0')
        break;
    }
  }
  
  #ifdef TEST
  
  int main (int argc, char *argv[])
  {
!   char fixed[FILENAME_MAX];
    __dpmi_regs r;
  
    if (argc > 2) {
--- 313,333 ----
      else if (*op == '\0')
        break;
    }
+ 
+   return out;
+ }
+ 
+ void
+ _fixpath(const char *in, char *out)
+ {
+   __canonicalize_path(in, out);
  }
  
  #ifdef TEST
  
  int main (int argc, char *argv[])
  {
!   char fixed[PATH_MAX];
    __dpmi_regs r;
  
    if (argc > 2) {

- Raw text -


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