2 * @(#)msd_dir.c 1.4 87/11/06 Public Domain.
4 * A public domain implementation of BSD directory routines for
5 * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
8 * Modified by Ian Stewartson, Data Logic (istewart@datlog.co.uk).
10 * Updates: 1. To support OS/2 1.x
11 * 2. To support HPFS long filenames
12 * 3. To support OS/2 2.x
13 * 4. To support TurboC
14 * 5. To support Windows NT
17 #include <sys/types.h>
31 #define WIN32_LEAN_AND_MEAN
34 #define FILE_NAME_E cFileName
35 #define OS_CloseFH(a) FindClose (a)
36 #define FIND_BUFFER WIN32_FIND_DATA
37 #define DISABLE_HARD_ERRORS SetErrorMode (0)
38 #define ENABLE_HARD_ERRORS SetErrorMode (SEM_FAILCRITICALERRORS | \
39 SEM_NOOPENFILEERRORBOX);
41 # define ERROR_EMPTY_DIR ERROR_FILE_NOT_FOUND
43 # define ATTRIBUTES (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \
44 _A_NORMAL | _A_RDONLY | _A_ARCH)
51 # define ENOTDIR 120 /* Not a directory */
55 # define S_IFMT 0xf000 /* type of file */
59 # define S_ISDIR(m) ((((m) & S_IFMT) == S_IFDIR))
66 typedef struct _dircontents DIRCONT;
67 static void free_dircontents (DIRCONT *);
70 * Open the directory stream
82 int len = strlen (name);
94 if ((nbuf = malloc (len + 5)) == (char *)NULL)
98 last = &nbuf[len - 1];
100 /* Ok, DOS is very picky about its directory names. The following are
107 * c:name/ is not valid
110 if (((*last == '\\') || (*last == '/')) && (len > 1) &&
111 (!((len == 3) && (name[1] == ':'))))
114 /* Check its a directory */
117 rc = stat (nbuf, &statb);
126 if (!S_ISDIR (statb.st_mode))
133 if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL)
139 /* Set up to find everything */
141 if ((*last != '\\') && (*last != '/'))
144 strcat (last, "*.*");
146 /* Find the file system type */
148 HPFS = IsHPFSFileSystem (nbuf);
151 dirp->dd_cp = (DIRCONT *) NULL;
152 dirp->dd_contents = (DIRCONT *) NULL;
156 d_handle = FindFirstFile (nbuf, &dtabuf);
157 rc = (d_handle == INVALID_HANDLE_VALUE) ? GetLastError () : 0;
161 /* Check for errors */
167 /* Empty directory */
169 #if defined (ERROR_EMPTY_DIR)
170 if (rc == ERROR_EMPTY_DIR)
178 /* Process the directory */
182 if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) ||
183 ((dp->_d_entry = strdup (dtabuf.FILE_NAME_E)) == (char *) NULL))
185 if (dp->_d_entry != (char *)NULL)
189 free_dircontents (dirp->dd_contents);
191 OS_CloseFH (d_handle);
196 strlwr (dp->_d_entry);
198 if (dirp->dd_contents != (DIRCONT *) NULL)
199 dirp->dd_cp = dirp->dd_cp->_d_next = dp;
202 dirp->dd_contents = dirp->dd_cp = dp;
204 dp->_d_next = (DIRCONT *) NULL;
206 } while (FindNextFile (d_handle, &dtabuf));
208 dirp->dd_cp = dirp->dd_contents;
211 OS_CloseFH (d_handle);
217 * Close the directory stream
224 if (dirp != (DIR *)NULL)
226 free_dircontents (dirp->dd_contents);
234 * Read the next record from the stream
241 static struct dirent dp;
243 if ((dirp == (DIR *)NULL) || (dirp->dd_cp == (DIRCONT *) NULL))
244 return (struct dirent *) NULL;
246 dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
247 dp.d_off = dirp->dd_loc * 32;
248 dp.d_ino = (ino_t)++dirp->dd_loc;
249 dirp->dd_cp = dirp->dd_cp->_d_next;
255 * Restart the directory stream
262 seekdir (dirp, (off_t)0);
266 * Move to a know position in the stream
277 if ((dirp == (DIR *)NULL) || (off < 0L))
280 for (dp = dirp->dd_contents; (--i >= 0) && (dp != (DIRCONT *)NULL);
284 dirp->dd_loc = off - (i + 1);
289 * Get the current position
296 return (dirp == (DIR *)NULL) ? (off_t) -1 : dirp->dd_loc;
300 * Release the internal structure
304 free_dircontents (dp)
309 while ((odp = dp) != (DIRCONT *)NULL)
311 if (dp->_d_entry != (char *)NULL)
325 IsHPFSFileSystem (directory)
333 char szCurDir [MAX_PATH];
335 if (isalpha (directory[0]) && (directory[1] == ':'))
336 nDrive = toupper (directory[0]) - '@';
340 GetCurrentDirectory (MAX_PATH, szCurDir);
341 nDrive = szCurDir[0] - 'A' + 1;
344 /* Set up the drive name */
346 strcpy (bName, "x:\\");
347 bName[0] = (char) (nDrive + '@');
349 /* Read the volume info, if we fail - assume non-HPFS */
353 rc = GetVolumeInformation (bName, (LPTSTR)NULL, 0, (LPDWORD)NULL,
354 &maxname, &flags, (LPTSTR)NULL, 0);
357 return ((rc) && (flags & (FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED)))