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
)))