Release 961222
[wine/multimedia.git] / win32 / findfile.c
blob799e5e178aaf8c7fcfa02606aaa317411fe5e2d5
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 "drive.h"
15 #include "stddebug.h"
16 #include "debug.h"
20 #define PATH_LEN 260
22 struct FindFileContext32 {
23 DIR * dir;
24 char mask[PATH_LEN];
25 char path[PATH_LEN];
26 char unixpath[PATH_LEN];
29 typedef struct FindFileContext32 FindFileContext32;
31 const char *DOSFS_Hash(const char *, int, int);
33 /* TODO/FIXME
34 * 1) Check volume information to see if long file names supported
35 * and do separate wildcard matching if so. Win95 has extended wildcard
36 * matching - It can have wildcards like '*foo*'. These can match both
37 * the long file name and the short file name.
38 * 2) These file functions may be called from an interrupt
39 * Interrupt 21h Function 714Eh FindFirstFile
40 * Interrupt 21h Function 714Fh FindNextFile
41 * Interrupt 21h Function 71A1h FindClose
44 static BOOL32 MatchWildCard(LPCSTR file, LPCSTR mask)
46 int len;
48 len = strlen(file);
50 if (strcmp(mask, "*.*") == 0)
51 return TRUE;
53 while (*file) {
54 if (*mask == '*') {
55 if (*(mask+1)) {
56 while (*file && (toupper(*file) != *(mask+1))) file++;
57 if (!*file)
58 return FALSE;
60 else
61 break;
63 else {
64 if (*mask != '?' && *mask != toupper(*file)) {
65 return FALSE;
67 file++;
69 mask++;
71 return (TRUE);
74 /* Functionality is same as GetFileInformationByHandle, but the structures
75 * it fills out are different. This needs to be kept the same as the above
76 * mentioned function.
80 static BOOL32 FINDFILE_GetFileInfo(const char *filename,
81 LPWIN32_FIND_DATA32A finfo)
83 struct stat file_stat;
85 if (stat(filename, &file_stat) == -1) {
86 SetLastError(ErrnoToLastError(errno));
87 return FALSE;
89 finfo->dwFileAttributes = 0;
90 if (file_stat.st_mode & S_IFREG)
91 finfo->dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
92 if (file_stat.st_mode & S_IFDIR)
93 finfo->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
94 if ((file_stat.st_mode & S_IRUSR) == 0)
95 finfo->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
97 /* Translate the file times. Use the last modification time
98 * for both the creation time and write time.
100 DOSFS_UnixTimeToFileTime(file_stat.st_mtime, &(finfo->ftCreationTime));
101 DOSFS_UnixTimeToFileTime(file_stat.st_mtime, &(finfo->ftLastWriteTime));
102 DOSFS_UnixTimeToFileTime(file_stat.st_atime, &(finfo->ftLastAccessTime));
104 finfo->nFileSizeLow = file_stat.st_size;
106 /* Zero out currently unused fields.
108 finfo->nFileSizeHigh = 0;
109 finfo->dwReserved0 = 0;
110 finfo->dwReserved1 = 0;
111 return TRUE;
116 /*************************************************************************
117 * FindNextFile32A (KERNEL32.126)
119 BOOL32 FindNextFile32A(HANDLE32 handle, LPWIN32_FIND_DATA32A data)
121 FindFileContext32 *context;
122 struct dirent *dirent;
123 char dosname[14];
124 char fullfilename[PATH_LEN];
126 memset(data, 0, sizeof(WIN32_FIND_DATA32A));
127 context = (FindFileContext32 *) handle;
129 while ((dirent = readdir(context->dir)) != NULL) {
130 if (strcmp(dirent->d_name, "..") == 0 ||
131 strcmp(dirent->d_name, ".") == 0)
132 continue;
134 lstrcpy32A(dosname, DOSFS_Hash(dirent->d_name, FALSE, FALSE));
136 if (MatchWildCard(dirent->d_name, context->mask)) {
137 /* fill in file information */
138 lstrcpy32A(fullfilename, context->unixpath);
139 if (context->unixpath[strlen(context->unixpath)-1] != '/')
140 strcat(fullfilename, "/");
141 strcat(fullfilename, dirent->d_name);
142 FINDFILE_GetFileInfo(fullfilename, data);
144 /* long file name */
145 lstrcpy32A(data->cFileName, dirent->d_name);
147 /* file name expressed in 8.3 format */
148 lstrcpy32A(data->cAlternateFileName, dosname);
150 dprintf_file(stddeb, "FindNextFile32A: %s (%s)\n",
151 data->cFileName, data->cAlternateFileName);
152 return (TRUE);
156 return (FALSE);
159 /*************************************************************************
160 * FindNextFile32W (KERNEL32.127)
162 BOOL32 FindNextFile32W(HANDLE32 handle, LPWIN32_FIND_DATA32W data)
164 WIN32_FIND_DATA32A adata;
165 BOOL32 res;
167 adata.dwFileAttributes = data->dwFileAttributes;
168 adata.ftCreationTime = data->ftCreationTime;
169 adata.ftLastAccessTime = data->ftLastAccessTime;
170 adata.ftLastWriteTime = data->ftLastWriteTime;
171 adata.nFileSizeHigh = data->nFileSizeHigh;
172 adata.nFileSizeLow = data->nFileSizeLow;
173 adata.dwReserved0 = data->dwReserved0;
174 adata.dwReserved1 = data->dwReserved1;
175 lstrcpyWtoA(adata.cFileName,data->cFileName);
176 lstrcpyWtoA(adata.cAlternateFileName,data->cAlternateFileName);
177 res=FindNextFile32A(handle,&adata);
178 if (res) {
179 data->dwFileAttributes = adata.dwFileAttributes;
180 data->ftCreationTime = adata.ftCreationTime;
181 data->ftLastAccessTime = adata.ftLastAccessTime;
182 data->ftLastWriteTime = adata.ftLastWriteTime;
183 data->nFileSizeHigh = adata.nFileSizeHigh;
184 data->nFileSizeLow = adata.nFileSizeLow;
185 data->dwReserved0 = adata.dwReserved0;
186 data->dwReserved1 = adata.dwReserved1;
187 lstrcpyAtoW(data->cFileName,adata.cFileName);
188 lstrcpyAtoW(data->cAlternateFileName,adata.cAlternateFileName);
190 return res;
193 /*************************************************************************
194 * FindFirstFile32A (KERNEL32.123)
197 HANDLE32 FindFirstFile32A(LPCSTR lpfilename_in,
198 LPWIN32_FIND_DATA32A lpFindFileData)
200 const char *unixpath;
201 char *slash, *p;
202 FindFileContext32 *context;
203 char lpfilename[PATH_LEN];
204 INT32 len;
206 context = HeapAlloc(SystemHeap, 0, sizeof(FindFileContext32));
207 if (!context)
208 return (INVALID_HANDLE_VALUE);
210 /* These type of cases
211 * A;\*.*
212 * A;stuff\*.*
213 * *.*
214 * \stuff\*.*
216 lstrcpy32A(lpfilename, lpfilename_in);
217 if (lpfilename[1] != ':' &&
218 lpfilename[0] != '\\') {
219 /* drive and root path are not set */
220 len = GetCurrentDirectory32A(PATH_LEN, lpfilename);
221 if (lpfilename[len-1] != '\\')
222 strcat(lpfilename, "\\");
223 strcat(lpfilename, lpfilename_in);
225 else if (lpfilename[1] != ':') {
226 /* drive not set, but path is rooted */
227 memmove(&lpfilename[2], lpfilename, strlen(lpfilename));
228 lpfilename[0] = DRIVE_GetCurrentDrive();
229 lpfilename[1] = ':';
231 else if (lpfilename[1] == ':' &&
232 lpfilename[2] != '\\') {
233 /* drive is set, but not root path */
234 lstrcpy32A(lpfilename, DRIVE_GetDosCwd(lpfilename[0]));
235 strcat(lpfilename, lpfilename_in);
238 dprintf_file(stddeb, "FindFirstFile32A: %s -> %s .\n",
239 lpfilename_in, lpfilename);
241 slash = strrchr(lpfilename, '\\');
243 if (slash) {
244 lstrcpyn32A(context->path, lpfilename, slash - lpfilename + 1);
245 context->path[slash - lpfilename + 1] = '\0';
246 unixpath = DOSFS_GetUnixFileName(context->path, FALSE);
247 if (!unixpath) {
248 /* FIXME: SetLastError(??) */
249 HeapFree(SystemHeap, 0, context);
250 return INVALID_HANDLE_VALUE;
252 lstrcpy32A(context->mask, slash+1);
254 else {
255 /* shouldn't really get here now */
256 context->path[0] = '\0';
257 unixpath = ".";
258 lstrcpy32A(context->mask, lpfilename);
261 lstrcpy32A(context->unixpath, unixpath);
262 context->dir = opendir(unixpath);
263 if (!context->dir) {
264 /* FIXME: SetLastError(??) */
265 HeapFree(SystemHeap, 0, context);
266 return INVALID_HANDLE_VALUE;
269 /* uppercase mask in place */
270 for (p = context->mask ; *p; p++)
271 *p = toupper(*p);
273 if (!FindNextFile32A((HANDLE32) context, lpFindFileData))
274 return (INVALID_HANDLE_VALUE);
275 return ((HANDLE32) context);
278 /*************************************************************************
279 * FindFirstFile32W (KERNEL32.124)
281 HANDLE32 FindFirstFile32W(LPCWSTR filename,LPWIN32_FIND_DATA32W data)
283 WIN32_FIND_DATA32A adata;
284 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
285 HANDLE32 res = FindFirstFile32A(afn,&adata);
286 if (res)
288 data->dwFileAttributes = adata.dwFileAttributes;
289 data->ftCreationTime = adata.ftCreationTime;
290 data->ftLastAccessTime = adata.ftLastAccessTime;
291 data->ftLastWriteTime = adata.ftLastWriteTime;
292 data->nFileSizeHigh = adata.nFileSizeHigh;
293 data->nFileSizeLow = adata.nFileSizeLow;
294 data->dwReserved0 = adata.dwReserved0;
295 data->dwReserved1 = adata.dwReserved1;
296 lstrcpyAtoW(data->cFileName,adata.cFileName);
297 lstrcpyAtoW(data->cAlternateFileName,adata.cAlternateFileName);
299 HeapFree( GetProcessHeap(), 0, afn );
300 return res;
303 /*************************************************************************
304 * FindClose32 (KERNEL32.119)
306 BOOL32 FindClose32(HANDLE32 handle)
308 FindFileContext32 *context;
310 /* Windows95 ignores an invalid handle. */
311 if (handle == INVALID_HANDLE_VALUE)
313 SetLastError(ERROR_INVALID_HANDLE);
314 return FALSE;
316 context = (FindFileContext32 *) handle;
317 if (context->dir)
318 closedir(context->dir);
319 HeapFree(SystemHeap, 0, context);
320 return (TRUE);
323 /* 16 bit versions of find functions */
324 /*************************************************************************
325 * FindFirstFile16 (KERNEL.413)
328 HANDLE16
329 FindFirstFile16(LPCSTR lpFileName, LPVOID lpdata)
331 WIN32_FIND_DATA32A *findData = (WIN32_FIND_DATA32A *) lpdata;
332 HANDLE32 h32;
333 HGLOBAL16 h16;
334 HANDLE32 *ptr;
336 /* get a handle to the real pointer */
339 h32 = FindFirstFile32A(lpFileName, findData);
340 if (h32 > 0) {
341 h16 = GlobalAlloc16(0, sizeof(h32));
342 ptr = GlobalLock16(h16);
343 *ptr = h32;
344 return (h16);
346 else
347 return ((HANDLE16) h32);
350 /*************************************************************************
351 * FindNextFile16 (KERNEL.414)
354 BOOL16
355 FindNextFile16(HANDLE16 handle, LPVOID lpdata)
357 WIN32_FIND_DATA32A *findData = (WIN32_FIND_DATA32A *) lpdata;
358 HANDLE32 *lph32;
360 lph32 = GlobalLock16(handle);
361 if (FindNextFile32A(*lph32, findData)) {
362 return TRUE;
364 else
365 return FALSE;
368 /*************************************************************************
369 * FindClose16 (KERNEL.415)
372 BOOL16
373 FindClose16(HANDLE16 handle)
375 HANDLE32 *lph32;
376 BOOL16 ret;
378 if (handle == (HANDLE16) INVALID_HANDLE_VALUE) {
379 SetLastError(ERROR_INVALID_HANDLE);
380 return FALSE;
383 lph32 = GlobalLock16(handle);
384 ret = FindClose32(*lph32);
385 GlobalFree16(handle);
386 return (ret);