Date: Sun, 3 Nov 1996 17:00:20 +0200 (IST) From: Eli Zaretskii To: djgpp-workers AT delorie DOT com Subject: /dev/null support by `stat' and `_truename' Message-Id: Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII `_truename' didn't use `putpath' and therefore didn't support the /dev/ style of standard devices. `stat' also failed on devices in some cases. (I think this is the cause of bash failing on redirection to /dev/null.) Here's the patch: *** src/libc/posix/sys/stat/stat.c~1 Fri Nov 1 11:06:52 1996 --- src/libc/posix/sys/stat/stat.c Sat Nov 2 15:05:56 1996 *************** stat_assist(const char *path, struct sta *** 391,396 **** --- 391,397 ---- { struct ffblk ff_blk; char canon_path[MAX_TRUE_NAME]; + char pathname[MAX_TRUE_NAME]; short drv_no; unsigned dos_ftime; *************** stat_assist(const char *path, struct sta *** 407,420 **** statbuf->st_blksize = _go32_info_block.size_of_transfer_buffer; #endif /* Get the drive number. It is always explicit, since we called `_fixpath' on the original pathname. */ ! drv_no = toupper(*path) - 'A'; /* Produce canonical pathname, with all the defaults resolved and all redundant parts removed. This calls undocumented DOS function 60h. */ ! if (_truename(path, canon_path)) { /* Detect character device names which must be treated specially. We could simply call FindFirst and test the 6th bit, but some --- 408,428 ---- statbuf->st_blksize = _go32_info_block.size_of_transfer_buffer; #endif + /* Make the path explicit. This makes the rest of our job much + easier by getting rid of some constructs which, if present, + confuse `_truename' and/or `findfirst'. In particular, it + deletes trailing slashes, makes "d:" explicit, and allows us + to make an illusion of having a ".." entry in root directories. */ + _fixpath (path, pathname); + /* Get the drive number. It is always explicit, since we called `_fixpath' on the original pathname. */ ! drv_no = toupper(pathname[0]) - 'A'; /* Produce canonical pathname, with all the defaults resolved and all redundant parts removed. This calls undocumented DOS function 60h. */ ! if (_truename(path, canon_path) || _truename(pathname, canon_path)) { /* Detect character device names which must be treated specially. We could simply call FindFirst and test the 6th bit, but some *************** stat_assist(const char *path, struct sta *** 485,491 **** /* _truename() failed. (This really shouldn't happen, but who knows?) At least uppercase all letters, convert forward slashes to backward ones, and pray... */ ! register const char *src = path; register char *dst = canon_path; while ( (*dst = (*src > 'a' && *src < 'z' --- 493,499 ---- /* _truename() failed. (This really shouldn't happen, but who knows?) At least uppercase all letters, convert forward slashes to backward ones, and pray... */ ! register const char *src = pathname; register char *dst = canon_path; while ( (*dst = (*src > 'a' && *src < 'z' *************** stat_assist(const char *path, struct sta *** 501,507 **** } /* Call DOS FindFirst function, which will bring us most of the info. */ ! if (!__findfirst(path, &ff_blk, ALL_FILES)) { /* Time fields. */ dos_ftime = --- 509,515 ---- } /* Call DOS FindFirst function, which will bring us most of the info. */ ! if (!__findfirst(pathname, &ff_blk, ALL_FILES)) { /* Time fields. */ dos_ftime = *************** stat_assist(const char *path, struct sta *** 532,538 **** statbuf->st_ino = _invent_inode(canon_path, dos_ftime, ff_blk.ff_fsize); } ! else if (toupper (canon_path[0]) != toupper (path[0]) && canon_path[1] == ':' && canon_path[2] == '\\' && canon_path[3] == '\0') --- 540,546 ---- statbuf->st_ino = _invent_inode(canon_path, dos_ftime, ff_blk.ff_fsize); } ! else if (toupper (canon_path[0]) != toupper (pathname[0]) && canon_path[1] == ':' && canon_path[2] == '\\' && canon_path[3] == '\0') *************** stat_assist(const char *path, struct sta *** 569,575 **** first 2 bytes. */ if (extension) extension++; /* get past the dot */ ! if (_is_executable(path, -1, extension)) statbuf->st_mode |= EXEC_ACCESS; } } --- 577,583 ---- first 2 bytes. */ if (extension) extension++; /* get past the dot */ ! if (_is_executable(pathname, -1, extension)) statbuf->st_mode |= EXEC_ACCESS; } } *************** stat_assist(const char *path, struct sta *** 582,594 **** errno = ENODEV; return -1; } ! else if (path[3] == '\0') { /* Detect root directories. These are special because, unlike ! subdirectories, FindFirst fails for them. We look at PATH because a network redirector could tweak what `_truename' ! returns to be utterly unrecognizable as root directory. ! PATH always begins with "d:/", so it is root if PATH[3] = 0. */ /* Mode bits. */ statbuf->st_mode |= (S_IFDIR|READ_ACCESS|WRITE_ACCESS|EXEC_ACCESS); --- 590,602 ---- errno = ENODEV; return -1; } ! else if (pathname[3] == '\0') { /* Detect root directories. These are special because, unlike ! subdirectories, FindFirst fails for them. We look at PATHNAME because a network redirector could tweak what `_truename' ! returns to be utterly unrecognizable as root directory. PATHNAME ! always begins with "d:/", so it is root if PATHNAME[3] = 0. */ /* Mode bits. */ statbuf->st_mode |= (S_IFDIR|READ_ACCESS|WRITE_ACCESS|EXEC_ACCESS); *************** stat_assist(const char *path, struct sta *** 610,616 **** { char buf[7]; ! strcpy(buf, path); strcat(buf, "*.*"); if (!__findfirst(buf, &ff_blk, FA_LABEL)) dos_ftime = ( (unsigned)ff_blk.ff_fdate << 16 ) + ff_blk.ff_ftime; --- 618,624 ---- { char buf[7]; ! strcpy(buf, pathname); strcat(buf, "*.*"); if (!__findfirst(buf, &ff_blk, FA_LABEL)) dos_ftime = ( (unsigned)ff_blk.ff_fdate << 16 ) + ff_blk.ff_ftime; *************** stat_assist(const char *path, struct sta *** 621,649 **** else { int i = 0; ! int j = strlen (path) - 1; /* Check for volume labels. We did not mix FA_LABEL with other attributes in the call to `__findfirst' above, because some environments will return bogus info in that case. For instance, Win95 and WinNT seem to ! ignore `path' and return the volume label even if it ! doesn't fit the name in `path'. This fools us to think that a non-existent file exists and is a volume ! label. Hence we test the returned name to be PATH. */ ! if (!__findfirst(path, &ff_blk, FA_LABEL)) { i = strlen (ff_blk.ff_name) - 1; if (j >= i) { for ( ; i >= 0 && j >= 0; i--, j--) ! if (toupper (ff_blk.ff_name[i]) != toupper (path[j])) break; } } ! if (i < 0 && path[j] == '/') { /* Indeed a label. */ statbuf->st_mode = READ_ACCESS; --- 629,657 ---- else { int i = 0; ! int j = strlen (pathname) - 1; /* Check for volume labels. We did not mix FA_LABEL with other attributes in the call to `__findfirst' above, because some environments will return bogus info in that case. For instance, Win95 and WinNT seem to ! ignore `pathname' and return the volume label even if it ! doesn't fit the name in `pathname'. This fools us to think that a non-existent file exists and is a volume ! label. Hence we test the returned name to be PATHNAME. */ ! if (!__findfirst(pathname, &ff_blk, FA_LABEL)) { i = strlen (ff_blk.ff_name) - 1; if (j >= i) { for ( ; i >= 0 && j >= 0; i--, j--) ! if (toupper (ff_blk.ff_name[i]) != toupper (pathname[j])) break; } } ! if (i < 0 && pathname[j] == '/') { /* Indeed a label. */ statbuf->st_mode = READ_ACCESS; *************** stat_assist(const char *path, struct sta *** 712,725 **** even at performance cost, because it's more robust for networked drives. */ ! size_t pathlen = strlen (path); ! char lastc = path[pathlen - 1]; char *search_spec = (char *)alloca (pathlen + 10); /* need only +5 */ int nfiles = 0, nsubdirs = 0, done; size_t extra = 0; int add_extra = 0; ! strcpy(search_spec, path); if (lastc == '/') strcat(search_spec, "*.*"); else --- 720,733 ---- even at performance cost, because it's more robust for networked drives. */ ! size_t pathlen = strlen (pathname); ! char lastc = pathname[pathlen - 1]; char *search_spec = (char *)alloca (pathlen + 10); /* need only +5 */ int nfiles = 0, nsubdirs = 0, done; size_t extra = 0; int add_extra = 0; ! strcpy(search_spec, pathname); if (lastc == '/') strcat(search_spec, "*.*"); else *************** stat_assist(const char *path, struct sta *** 731,737 **** store the long filenames. */ char fstype[40]; ! if ((_get_volume_info(path, 0, 0, fstype) & _FILESYS_LFN_SUPPORTED) && strncmp(fstype, "FAT", 4) == 0) add_extra = 1; } --- 739,745 ---- store the long filenames. */ char fstype[40]; ! if ((_get_volume_info(pathname,0,0,fstype) & _FILESYS_LFN_SUPPORTED) && strncmp(fstype, "FAT", 4) == 0) add_extra = 1; } *************** int *** 777,783 **** stat(const char *path, struct stat *statbuf) { int e = errno; - char pathname[MAX_TRUE_NAME]; int pathlen; if (!path || !statbuf) --- 785,790 ---- *************** stat(const char *path, struct stat *stat *** 799,812 **** return -1; } ! /* Make the path explicit. This makes the rest of our job much ! easier by getting rid of some constructs which, if present, ! confuse `_truename' and/or `findfirst'. In particular, it ! deletes trailing slashes, makes "d:" explicit, and allows us ! to make an illusion of having a ".." entry in root directories. */ ! _fixpath (path, pathname); ! ! if (stat_assist(pathname, statbuf) == -1) { return -1; /* errno set by stat_assist() */ } --- 806,812 ---- return -1; } ! if (stat_assist(path, statbuf) == -1) { return -1; /* errno set by stat_assist() */ } *** src/libc/dos/dos/truename.c~0 Sun Sep 1 01:09:32 1996 --- src/libc/dos/dos/truename.c Sat Nov 2 15:14:40 1996 *************** _truename(const char *file, char *buf) *** 99,106 **** name_start[3] = '.'; name_start[4] = '\0'; } ! movedata(our_mem_selector, (unsigned int)name_start, ! dos_mem_selector, __tb, strlen(name_start) + 1); /* Call DOS INT 21H undocumented function 60h. */ if(use_lfn) { --- 99,105 ---- name_start[3] = '.'; name_start[4] = '\0'; } ! _put_path(name_start); /* Call DOS INT 21H undocumented function 60h. */ if(use_lfn) { *** src/libc/dos/io/putpath.c~0 Sat Nov 2 15:15:42 1996 --- src/libc/dos/io/putpath.c Sat Nov 2 15:28:32 1996 *************** *** 1,4 **** --- 1,5 ---- /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ + #include #include #include #include *************** void *** 16,21 **** --- 17,23 ---- _put_path2(const char *path, int offset) { int o, space = _go32_info_block.size_of_transfer_buffer - offset; + const char *p = path; if (path == 0) { *************** _put_path2(const char *path, int offset) *** 23,32 **** abort(); } ! if (strcmp(path, "/dev/null") == 0) path = "nul"; ! if (strcmp(path, "/dev/tty") == 0) path = "con"; _farsetsel(_dos_ds); --- 25,38 ---- abort(); } ! if (p[0] && p[1] == ':') ! p += 2; ! if (strcmp(p, "/dev/null") == 0) path = "nul"; ! else if (strcmp(p, "/dev/tty") == 0) path = "con"; + else if (strncmp(p, "/dev/", 5) == 0 && p[5] != 0) + path = p + 5; _farsetsel(_dos_ds);