/* * @(#)msd_dir.c 1.4 87/11/06 Public Domain. * * A public domain implementation of BSD directory routines for * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield), * August 1897 * * Modified by Ian Stewartson, Data Logic. */ #include #include #include #include #include #include #include #include #include #include #ifdef OS2 #define INCL_DOSFILEMGR #include #else #include #endif #ifdef OS2 # define ATTRIBUTES (FILE_DIRECTORY | FILE_HIDDEN | FILE_SYSTEM | \ FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED) #else # define ATTRIBUTES (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \ _A_NORMAL | _A_RDONLY | _A_ARCH) #endif typedef struct _dircontents DIRCONT; static void free_dircontents (DIRCONT *); DIR *opendir (name) const char *name; { struct stat statb; DIR *dirp; char *last; DIRCONT *dp; char *nbuf; #ifdef OS2 FILEFINDBUF dtabuf; HDIR d_handle = HDIR_SYSTEM; USHORT d_count = 1; bool HPFS = FALSE; #else struct find_t dtabuf; #endif int len = strlen (name); if (!len) { errno = ENOTDIR; return (DIR *)NULL; } if ((nbuf = malloc (len + 5)) == (char *)NULL) return (DIR *) NULL; strcpy (nbuf, name); last = &nbuf[len - 1]; /* Ok, DOS is very picky about its directory names. The following are * valid. * * c:/ * c:. * c:name/name1 * * c:name/ is not valid */ if (((*last == '\\') || (*last == '/')) && (len > 1) && (!((len == 3) && (name[1] == ':')))) *(last--) = 0; /* Check its a directory */ if (stat (nbuf, &statb) < 0) { free (nbuf); return (DIR *) NULL; } if (!S_ISDIR (statb.st_mode)) { free (nbuf); errno = ENOTDIR; return (DIR *)NULL; } if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL) { free (nbuf); return (DIR *) NULL; } /* Set up to find everything */ if ((*last != '\\') && (*last != '/')) strcat (last, "/"); strcat (last, "*.*"); /* For OS/2, find the file system type */ #ifdef OS2 HPFS = IsHPFSFileSystem (nbuf); #endif dirp->dd_loc = 0; dirp->dd_cp = (DIRCONT *) NULL; dirp->dd_contents = (DIRCONT *) NULL; #ifdef OS2 if (DosFindFirst (nbuf, &d_handle, ATTRIBUTES, &dtabuf, sizeof (FILEFINDBUF), &d_count, (ULONG)0) != 0) #else if (_dos_findfirst (nbuf, ATTRIBUTES, &dtabuf) != 0) #endif { free (nbuf); return dirp; } do { #ifdef OS2 if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) || ((dp->_d_entry = strdup (dtabuf.achName)) == (char *) NULL)) #else if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) || ((dp->_d_entry = strdup (dtabuf.name)) == (char *) NULL)) #endif { if (dp != (char *)NULL) free ((char *)dp); free (nbuf); free_dircontents (dirp->dd_contents); #ifdef OS2 DosFindClose (d_handle); #endif return (DIR *) NULL; } #ifdef OS2 if (!HPFS) strlwr (dp->_d_entry); #endif if (dirp->dd_contents != (DIRCONT *) NULL) dirp->dd_cp = dirp->dd_cp->_d_next = dp; else dirp->dd_contents = dirp->dd_cp = dp; dp->_d_next = (DIRCONT *) NULL; #ifdef OS2 d_count = 1; } while (DosFindNext (d_handle, &dtabuf, sizeof (FILEFINDBUF), &d_count) == 0); #else } while (_dos_findnext (&dtabuf) == 0); #endif dirp->dd_cp = dirp->dd_contents; free (nbuf); #ifdef OS2 DosFindClose (d_handle); #endif return dirp; } int closedir (dirp) DIR *dirp; { free_dircontents (dirp->dd_contents); free ((char *)dirp); return 0; } struct dirent *readdir (dirp) DIR *dirp; { static struct dirent dp; if (dirp->dd_cp == (DIRCONT *) NULL) return (struct dirent *) NULL; dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry)); dp.d_off = dirp->dd_loc * 32; dp.d_ino = (ino_t)++dirp->dd_loc; dirp->dd_cp = dirp->dd_cp->_d_next; #ifndef OS2 strlwr (dp.d_name); #endif return &dp; } void rewinddir (dirp) DIR *dirp; { seekdir (dirp, (off_t)0); } void seekdir (dirp, off) DIR *dirp; off_t off; { long i = off; DIRCONT *dp; if (off < 0L) return; for (dp = dirp->dd_contents; (--i >= 0) && (dp != (DIRCONT *)NULL); dp = dp->_d_next) ; dirp->dd_loc = off - (i + 1); dirp->dd_cp = dp; } off_t telldir(dirp) DIR *dirp; { return dirp->dd_loc; } static void free_dircontents (dp) DIRCONT *dp; { DIRCONT *odp; while ((odp = dp) != (DIRCONT *)NULL) { if (dp->_d_entry != (char *)NULL) free (dp->_d_entry); dp = dp->_d_next; free ((char *)odp); } } /* * For OS/2, we need to know if we have to convert to lower case. This * only applies to non-HPFS (FAT, NETWARE etc) file systems. */ #ifdef OS2 bool IsHPFSFileSystem (char *directory) { USHORT nDrive; ULONG lMap; BYTE bData[64]; BYTE bName[3]; USHORT cbData; if ( _osmode == DOS_MODE ) return FALSE; /* * Mike tells me there are IFS calls to determine this, but he carn't * remember which. So we read the partition info and check for HPFS. */ if (isalpha (directory[0]) && (directory[1] == ':')) nDrive = toupper (directory[0]) - '@'; else DosQCurDisk (&nDrive, &lMap); /* Set up the drive name */ bName[0] = (char) (nDrive + '@'); bName[1] = ':'; bName[2] = 0; cbData = sizeof (bData); /* Read the info, if we fail - assume non-HPFS */ if (DosQFSAttach (bName, 0, FSAIL_QUERYNAME, bData, &cbData, 0L) ) return FALSE; else if (!strcmp (bData + (*((USHORT *) (bData + 2)) + 7), "HPFS")) return TRUE; else return FALSE; } #endif