|
|
1.1 root 1: /*
2: * @(#)msd_dir.c 1.4 87/11/06 Public Domain.
3: *
4: * A public domain implementation of BSD directory routines for
5: * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
6: * August 1897
7: *
8: * Modified by Ian Stewartson, Data Logic ([email protected]).
9: *
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
15: */
16:
17: #include <sys/types.h>
18: #include <sys/stat.h>
19: #include <stdio.h>
20: #include <stdlib.h>
21:
22: #include <malloc.h>
23:
24: #include <string.h>
25: #include <limits.h>
26: #include <ctype.h>
27: #include <errno.h>
28: #include <dirent.h>
29:
30:
31: #define WIN32_LEAN_AND_MEAN
32: #include <windows.h>
33:
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);
40:
41: # define ERROR_EMPTY_DIR ERROR_FILE_NOT_FOUND
42:
43: # define ATTRIBUTES (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \
44: _A_NORMAL | _A_RDONLY | _A_ARCH)
45:
46: /*
47: * missing ??
48: */
49:
50: #ifndef ENOTDIR
51: # define ENOTDIR 120 /* Not a directory */
52: #endif
53:
54: #ifndef S_IFMT
55: # define S_IFMT 0xf000 /* type of file */
56: #endif
57:
58: #ifndef S_ISDIR
59: # define S_ISDIR(m) ((((m) & S_IFMT) == S_IFDIR))
60: #endif
61:
62: /*
63: * Internals
64: */
65:
66: typedef struct _dircontents DIRCONT;
67: static void free_dircontents (DIRCONT *);
68:
69: /*
70: * Open the directory stream
71: */
72:
73: DIR *
74: opendir (name)
75: const char *name;
76: {
77: struct stat statb;
78: DIR *dirp;
79: char *last;
80: DIRCONT *dp;
81: char *nbuf;
82: int len = strlen (name);
83: unsigned long rc;
84: FIND_BUFFER dtabuf;
85: HANDLE d_handle;
86: bool HPFS = FALSE;
87:
88: if (!len)
89: {
90: errno = ENOTDIR;
91: return (DIR *)NULL;
92: }
93:
94: if ((nbuf = malloc (len + 5)) == (char *)NULL)
95: return (DIR *) NULL;
96:
97: strcpy (nbuf, name);
98: last = &nbuf[len - 1];
99:
100: /* Ok, DOS is very picky about its directory names. The following are
101: * valid.
102: *
103: * c:/
104: * c:.
105: * c:name/name1
106: *
107: * c:name/ is not valid
108: */
109:
110: if (((*last == '\\') || (*last == '/')) && (len > 1) &&
111: (!((len == 3) && (name[1] == ':'))))
112: *(last--) = 0;
113:
114: /* Check its a directory */
115:
116: DISABLE_HARD_ERRORS;
117: rc = stat (nbuf, &statb);
118: ENABLE_HARD_ERRORS;
119:
120: if (rc)
121: {
122: free (nbuf);
123: return (DIR *) NULL;
124: }
125:
126: if (!S_ISDIR (statb.st_mode))
127: {
128: free (nbuf);
129: errno = ENOTDIR;
130: return (DIR *)NULL;
131: }
132:
133: if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL)
134: {
135: free (nbuf);
136: return (DIR *) NULL;
137: }
138:
139: /* Set up to find everything */
140:
141: if ((*last != '\\') && (*last != '/'))
142: strcat (last, "/");
143:
144: strcat (last, "*.*");
145:
146: /* Find the file system type */
147:
148: HPFS = IsHPFSFileSystem (nbuf);
149:
150: dirp->dd_loc = 0;
151: dirp->dd_cp = (DIRCONT *) NULL;
152: dirp->dd_contents = (DIRCONT *) NULL;
153:
154: DISABLE_HARD_ERRORS;
155:
156: d_handle = FindFirstFile (nbuf, &dtabuf);
157: rc = (d_handle == INVALID_HANDLE_VALUE) ? GetLastError () : 0;
158:
159: ENABLE_HARD_ERRORS;
160:
161: /* Check for errors */
162:
163: if (rc)
164: {
165: free (nbuf);
166:
167: /* Empty directory */
168:
169: #if defined (ERROR_EMPTY_DIR)
170: if (rc == ERROR_EMPTY_DIR)
171: return dirp;
172: #endif
173:
174: free (dirp);
175: return (DIR *) NULL;
176: }
177:
178: /* Process the directory */
179:
180: do
181: {
182: if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) ||
183: ((dp->_d_entry = strdup (dtabuf.FILE_NAME_E)) == (char *) NULL))
184: {
185: if (dp->_d_entry != (char *)NULL)
186: free ((char *)dp);
187:
188: free (nbuf);
189: free_dircontents (dirp->dd_contents);
190:
191: OS_CloseFH (d_handle);
192: return (DIR *) NULL;
193: }
194:
195: if (!HPFS)
196: strlwr (dp->_d_entry);
197:
198: if (dirp->dd_contents != (DIRCONT *) NULL)
199: dirp->dd_cp = dirp->dd_cp->_d_next = dp;
200:
201: else
202: dirp->dd_contents = dirp->dd_cp = dp;
203:
204: dp->_d_next = (DIRCONT *) NULL;
205:
206: } while (FindNextFile (d_handle, &dtabuf));
207:
208: dirp->dd_cp = dirp->dd_contents;
209: free (nbuf);
210:
211: OS_CloseFH (d_handle);
212: return dirp;
213: }
214:
215:
216: /*
217: * Close the directory stream
218: */
219:
220: int
221: closedir (dirp)
222: DIR *dirp;
223: {
224: if (dirp != (DIR *)NULL)
225: {
226: free_dircontents (dirp->dd_contents);
227: free ((char *)dirp);
228: }
229:
230: return 0;
231: }
232:
233: /*
234: * Read the next record from the stream
235: */
236:
237: struct dirent *
238: readdir (dirp)
239: DIR *dirp;
240: {
241: static struct dirent dp;
242:
243: if ((dirp == (DIR *)NULL) || (dirp->dd_cp == (DIRCONT *) NULL))
244: return (struct dirent *) NULL;
245:
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;
250:
251: return &dp;
252: }
253:
254: /*
255: * Restart the directory stream
256: */
257:
258: void
259: rewinddir (dirp)
260: DIR *dirp;
261: {
262: seekdir (dirp, (off_t)0);
263: }
264:
265: /*
266: * Move to a know position in the stream
267: */
268:
269: void
270: seekdir (dirp, off)
271: DIR *dirp;
272: off_t off;
273: {
274: long i = off;
275: DIRCONT *dp;
276:
277: if ((dirp == (DIR *)NULL) || (off < 0L))
278: return;
279:
280: for (dp = dirp->dd_contents; (--i >= 0) && (dp != (DIRCONT *)NULL);
281: dp = dp->_d_next)
282: ;
283:
284: dirp->dd_loc = off - (i + 1);
285: dirp->dd_cp = dp;
286: }
287:
288: /*
289: * Get the current position
290: */
291:
292: off_t
293: telldir(dirp)
294: DIR *dirp;
295: {
296: return (dirp == (DIR *)NULL) ? (off_t) -1 : dirp->dd_loc;
297: }
298:
299: /*
300: * Release the internal structure
301: */
302:
303: static void
304: free_dircontents (dp)
305: DIRCONT *dp;
306: {
307: DIRCONT *odp;
308:
309: while ((odp = dp) != (DIRCONT *)NULL)
310: {
311: if (dp->_d_entry != (char *)NULL)
312: free (dp->_d_entry);
313:
314: dp = dp->_d_next;
315: free ((char *)odp);
316: }
317: }
318:
319:
320: /*
321: * Windows NT version
322: */
323:
324: bool
325: IsHPFSFileSystem (directory)
326: char *directory;
327: {
328: char bName[4];
329: DWORD flags;
330: DWORD maxname;
331: BOOL rc;
332: unsigned int nDrive;
333: char szCurDir [MAX_PATH];
334:
335: if (isalpha (directory[0]) && (directory[1] == ':'))
336: nDrive = toupper (directory[0]) - '@';
337:
338: else
339: {
340: GetCurrentDirectory (MAX_PATH, szCurDir);
341: nDrive = szCurDir[0] - 'A' + 1;
342: }
343:
344: /* Set up the drive name */
345:
346: strcpy (bName, "x:\\");
347: bName[0] = (char) (nDrive + '@');
348:
349: /* Read the volume info, if we fail - assume non-HPFS */
350:
351: DISABLE_HARD_ERRORS;
352:
353: rc = GetVolumeInformation (bName, (LPTSTR)NULL, 0, (LPDWORD)NULL,
354: &maxname, &flags, (LPTSTR)NULL, 0);
355: ENABLE_HARD_ERRORS;
356:
357: return ((rc) && (flags & (FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED)))
358: ? TRUE : FALSE;
359: }
360:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.