/****************************************************************/ /* */ /* fatdir.c */ /* DOS-C */ /* */ /* FAT File System dir Functions */ /* */ /* Copyright (c) 1995 */ /* Pasquale J. Villani */ /* All Rights Reserved */ /* */ /* This file is part of DOS-C. */ /* */ /* DOS-C is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version */ /* 2, or (at your option) any later version. */ /* */ /* DOS-C is distributed in the hope that it will be useful, but */ /* WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ /* the GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public */ /* License along with DOS-C; see the file COPYING. If not, */ /* write to the Free Software Foundation, 675 Mass Ave, */ /* Cambridge, MA 02139, USA. */ /****************************************************************/ #include "portab.h" #include "globals.h" #ifdef VERSION_STRINGS static BYTE *fatdirRcsId = "$Id$"; #endif /* * $Log$ * Revision 1.10 2001/03/19 04:50:56 bartoldeman * See history.txt for overview: put kernel 2022beo1 into CVS * * Revision 1.10 2001/03/08 21:00:00 bartoldeman * Fix handling of very long path names (Tom Ehlert) * * Revision 1.9 2000/08/06 05:50:17 jimtabor * Add new files and update cvs with patches and changes * * Revision 1.8 2000/06/21 18:16:46 jimtabor * Add UMB code, patch, and code fixes * * Revision 1.7 2000/06/01 06:46:57 jimtabor * Removed Debug printf * * Revision 1.6 2000/06/01 06:37:38 jimtabor * Read History for Changes * * Revision 1.5 2000/05/26 19:25:19 jimtabor * Read History file for Change info * * Revision 1.4 2000/05/25 20:56:21 jimtabor * Fixed project history * * Revision 1.3 2000/05/17 19:15:12 jimtabor * Cleanup, add and fix source. * * Revision 1.2 2000/05/08 04:30:00 jimtabor * Update CVS to 2020 * * Revision 1.1.1.1 2000/05/06 19:34:53 jhall1 * The FreeDOS Kernel. A DOS kernel that aims to be 100% compatible with * MS-DOS. Distributed under the GNU GPL. * * Revision 1.12 2000/03/31 05:40:09 jtabor * Added Eric W. Biederman Patches * * Revision 1.11 2000/03/17 22:59:04 kernel * Steffen Kaiser's NLS changes * * Revision 1.10 2000/03/09 06:07:11 kernel * 2017f updates by James Tabor * * Revision 1.9 1999/08/25 03:18:07 jprice * ror4 patches to allow TC 2.01 compile. * * Revision 1.8 1999/08/10 17:57:12 jprice * ror4 2011-02 patch * * Revision 1.7 1999/05/03 06:25:45 jprice * Patches from ror4 and many changed of signed to unsigned variables. * * Revision 1.6 1999/04/16 00:53:32 jprice * Optimized FAT handling * * Revision 1.5 1999/04/13 15:48:20 jprice * no message * * Revision 1.4 1999/04/11 04:33:38 jprice * ror4 patches * * Revision 1.2 1999/04/04 18:51:43 jprice * no message * * Revision 1.1.1.1 1999/03/29 15:41:58 jprice * New version without IPL.SYS * * Revision 1.7 1999/03/25 05:06:57 jprice * Fixed findfirst & findnext functions to treat the attributes like MSDOS does. * * Revision 1.6 1999/02/14 04:27:09 jprice * Changed check media so that it checks if a floppy disk has been changed. * * Revision 1.5 1999/02/09 02:54:23 jprice * Added Pat's 1937 kernel patches * * Revision 1.4 1999/02/01 01:43:28 jprice * Fixed findfirst function to find volume label with Windows long filenames * * Revision 1.3 1999/01/30 08:25:34 jprice * Clean up; Fixed bug with set attribute function. If you tried to * change the attributres of a directory, it would erase it. * * Revision 1.2 1999/01/22 04:15:28 jprice * Formating * * Revision 1.1.1.1 1999/01/20 05:51:00 jprice * Imported sources * * * Rev 1.10 06 Dec 1998 8:44:36 patv * Bug fixes. * * Rev 1.9 22 Jan 1998 4:09:00 patv * Fixed pointer problems affecting SDA * * Rev 1.8 04 Jan 1998 23:14:36 patv * Changed Log for strip utility * * Rev 1.7 03 Jan 1998 8:36:02 patv * Converted data area to SDA format * * Rev 1.6 16 Jan 1997 12:46:30 patv * pre-Release 0.92 feature additions * * Rev 1.5 29 May 1996 21:15:18 patv * bug fixes for v0.91a * * Rev 1.4 19 Feb 1996 3:20:12 patv * Added NLS, int2f and config.sys processing * * Rev 1.2 01 Sep 1995 17:48:38 patv * First GPL release. * * Rev 1.1 30 Jul 1995 20:50:24 patv * Eliminated version strings in ipl * * Rev 1.0 02 Jul 1995 8:04:34 patv * Initial revision. */ VOID pop_dmp(dmatch FAR *, struct f_node FAR *); struct f_node FAR *dir_open(BYTE FAR * dirname) { struct f_node FAR *fnp; COUNT drive; BYTE *p; WORD i, x; BYTE *s; struct cds FAR *cdsp; BYTE *pszPath = &TempCDS.cdsCurrentPath[2]; /* Allocate an fnode if possible - error return (0) if not. */ if ((fnp = get_f_node()) == (struct f_node FAR *)0) { return (struct f_node FAR *)NULL; } /* Force the fnode into read-write mode */ fnp->f_mode = RDWR; /* and initialize temporary CDS */ TempCDS.cdsFlags = 0; /* determine what drive we are using... */ dirname = adjust_far(dirname); if (ParseDosName(dirname, &drive, (BYTE *) 0, (BYTE *) 0, (BYTE *) 0, FALSE) != SUCCESS) { release_f_node(fnp); return NULL; } /* If the drive was specified, drive is non-negative and */ /* corresponds to the one passed in, i.e., 0 = A, 1 = B, etc. */ /* We use that and skip the "D:" part of the string. */ /* Otherwise, just use the default drive */ if (drive >= 0) { dirname += 2; /* Assume FAT style drive */ } else { drive = default_drive; } if (drive > (lastdrive-1)) { release_f_node(fnp); return NULL; } TempCDS.cdsDpb = CDSp->cds_table[drive].cdsDpb; cdsp = &CDSp->cds_table[drive]; TempCDS.cdsCurrentPath[0] = 'A' + drive; TempCDS.cdsCurrentPath[1] = ':'; TempCDS.cdsJoinOffset = 2; x = cdsp->cdsJoinOffset; /* Generate full path name */ ParseDosPath(dirname, (COUNT *) 0, pszPath, (BYTE FAR *) & cdsp->cdsCurrentPath[x]); /* for testing only for now */ #if 0 if ((cdsp->cdsFlags & CDSNETWDRV)) { printf("FailSafe %x \n", Int21AX); return fnp; } #endif if (TempCDS.cdsDpb == 0) { release_f_node(fnp); return NULL; } fnp->f_dpb = (struct dpb *)TempCDS.cdsDpb; /* Perform all directory common handling after all special */ /* handling has been performed. */ if (media_check((struct dpb *)TempCDS.cdsDpb) < 0) { release_f_node(fnp); return (struct f_node FAR *)0; } fnp->f_dsize = DIRENT_SIZE * TempCDS.cdsDpb->dpb_dirents; fnp->f_diroff = 0l; fnp->f_flags.f_dmod = FALSE; /* a brand new fnode */ fnp->f_flags.f_dnew = TRUE; fnp->f_flags.f_dremote = FALSE; fnp->f_dirstart = 0; /* Walk the directory tree to find the starting cluster */ /* */ /* Set the root flags since we always start from the root */ fnp->f_flags.f_droot = TRUE; for (p = pszPath; *p != '\0';) { /* skip all path seperators */ while (*p == '\\') ++p; /* don't continue if we're at the end */ if (*p == '\0') break; /* Convert the name into an absolute name for */ /* comparison... */ /* first the file name with trailing spaces... */ for (i = 0; i < FNAME_SIZE; i++) { if (*p != '\0' && *p != '.' && *p != '/' && *p != '\\') TempBuffer[i] = *p++; else break; } for (; i < FNAME_SIZE; i++) TempBuffer[i] = ' '; /* and the extension (don't forget to */ /* add trailing spaces)... */ if (*p == '.') ++p; for (i = 0; i < FEXT_SIZE; i++) { if (*p != '\0' && *p != '.' && *p != '/' && *p != '\\') TempBuffer[i + FNAME_SIZE] = *p++; else break; } for (; i < FEXT_SIZE; i++) TempBuffer[i + FNAME_SIZE] = ' '; /* Now search through the directory to */ /* find the entry... */ i = FALSE; DosUpFMem((BYTE FAR *) TempBuffer, FNAME_SIZE + FEXT_SIZE); while (dir_read(fnp) == DIRENT_SIZE) { if (fnp->f_dir.dir_name[0] != '\0' && fnp->f_dir.dir_name[0] != DELETED) { if (fcmp((BYTE FAR *) TempBuffer, (BYTE FAR *) fnp->f_dir.dir_name, FNAME_SIZE + FEXT_SIZE)) { i = TRUE; break; } } } if (!i || !(fnp->f_dir.dir_attrib & D_DIR)) { release_f_node(fnp); return (struct f_node FAR *)0; } else { /* make certain we've moved off */ /* root */ fnp->f_flags.f_droot = FALSE; fnp->f_flags.f_ddir = TRUE; /* set up for file read/write */ fnp->f_offset = 0l; fnp->f_cluster_offset = 0l; /*JPP */ fnp->f_highwater = 0l; fnp->f_cluster = fnp->f_dir.dir_start; fnp->f_dirstart = fnp->f_dir.dir_start; /* reset the directory flags */ fnp->f_diroff = 0l; fnp->f_flags.f_dmod = FALSE; fnp->f_flags.f_dnew = TRUE; fnp->f_dsize = DIRENT_SIZE * TempCDS.cdsDpb->dpb_dirents; } } return fnp; } COUNT dir_read(REG struct f_node FAR * fnp) { REG i; REG j; struct buffer FAR *bp; /* Directories need to point to their current offset, not for */ /* next op. Therefore, if it is anything other than the first */ /* directory entry, we will update the offset on entry rather */ /* than wait until exit. If it was new, clear the special new */ /* flag. */ if (fnp->f_flags.f_dnew) fnp->f_flags.f_dnew = FALSE; else fnp->f_diroff += DIRENT_SIZE; /* Determine if we hit the end of the directory. If we have, */ /* bump the offset back to the end and exit. If not, fill the */ /* dirent portion of the fnode, clear the f_dmod bit and leave, */ /* but only for root directories */ if (fnp->f_flags.f_droot && fnp->f_diroff >= fnp->f_dsize) { fnp->f_diroff -= DIRENT_SIZE; return 0; } else { if (fnp->f_flags.f_droot) { if ((fnp->f_diroff / fnp->f_dpb->dpb_secsize + fnp->f_dpb->dpb_dirstrt) >= fnp->f_dpb->dpb_data) { fnp->f_flags.f_dfull = TRUE; return 0; } bp = getblock((ULONG) (fnp->f_diroff / fnp->f_dpb->dpb_secsize + fnp->f_dpb->dpb_dirstrt), fnp->f_dpb->dpb_unit); bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR; #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } else { REG UWORD secsize = fnp->f_dpb->dpb_secsize; /* Do a "seek" to the directory position */ fnp->f_offset = fnp->f_diroff; /* Search through the FAT to find the block */ /* that this entry is in. */ #ifdef DISPLAY_GETBLOCK printf("dir_read: "); #endif if (map_cluster(fnp, XFR_READ) != SUCCESS) { fnp->f_flags.f_dfull = TRUE; return 0; } /* If the returned cluster is FREE, return zero */ /* bytes read. */ if (fnp->f_cluster == FREE) return 0; /* If the returned cluster is LAST_CLUSTER or */ /* LONG_LAST_CLUSTER, return zero bytes read */ /* and set the directory as full. */ if (last_link(fnp)) { fnp->f_diroff -= DIRENT_SIZE; fnp->f_flags.f_dfull = TRUE; return 0; } /* Compute the block within the cluster and the */ /* offset within the block. */ fnp->f_sector = (fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; fnp->f_boff = fnp->f_offset % secsize; /* Get the block we need from cache */ bp = getblock((ULONG) clus2phys(fnp->f_cluster, (fnp->f_dpb->dpb_clsmask + 1), fnp->f_dpb->dpb_data) + fnp->f_sector, fnp->f_dpb->dpb_unit); bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR; #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } /* Now that we have the block for our entry, get the */ /* directory entry. */ if (bp != NULL) getdirent((BYTE FAR *) & bp->b_buffer[fnp->f_diroff % fnp->f_dpb->dpb_secsize], (struct dirent FAR *)&fnp->f_dir); else { fnp->f_flags.f_dfull = TRUE; return 0; } /* Update the fnode's directory info */ fnp->f_flags.f_dfull = FALSE; fnp->f_flags.f_dmod = FALSE; /* and for efficiency, stop when we hit the first */ /* unused entry. */ if (fnp->f_dir.dir_name[0] == '\0') return 0; else return DIRENT_SIZE; } } #ifndef IPL COUNT dir_write(REG struct f_node FAR * fnp) { struct buffer FAR *bp; /* Update the entry if it was modified by a write or create... */ if (fnp->f_flags.f_dmod) { /* Root is a consecutive set of blocks, so handling is */ /* simple. */ if (fnp->f_flags.f_droot) { bp = getblock( (ULONG) (fnp->f_diroff / fnp->f_dpb->dpb_secsize + fnp->f_dpb->dpb_dirstrt), fnp->f_dpb->dpb_unit); bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR; #ifdef DISPLAY_GETBLOCK printf("DIR (dir_write)\n"); #endif } /* All other directories are just files. The only */ /* special handling is resetting the offset so that we */ /* can continually update the same directory entry. */ else { REG UWORD secsize = fnp->f_dpb->dpb_secsize; /* Do a "seek" to the directory position */ /* and convert the fnode to a directory fnode. */ fnp->f_offset = fnp->f_diroff; fnp->f_back = LONG_LAST_CLUSTER; fnp->f_cluster = fnp->f_dirstart; fnp->f_cluster_offset = 0l; /*JPP */ /* Search through the FAT to find the block */ /* that this entry is in. */ #ifdef DISPLAY_GETBLOCK printf("dir_write: "); #endif if (map_cluster(fnp, XFR_READ) != SUCCESS) { fnp->f_flags.f_dfull = TRUE; release_f_node(fnp); return 0; } /* If the returned cluster is FREE, return zero */ /* bytes read. */ if (fnp->f_cluster == FREE) { release_f_node(fnp); return 0; } /* Compute the block within the cluster and the */ /* offset within the block. */ fnp->f_sector = (fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; fnp->f_boff = fnp->f_offset % secsize; /* Get the block we need from cache */ bp = getblock((ULONG) clus2phys(fnp->f_cluster, (fnp->f_dpb->dpb_clsmask + 1), fnp->f_dpb->dpb_data) + fnp->f_sector, fnp->f_dpb->dpb_unit); bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR; #ifdef DISPLAY_GETBLOCK printf("DIR (dir_write)\n"); #endif } /* Now that we have a block, transfer the diectory */ /* entry into the block. */ if (bp == NULL) { release_f_node(fnp); return 0; } putdirent((struct dirent FAR *)&fnp->f_dir, (VOID FAR *) & bp->b_buffer[fnp->f_diroff % fnp->f_dpb->dpb_secsize]); bp->b_flag |= BFR_DIRTY; } return DIRENT_SIZE; } #endif VOID dir_close(REG struct f_node FAR * fnp) { REG COUNT disk = fnp->f_dpb->dpb_unit; /* Test for invalid f_nodes */ if (fnp == NULL) return; #ifndef IPL /* Write out the entry */ dir_write(fnp); #endif /* Clear buffers after release */ flush_buffers(disk); /* and release this instance of the fnode */ release_f_node(fnp); } #ifndef IPL COUNT dos_findfirst(UCOUNT attr, BYTE FAR * name) { REG struct f_node FAR *fnp; REG dmatch FAR *dmp = (dmatch FAR *) dta; REG COUNT i; COUNT nDrive; BYTE *p; BYTE FAR *ptr; static BYTE local_name[FNAME_SIZE + 1], local_ext[FEXT_SIZE + 1], Tname[65]; fsncopy(name, (BYTE FAR *)&Tname, sizeof(Tname)); Tname[sizeof(Tname)-1]=0; /* printf("ff %s", Tname); */ /* The findfirst/findnext calls are probably the worst of the */ /* DOS calls. They must work somewhat on the fly (i.e. - open */ /* but never close). Since we don't want to lose fnodes every */ /* time a directory is searched, we will initialize the DOS */ /* dirmatch structure and then for every find, we will open the */ /* current directory, do a seek and read, then close the fnode. */ /* Start out by initializing the dirmatch structure. */ dmp->dm_drive = default_drive ; dmp->dm_entry = 0; dmp->dm_cluster = 0; dmp->dm_attr_srch = attr | D_RDONLY | D_ARCHIVE; /* Parse out the drive, file name and file extension. */ i = ParseDosName((BYTE FAR *)&Tname, &nDrive, &LocalPath[2], local_name, local_ext, TRUE); if (i != SUCCESS) return i; /* printf("\nff %s", Tname); printf("ff %s", local_name); printf("ff %s\n", local_ext); */ if (nDrive >= 0) { dmp->dm_drive = nDrive ; } else nDrive = default_drive; if (nDrive > (lastdrive -1)) { return DE_INVLDDRV; } current_ldt = &CDSp->cds_table[nDrive]; SAttr = (BYTE) attr; /* Now build a directory. */ if (!LocalPath[2]) strcpy(&LocalPath[2], "."); /* Build the match pattern out of the passed string */ /* copy the part of the pattern which belongs to the filename and is fixed */ for (p = local_name, i = 0; i < FNAME_SIZE && *p && *p != '*'; ++p, ++i) SearchDir.dir_name[i] = *p; if (*p == '*') { for (; i < FNAME_SIZE; ++i) SearchDir.dir_name[i] = '?'; while (*++p) ; } else for (; i < FNAME_SIZE; i++) SearchDir.dir_name[i] = ' '; /* and the extension (don't forget to add trailing spaces)... */ for (p = local_ext, i = 0; i < FEXT_SIZE && *p && *p != '*'; ++p, ++i) SearchDir.dir_ext[i] = *p; if (*p == '*') { for (; i < FEXT_SIZE; ++i) SearchDir.dir_ext[i] = '?'; while (*++p) ; } else for (; i < FEXT_SIZE; i++) SearchDir.dir_ext[i] = ' '; /* Convert everything to uppercase. */ DosUpFMem(SearchDir.dir_name, FNAME_SIZE + FEXT_SIZE); /* Copy the raw pattern from our data segment to the DTA. */ fbcopy((BYTE FAR *) SearchDir.dir_name, dmp->dm_name_pat, FNAME_SIZE + FEXT_SIZE); if (current_ldt->cdsFlags & CDSNETWDRV) { if (Remote_find(REM_FINDFIRST, name, dmp) != 0) return DE_FILENOTFND; return SUCCESS; } /* /// Added code here to do matching against device names. DOS findfirst will match exact device names if the filename portion (excluding the extension) contains a valid device name. Credits: some of this code was ripped off from truename() in newstuff.c. - Ron Cemer */ if (!(attr & D_VOLID)) { char Name[FNAME_SIZE]; int d, wild = 0; for (d = 0; d < FNAME_SIZE; d++) { if ((Name[d] = SearchDir.dir_name[d]) == '?') { wild = 1; break; } } if (!wild) { struct dhdr FAR *dhp; for (dhp = (struct dhdr FAR *)&nul_dev; dhp != (struct dhdr FAR *)-1; dhp = dhp->dh_next) { if (fnmatch ((BYTE FAR *)&Name, (BYTE FAR *)dhp->dh_name, FNAME_SIZE, FALSE)) { /* Found a matching device. */ dmp->dm_entry = 0; dmp->dm_cluster = 0; dmp->dm_flags.f_dmod = 0; dmp->dm_flags.f_droot = 0; dmp->dm_flags.f_dnew = 0; dmp->dm_flags.f_ddir = 0; dmp->dm_flags.f_dfull = 0; dmp->dm_dirstart = 0; dmp->dm_attr_fnd = D_DEVICE; dmp->dm_time = dos_gettime(); dmp->dm_date = dos_getdate(); dmp->dm_size = 0L; for (d = 0; ( (d < FNAME_SIZE) && (Name[d] != ' ') ); d++) dmp->dm_name[d] = Name[d]; dmp->dm_name[d] = '\0'; return SUCCESS; } } } } /* /// End of additions. - Ron Cemer */ /* Now search through the directory to find the entry... */ /* Special handling - the volume id is only in the root */ /* directory and only searched for once. So we need to open */ /* the root and return only the first entry that contains the */ /* volume id bit set. */ if ((attr & ~(D_RDONLY | D_ARCHIVE)) == D_VOLID) { /* Now open this directory so that we can read the */ /* fnode entry and do a match on it. */ if ((fnp = dir_open((BYTE FAR *) "\\")) == NULL) return DE_PATHNOTFND; /* Now do the search */ while (dir_read(fnp) == DIRENT_SIZE) { /* Test the attribute and return first found */ if ((fnp->f_dir.dir_attrib & ~(D_RDONLY | D_ARCHIVE)) == D_VOLID) { pop_dmp(dmp, fnp); dir_close(fnp); return SUCCESS; } } /* Now that we've done our failed search, close it and */ /* return an error. */ dir_close(fnp); return DE_FILENOTFND; } /* Otherwise just do a normal find next */ else { /* Complete building the directory from the passed in */ /* name */ if (nDrive >= 0) LocalPath[0] = 'A' + nDrive; else LocalPath[0] = 'A' + default_drive; LocalPath[1] = ':'; /* Now open this directory so that we can read the */ /* fnode entry and do a match on it. */ if ((fnp = dir_open((BYTE FAR *) LocalPath)) == NULL) return DE_PATHNOTFND; pop_dmp(dmp, fnp); dmp->dm_entry = 0; if (!fnp->f_flags.f_droot) { dmp->dm_cluster = fnp->f_dirstart; dmp->dm_dirstart = fnp->f_dirstart; } else { dmp->dm_cluster = 0; dmp->dm_dirstart = 0; } dir_close(fnp); return dos_findnext(); } } COUNT dos_findnext(void) { REG dmatch FAR *dmp = (dmatch FAR *) dta; REG struct f_node FAR *fnp; BOOL found = FALSE; BYTE FAR *p; BYTE FAR *q; COUNT nDrive; /* assign our match parameters pointer. */ dmp = (dmatch FAR *) dta; /* /// findnext will always fail on a device name. - Ron Cemer */ if (dmp->dm_attr_fnd == D_DEVICE) return DE_FILENOTFND; /* * The new version of SHSUCDX 1.0 looks at the dm_drive byte to * test 40h. I used RamView to see location MSD 116:04be and * FD f??:04be, the byte set with 0xc4 = Remote/Network drive 4. * Ralf Brown docs for dos 4eh say bit 7 set == remote so what is * bit 6 for? SHSUCDX Mod info say "test redir not network bit". * Just to confuse the rest, MSCDEX sets bit 5 too. * * So, assume bit 6 is redirector and bit 7 is network. * jt */ nDrive = dmp->dm_drive & 0x1f; if (nDrive > (lastdrive -1)) { return DE_INVLDDRV; } current_ldt = &CDSp->cds_table[nDrive]; #if 0 printf("findnext: %c %s\n", nDrive + 'A', (cdsp->cdsFlags & CDSNETWDRV)?"remote":"local"); #endif if (current_ldt->cdsFlags & CDSNETWDRV) { if (Remote_find(REM_FINDNEXT, 0, dmp) != 0) return DE_FILENOTFND; return SUCCESS; } /* Allocate an fnode if possible - error return (0) if not. */ if ((fnp = get_f_node()) == (struct f_node FAR *)0) { return DE_FILENOTFND; } /* Force the fnode into read-write mode */ fnp->f_mode = RDWR; if (dmp->dm_drive > (lastdrive)) { return DE_INVLDDRV; } /* Select the default to help non-drive specified path */ /* searches... */ fnp->f_dpb = (struct dpb *)CDSp->cds_table[dmp->dm_drive].cdsDpb; if (media_check(fnp->f_dpb) < 0) { release_f_node(fnp); return DE_FILENOTFND; } fnp->f_dsize = DIRENT_SIZE * (fnp->f_dpb)->dpb_dirents; /* Search through the directory to find the entry, but do a */ /* seek first. */ if (dmp->dm_entry > 0) fnp->f_diroff = (dmp->dm_entry - 1) * DIRENT_SIZE; fnp->f_offset = fnp->f_highwater = fnp->f_diroff; fnp->f_cluster = dmp->dm_cluster; fnp->f_cluster_offset = 0l; /*JPP */ fnp->f_flags.f_dmod = dmp->dm_flags.f_dmod; fnp->f_flags.f_droot = dmp->dm_flags.f_droot; fnp->f_flags.f_dnew = dmp->dm_flags.f_dnew; fnp->f_flags.f_ddir = dmp->dm_flags.f_ddir; fnp->f_flags.f_dfull = dmp->dm_flags.f_dfull; fnp->f_dirstart = dmp->dm_dirstart; /* Loop through the directory */ while (dir_read(fnp) == DIRENT_SIZE) { ++dmp->dm_entry; if (fnp->f_dir.dir_name[0] != '\0' && fnp->f_dir.dir_name[0] != DELETED) { if (fcmp_wild((BYTE FAR *) (dmp->dm_name_pat), (BYTE FAR *) fnp->f_dir.dir_name, FNAME_SIZE + FEXT_SIZE)) { /* MSD Command.com uses FCB FN 11 & 12 with attrib set to 0x16. Bits 0x21 seem to get set some where in MSD so Rd and Arc files are returned. FD assumes the user knows what they need to see. */ /* Test the attribute as the final step */ if (!(~dmp->dm_attr_srch & fnp->f_dir.dir_attrib)) { found = TRUE; break; } else continue; } } } /* If found, transfer it to the dmatch structure */ if (found) pop_dmp(dmp, fnp); /* return the result */ release_f_node(fnp); return found ? SUCCESS : DE_FILENOTFND; } static VOID pop_dmp(dmatch FAR * dmp, struct f_node FAR * fnp) { COUNT idx; BYTE FAR *p; BYTE FAR *q; dmp->dm_attr_fnd = fnp->f_dir.dir_attrib; dmp->dm_time = fnp->f_dir.dir_time; dmp->dm_date = fnp->f_dir.dir_date; dmp->dm_size = fnp->f_dir.dir_size; /* dmp -> dm_cluster = fnp -> f_cluster; /* */ dmp->dm_flags.f_droot = fnp->f_flags.f_droot; dmp->dm_flags.f_ddir = fnp->f_flags.f_ddir; dmp->dm_flags.f_dmod = fnp->f_flags.f_dmod; dmp->dm_flags.f_dnew = fnp->f_flags.f_dnew; p = dmp->dm_name; if (fnp->f_dir.dir_name[0] == '.') { for (idx = 0, q = (BYTE FAR *) fnp->f_dir.dir_name; idx < FNAME_SIZE; idx++) { if (*q == ' ') break; *p++ = *q++; } } else { for (idx = 0, q = (BYTE FAR *) fnp->f_dir.dir_name; idx < FNAME_SIZE; idx++) { if (*q == ' ') break; *p++ = *q++; } if (fnp->f_dir.dir_ext[0] != ' ') { *p++ = '.'; for (idx = 0, q = (BYTE FAR *) fnp->f_dir.dir_ext; idx < FEXT_SIZE; idx++) { if (*q == ' ') break; *p++ = *q++; } } } *p++ = NULL; } #endif