Date: Sun, 14 Sep 1997 20:02:14 +0300 (IDT) From: Eli Zaretskii To: DJ Delorie cc: djgpp-workers AT delorie DOT com Subject: mntent in 970831 Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Precedence: bulk A patch for `mntent' that clears some bugs which only show on NT: diff -c src/libc/compat/mntent/mntent.c~0 src/libc/compat/mntent/mntent.c *** src/libc/compat/mntent/mntent.c~0 Tue Aug 13 03:14:46 1996 --- src/libc/compat/mntent/mntent.c Sat Apr 12 12:21:06 1997 *************** *** 1,9 **** /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ /* * This is implementation of getmntent() and friends for DJGPP v2.x. * ! * Copyright (c) 1995-96 Eli Zaretskii * * This software may be used freely so long as this copyright notice is * left intact. There is no warranty on this software. --- 1,10 ---- + /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ /* * This is implementation of getmntent() and friends for DJGPP v2.x. * ! * Copyright (c) 1995-97 Eli Zaretskii * * This software may be used freely so long as this copyright notice is * left intact. There is no warranty on this software. *************** *** 41,47 **** #include #include #include ! #include /* Macro to convert a segment and an offset to a "far offset" suitable for _farxxx() functions of DJGPP. */ --- 42,48 ---- #include #include #include ! #include /* Macro to convert a segment and an offset to a "far offset" suitable for _farxxx() functions of DJGPP. */ *************** *** 114,121 **** our_mem_base, (unsigned int)currdir, 0x43); /* The drive attribute word is at the offset 43h, right after the ! current directory string. */ ! return _farpeekw(dos_mem_base, cds_entry_address + 0x43); } /* --- 115,123 ---- our_mem_base, (unsigned int)currdir, 0x43); /* The drive attribute word is at the offset 43h, right after the ! current directory string. NT doesn't support this. */ ! return ! cds_elsize == 0x47 ? 0 : _farpeekw(dos_mem_base, cds_entry_address + 0x43); } /* *************** *** 368,398 **** } /* ! * Return 1 if a CD-ROM drive DRIVE_NUM is ready, i.e. there is a ! * disk in the drive and that disk is a data (not AUDIO) disk. */ static int cdrom_drive_ready(int drive_num) { __dpmi_regs r; - int i = 2; ! /* Int 2Fh/AX=1505h (Read Volume Table Of Contents) will return ! with error for empty drives or if the disk is an AUDIO disk. */ ! r.x.es = __tb >> 4; ! r.x.bx = __tb & 15; ! r.x.cx = drive_num - 1; /* 0 = A: */ ! r.x.dx = 0; /* get the 1st descriptor (usually, the only one) */ ! ! /* First time after the door is closed the call might fail. ! Therefore try twice before giving up. */ ! do ! { ! r.x.ax = 0x1505; ! __dpmi_int(0x2f, &r); ! } while (--i && (r.x.flags & 1)); ! ! if ((r.x.flags & 1) == 0 && (r.x.ax == 0 || r.x.ax == 1)) return 1; return 0; } --- 370,428 ---- } /* ! * Return 1 if a CD-ROM drive DRIVE_NUM is ready, i.e. there ! * is a disk in the drive and the tray door is closed. */ static int cdrom_drive_ready(int drive_num) { __dpmi_regs r; ! /* We need to avoid reading any information off the CD-ROM, ! because then the driver will dupe MSCDEX into thinking the ! disk isn't ever changed, and DOS calls get stale info after ! you change the disk. (We cannot use DOS calls *before* this ! function, because QDPMI will crash the program if we issue ! a DOS call that hits the disk when the drive is empty or the ! disk is an audio disk.) ! ! So we use the Read Device Status command and look for the ! door open and drive empty bits (seems like door locked bit ! is not universally supported). This still leaves an unsolved ! problem: an audio disk will be reported as a ready drive, and ! under QDPMI will crash the program when we access the drive. ! I don't see any way out of this mess (anybody?). Well, at ! least with data disks we don't screw up DOS operations anymore. ! ! Gosh, why is it always so tricky with Microsoft software?? */ ! ! unsigned char request_header[0x14]; ! int status; ! unsigned dev_status; ! ! /* Construct the request header for the CD-ROM device driver. */ ! memset(request_header, 0, sizeof request_header); ! request_header[0] = sizeof request_header; ! request_header[2] = 3; /* IOCTL READ command */ ! *(unsigned short *)&request_header[0xe] = __tb_offset; ! *(unsigned short *)&request_header[0x10] = __tb_segment; ! request_header[0x12] = 5; /* number of bytes to transfer */ ! ! /* Put control block into the transfer buffer. */ ! _farpokeb(_dos_ds, __tb, 6); /* read device status */ ! _farpokel(_dos_ds, __tb + 1, 0); /* zero out the result field */ ! ! /* Put request header into the transfer buffer and call the driver. */ ! dosmemput(request_header, sizeof (request_header), __tb + 5); ! r.x.ax = 0x1510; ! r.x.cx = drive_num - 1; ! r.x.es = __tb_segment; ! r.x.bx = __tb_offset + 5; ! __dpmi_int(0x2f, &r); ! status = _farpeekw(_dos_ds, __tb + 5 + 3); ! dev_status = _farpeekl(_dos_ds, __tb + 1); ! if (status == 0x100 && _farpeekw (_dos_ds, __tb + 5 + 0x12) == 5 ! && (dev_status & 0x801) == 0) /* door open and drive empty bits */ return 1; return 0; } *************** *** 473,478 **** --- 503,513 ---- cds_address_offset = 0x17; cds_elsize = 0x51; } + else if (true_dos_version == 0x0332) /* NT */ + { + cds_address_offset = 0x16; + cds_elsize = 0x47; + } else { cds_address_offset = 0x16; *************** *** 597,609 **** These are used in the above order. */ /* See what 2160 can tell us. If it fails, there ain't no such ! drive, as far as DOS is concerned. */ truename_result = _truename(drive_string, mnt_fsname); /* Get some info from the DOS Current Directory Structure (CDS). ! We've already hit the disk with _truename(), so CDS now ! contains valid and up to date data. */ ! if (drive_number <= cds_drives) cds_flags = get_cds_entry(drive_number, cds_path); if (truename_result != NULL) --- 632,651 ---- These are used in the above order. */ /* See what 2160 can tell us. If it fails, there ain't no such ! drive, as far as DOS is concerned. Some DOS clones, like NT, ! don't always upcase the drive letter, so we must do that here. */ truename_result = _truename(drive_string, mnt_fsname); + if (truename_result && mnt_fsname[0] + && mnt_fsname[1] == ':' && islower(mnt_fsname[0])) + mnt_fsname[0] = toupper(mnt_fsname[0]); /* Get some info from the DOS Current Directory Structure (CDS). ! We've already hit the disk with _truename(), so CDS now ! contains valid and up to date data. Don't look at the CDS ! for remote drives: they can't be JOINed anyway, and some ! DOS clones, such as NT, don't put them into the CDS. */ ! if (drive_number <= cds_drives ! && !_is_remote_drive (drive_number - 1)) cds_flags = get_cds_entry(drive_number, cds_path); if (truename_result != NULL) *************** *** 631,644 **** if (is_ram_drive(drive_number)) mnt_type = NAME_ram; else if (is_cdrom_drive(drive_number)) ! { ! /* Empty CD-ROM drives do NOT fail _truename(), ! so we must see if there is a disk in the drive. */ ! if (cdrom_drive_ready(drive_number)) ! mnt_type = NAME_cdrom; ! else ! continue; /* don't report this drive */ ! } /* _is_remote_drive() needs zero-based disk number */ else if (_is_remote_drive(drive_number - 1) == 1) mnt_type = NAME_net; --- 673,686 ---- if (is_ram_drive(drive_number)) mnt_type = NAME_ram; else if (is_cdrom_drive(drive_number)) ! { ! /* Empty CD-ROM drives do NOT fail _truename(), ! so we must see if there is a disk in the drive. */ ! if (cdrom_drive_ready(drive_number)) ! mnt_type = NAME_cdrom; ! else ! continue; ! } /* _is_remote_drive() needs zero-based disk number */ else if (_is_remote_drive(drive_number - 1) == 1) mnt_type = NAME_net; *************** *** 696,706 **** /* Some network redirectors don't set a UNC path to be returned by _truename(). See if 215F02 can help. */ ! if ((!got_fsname || mnt_fsname[0] != '\\') && ! strcmp(mnt_type, "net") == 0) if (get_netredir_entry(drive_number)) got_fsname = 1; ! if (!got_fsname || strcmp(mnt_type, "cdrom") == 0) { /* Look for the volume label. */ int e = errno; --- 738,749 ---- /* Some network redirectors don't set a UNC path to be returned by _truename(). See if 215F02 can help. */ ! if ((!got_fsname || mnt_fsname[0] != '\\') && mnt_type == NAME_net) if (get_netredir_entry(drive_number)) got_fsname = 1; ! /* MSCDEX makes `_truename' return a dull "\\X.\A.", so ! try to get the label anyway. */ ! if (!got_fsname || mnt_type == NAME_cdrom) { /* Look for the volume label. */ int e = errno; *************** *** 724,732 **** got_fsname = 1; } ! else if (errno == ENMFILE || errno == ENOENT) { /* Valid drive, but no label. Construct default filesystem name. If drive A: is mapped to B:, call it ``Drive A:''. */ --- 767,795 ---- got_fsname = 1; } ! /* CD-ROM without a label is taken as an empty CD drive or an ! audio disk, and not reported. This is because MSCDEX doesn't ! fail `_truename' for these cases and some DOS clones, such as ! NT, don't even emulate the drive empty bit reliably. ! I have never seen a CD-ROM without a label. Anybody? */ ! else if (mnt_type == NAME_cdrom) ! got_fsname = 0; else if (errno == ENMFILE || errno == ENOENT) { + /* Some device drivers for removable media (like JAZ on NT DOS + box) pass all above tests when the drive is empty. Force + them to hit the disk with DOS Get Free Disk Space function, + and if that fails, treat that drive as non-existing. */ + if (mnt_type == NAME_fd) + { + __dpmi_regs r; + + r.h.ah = 0x36; + r.h.dl = drive_number; + __dpmi_int(0x21, &r); + if ( (r.x.ax & 0xffff) == 0xffff ) /* aha! an impostor! */ + continue; + } /* Valid drive, but no label. Construct default filesystem name. If drive A: is mapped to B:, call it ``Drive A:''. */ *************** *** 763,776 **** mntent.mnt_opts = dev_opts; /* Make CD-ROM drives read-only, others read-write. */ ! if (strcmp(mnt_type, "cdrom") == 0) dev_opts[1] = 'o'; else dev_opts[1] = 'w'; /* Include "dev=XX" in the mnt_opts field, where XX should be consistent with what stat() returns in st_dev. */ ! sprintf(xdrive, "%02x", strcmp(mnt_type, "subst") ? drive_number - 1 : mnt_fsname[0] - 'A'); dev_opts[7] = xdrive[0]; --- 826,839 ---- mntent.mnt_opts = dev_opts; /* Make CD-ROM drives read-only, others read-write. */ ! if (mnt_type == NAME_cdrom) dev_opts[1] = 'o'; else dev_opts[1] = 'w'; /* Include "dev=XX" in the mnt_opts field, where XX should be consistent with what stat() returns in st_dev. */ ! sprintf(xdrive, "%02x", mnt_type != NAME_subst ? drive_number - 1 : mnt_fsname[0] - 'A'); dev_opts[7] = xdrive[0];