From: "Mark E." 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) Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Content-description: Mail message body 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 /* For Win NT version check */ #include #include + #include 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) {