Release 961215
[wine.git] / win32 / findfile.c
blob0c6618a907b564d16d7d98a30240f6ff78b688ab
1 #include <sys/types.h>
2 #include <dirent.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <malloc.h>
6 #include <errno.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include "xmalloc.h"
10 #include "windows.h"
11 #include "winerror.h"
12 #include "dos_fs.h"
13 #include "heap.h"
14 #include "string32.h"
15 #include "drive.h"
16 #include "stddebug.h"
17 #include "debug.h"
21 #define PATH_LEN 260
23 struct FindFileContext32 {
24 DIR * dir;
25 char mask[PATH_LEN];
26 char path[PATH_LEN];
27 char unixpath[PATH_LEN];
30 typedef struct FindFileContext32 FindFileContext32;
32 const char *DOSFS_Hash(const char *, int, int);
34 /* TODO/FIXME
35 * 1) Check volume information to see if long file names supported
36 * and do separate wildcard matching if so. Win95 has extended wildcard
37 * matching - It can have wildcards like '*foo*'. These can match both
38 * the long file name and the short file name.
39 * 2) These file functions may be called from an interrupt
40 * Interrupt 21h Function 714Eh FindFirstFile
41 * Interrupt 21h Function 714Fh FindNextFile
42 * Interrupt 21h Function 71A1h FindClose
45 static BOOL32 MatchWildCard(LPCSTR file, LPCSTR mask)
47 int len;
49 len = strlen(file);
51 if (strcmp(mask, "*.*") == 0)
52 return TRUE;
54 while (*file) {
55 if (*mask == '*') {
56 if (*(mask+1)) {
57 while (*file && (toupper(*file) != *(mask+1))) file++;
58 if (!*file)
59 return FALSE;
61 else
62 break;
64 else {
65 if (*mask != '?' && *mask != toupper(*file)) {
66 return FALSE;
68 file++;
70 mask++;
72 return (TRUE);
75 /* Functionality is same as GetFileInformationByHandle, but the structures
76 * it fills out are different. This needs to be kept the same as the above
77 * mentioned function.
81 static BOOL32 FINDFILE_GetFileInfo(const char *filename,
82 LPWIN32_FIND_DATA32A finfo)
84 struct stat file_stat;
86 if (stat(filename, &file_stat) == -1) {
87 SetLastError(ErrnoToLastError(errno));
88 return FALSE;
90 finfo->dwFileAttributes = 0;
91 if (file_stat.st_mode & S_IFREG)
92 finfo->dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
93 if (file_stat.st_mode & S_IFDIR)
94 finfo->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
95 if ((file_stat.st_mode & S_IRUSR) == 0)
96 finfo->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
98 /* Translate the file times. Use the last modification time
99 * for both the creation time and write time.
101 DOSFS_UnixTimeToFileTime(file_stat.st_mtime, &(finfo->ftCreationTime));
102 DOSFS_UnixTimeToFileTime(file_stat.st_mtime, &(finfo->ftLastWriteTime));
103 DOSFS_UnixTimeToFileTime(file_stat.st_atime, &(finfo->ftLastAccessTime));
105 finfo->nFileSizeLow = file_stat.st_size;
107 /* Zero out currently unused fields.
109 finfo->nFileSizeHigh = 0;
110 finfo->dwReserved0 = 0;
111 finfo->dwReserved1 = 0;
112 return TRUE;
117 /*************************************************************************
118 * FindNextFile32A (KERNEL32.126)
120 BOOL32 FindNextFile32A(HANDLE32 handle, LPWIN32_FIND_DATA32A data)
122 FindFileContext32 *context;
123 struct dirent *dirent;
124 char dosname[14];
125 char fullfilename[PATH_LEN];
127 memset(data, 0, sizeof(WIN32_FIND_DATA32A));
128 context = (FindFileContext32 *) handle;
130 while ((dirent = readdir(context->dir)) != NULL) {
131 if (strcmp(dirent->d_name, "..") == 0 ||
132 strcmp(dirent->d_name, ".") == 0)
133 continue;
135 lstrcpy32A(dosname, DOSFS_Hash(dirent->d_name, FALSE, FALSE));
137 if (MatchWildCard(dirent->d_name, context->mask)) {
138 /* fill in file information */
139 lstrcpy32A(fullfilename, context->unixpath);
140 if (context->unixpath[strlen(context->unixpath)-1] != '/')
141 strcat(fullfilename, "/");
142 strcat(fullfilename, dirent->d_name);
143 FINDFILE_GetFileInfo(fullfilename, data);
145 /* long file name */
146 lstrcpy32A(data->cFileName, dirent->d_name);
148 /* file name expressed in 8.3 format */
149 lstrcpy32A(data->cAlternateFileName, dosname);
151 dprintf_file(stddeb, "FindNextFile32A: %s (%s)\n",
152 data->cFileName, data->cAlternateFileName);
153 return (TRUE);
157 return (FALSE);
160 /*************************************************************************
161 * FindNextFile32W (KERNEL32.127)
163 BOOL32 FindNextFile32W(HANDLE32 handle, LPWIN32_FIND_DATA32W data)
165 WIN32_FIND_DATA32A adata;
166 BOOL32 res;
168 adata.dwFileAttributes = data->dwFileAttributes;
169 adata.ftCreationTime = data->ftCreationTime;
170 adata.ftLastAccessTime = data->ftLastAccessTime;
171 adata.ftLastWriteTime = data->ftLastWriteTime;
172 adata.nFileSizeHigh = data->nFileSizeHigh;
173 adata.nFileSizeLow = data->nFileSizeLow;
174 adata.dwReserved0 = data->dwReserved0;
175 adata.dwReserved1 = data->dwReserved1;
176 STRING32_UniToAnsi(adata.cFileName,data->cFileName);
177 STRING32_UniToAnsi(adata.cAlternateFileName,data->cAlternateFileName);
178 res=FindNextFile32A(handle,&adata);
179 if (res) {
180 data->dwFileAttributes = adata.dwFileAttributes;
181 data->ftCreationTime = adata.ftCreationTime;
182 data->ftLastAccessTime = adata.ftLastAccessTime;
183 data->ftLastWriteTime = adata.ftLastWriteTime;
184 data->nFileSizeHigh = adata.nFileSizeHigh;
185 data->nFileSizeLow = adata.nFileSizeLow;
186 data->dwReserved0 = adata.dwReserved0;
187 data->dwReserved1 = adata.dwReserved1;
188 STRING32_AnsiToUni(data->cFileName,adata.cFileName);
189 STRING32_AnsiToUni(data->cAlternateFileName,adata.cAlternateFileName);
191 return res;
194 /*************************************************************************
195 * FindFirstFile32A (KERNEL32.123)
198 HANDLE32 FindFirstFile32A(LPCSTR lpfilename_in,
199 LPWIN32_FIND_DATA32A lpFindFileData)
201 const char *unixpath;
202 char *slash, *p;
203 FindFileContext32 *context;
204 char lpfilename[PATH_LEN];
205 INT32 len;
207 context = HeapAlloc(SystemHeap, 0, sizeof(FindFileContext32));
208 if (!context)
209 return (INVALID_HANDLE_VALUE);
211 /* These type of cases
212 * A;\*.*
213 * A;stuff\*.*
214 * *.*
215 * \stuff\*.*
217 lstrcpy32A(lpfilename, lpfilename_in);
218 if (lpfilename[1] != ':' &&
219 lpfilename[0] != '\\') {
220 /* drive and root path are not set */
221 len = GetCurrentDirectory32A(PATH_LEN, lpfilename);
222 if (lpfilename[len-1] != '\\')
223 strcat(lpfilename, "\\");
224 strcat(lpfilename, lpfilename_in);
226 else if (lpfilename[1] != ':') {
227 /* drive not set, but path is rooted */
228 memmove(&lpfilename[2], lpfilename, strlen(lpfilename));
229 lpfilename[0] = DRIVE_GetCurrentDrive();
230 lpfilename[1] = ':';
232 else if (lpfilename[1] == ':' &&
233 lpfilename[2] != '\\') {
234 /* drive is set, but not root path */
235 lstrcpy32A(lpfilename, DRIVE_GetDosCwd(lpfilename[0]));
236 strcat(lpfilename, lpfilename_in);
239 dprintf_file(stddeb, "FindFirstFile32A: %s -> %s .\n",
240 lpfilename_in, lpfilename);
242 slash = strrchr(lpfilename, '\\');
244 if (slash) {
245 lstrcpyn32A(context->path, lpfilename, slash - lpfilename + 1);
246 context->path[slash - lpfilename + 1] = '\0';
247 unixpath = DOSFS_GetUnixFileName(context->path, FALSE);
248 if (!unixpath) {
249 /* FIXME: SetLastError(??) */
250 HeapFree(SystemHeap, 0, context);
251 return INVALID_HANDLE_VALUE;
253 lstrcpy32A(context->mask, slash+1);
255 else {
256 /* shouldn't really get here now */
257 context->path[0] = '\0';
258 unixpath = ".";
259 lstrcpy32A(context->mask, lpfilename);
262 lstrcpy32A(context->unixpath, unixpath);
263 context->dir = opendir(unixpath);
264 if (!context->dir) {
265 /* FIXME: SetLastError(??) */
266 HeapFree(SystemHeap, 0, context);
267 return INVALID_HANDLE_VALUE;
270 /* uppercase mask in place */
271 for (p = context->mask ; *p; p++)
272 *p = toupper(*p);
274 if (!FindNextFile32A((HANDLE32) context, lpFindFileData))
275 return (INVALID_HANDLE_VALUE);
276 return ((HANDLE32) context);
279 /*************************************************************************
280 * FindFirstFile32W (KERNEL32.124)
282 HANDLE32 FindFirstFile32W(LPCWSTR filename,LPWIN32_FIND_DATA32W data)
284 WIN32_FIND_DATA32A adata;
285 LPSTR afn = STRING32_DupUniToAnsi(filename);
286 HANDLE32 res;
288 res=FindFirstFile32A(afn,&adata);
289 if (res) {
290 data->dwFileAttributes = adata.dwFileAttributes;
291 data->ftCreationTime = adata.ftCreationTime;
292 data->ftLastAccessTime = adata.ftLastAccessTime;
293 data->ftLastWriteTime = adata.ftLastWriteTime;
294 data->nFileSizeHigh = adata.nFileSizeHigh;
295 data->nFileSizeLow = adata.nFileSizeLow;
296 data->dwReserved0 = adata.dwReserved0;
297 data->dwReserved1 = adata.dwReserved1;
298 STRING32_AnsiToUni(data->cFileName,adata.cFileName);
299 STRING32_AnsiToUni(data->cAlternateFileName,adata.cAlternateFileName);
301 free(afn);
302 return res;
305 /*************************************************************************
306 * FindClose32 (KERNEL32.119)
308 BOOL32 FindClose32(HANDLE32 handle)
310 FindFileContext32 *context;
312 /* Windows95 ignores an invalid handle. */
313 if (handle == INVALID_HANDLE_VALUE)
315 SetLastError(ERROR_INVALID_HANDLE);
316 return FALSE;
318 context = (FindFileContext32 *) handle;
319 if (context->dir)
320 closedir(context->dir);
321 HeapFree(SystemHeap, 0, context);
322 return (TRUE);
325 /* 16 bit versions of find functions */
326 /*************************************************************************
327 * FindFirstFile16 (KERNEL.413)
330 HANDLE16
331 FindFirstFile16(LPCSTR lpFileName, LPVOID lpdata)
333 WIN32_FIND_DATA32A *findData = (WIN32_FIND_DATA32A *) lpdata;
334 HANDLE32 h32;
335 HGLOBAL16 h16;
336 HANDLE32 *ptr;
338 /* get a handle to the real pointer */
341 h32 = FindFirstFile32A(lpFileName, findData);
342 if (h32 > 0) {
343 h16 = GlobalAlloc16(0, sizeof(h32));
344 ptr = GlobalLock16(h16);
345 *ptr = h32;
346 return (h16);
348 else
349 return ((HANDLE16) h32);
352 /*************************************************************************
353 * FindNextFile16 (KERNEL.414)
356 BOOL16
357 FindNextFile16(HANDLE16 handle, LPVOID lpdata)
359 WIN32_FIND_DATA32A *findData = (WIN32_FIND_DATA32A *) lpdata;
360 HANDLE32 *lph32;
362 lph32 = GlobalLock16(handle);
363 if (FindNextFile32A(*lph32, findData)) {
364 return TRUE;
366 else
367 return FALSE;
370 /*************************************************************************
371 * FindClose16 (KERNEL.415)
374 BOOL16
375 FindClose16(HANDLE16 handle)
377 HANDLE32 *lph32;
378 BOOL16 ret;
380 if (handle == (HANDLE16) INVALID_HANDLE_VALUE) {
381 SetLastError(ERROR_INVALID_HANDLE);
382 return FALSE;
385 lph32 = GlobalLock16(handle);
386 ret = FindClose32(*lph32);
387 GlobalFree16(handle);
388 return (ret);