blob: d1c8b54bb31d2e81cdad500639b4e740a45831f9 [file] [log] [blame]
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001/*
2 * DOS file system functions
3 *
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00006 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000020 */
21
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000022#include "config.h"
Patrik Stridvall33929be2001-07-18 21:04:23 +000023
Alexandre Julliard0c126c71996-02-18 18:44:41 +000024#include <sys/types.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000025#include <ctype.h>
26#include <dirent.h>
Alexandre Julliard44ed71f1997-12-21 19:17:50 +000027#include <errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000028#ifdef HAVE_SYS_ERRNO_H
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000029#include <sys/errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000030#endif
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000031#include <fcntl.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000032#include <string.h>
33#include <stdlib.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000034#include <sys/stat.h>
Vincent Béron9a624912002-05-31 23:06:46 +000035#ifdef HAVE_SYS_IOCTL_H
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000036#include <sys/ioctl.h>
Steven Edwards48ac89b2002-05-19 22:25:02 +000037#endif
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000038#include <time.h>
Patrik Stridvalld016f812002-08-17 00:43:16 +000039#ifdef HAVE_UNISTD_H
40# include <unistd.h>
41#endif
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000042
Marcus Meissner317af321999-02-17 13:51:06 +000043#include "windef.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000044#include "winerror.h"
Patrik Stridvall33929be2001-07-18 21:04:23 +000045#include "wingdi.h"
46
47#include "wine/unicode.h"
48#include "wine/winbase16.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000049#include "drive.h"
50#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000051#include "heap.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000052#include "msdos.h"
Patrik Stridvall9c1de6d2002-09-12 22:07:02 +000053#include "winternl.h"
Alexandre Julliard37e95032001-07-19 00:39:09 +000054#include "wine/server.h"
Peter Hunnisett73ab6492002-02-25 20:10:35 +000055#include "msvcrt/excpt.h"
Patrik Stridvall33929be2001-07-18 21:04:23 +000056
Mike McCormack963985b2002-07-19 03:17:19 +000057#include "smb.h"
58
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000059#include "wine/debug.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000060
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000061WINE_DEFAULT_DEBUG_CHANNEL(dosfs);
62WINE_DECLARE_DEBUG_CHANNEL(file);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000063
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000064/* Define the VFAT ioctl to get both short and long file names */
Alexandre Julliardc6c09441997-01-12 18:32:19 +000065/* FIXME: is it possible to get this to work on other systems? */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000066#ifdef linux
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000067/* We want the real kernel dirent structure, not the libc one */
68typedef struct
69{
70 long d_ino;
71 long d_off;
72 unsigned short d_reclen;
73 char d_name[256];
74} KERNEL_DIRENT;
75
Peter Ganten0bac5e91999-09-27 11:46:27 +000076#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, KERNEL_DIRENT [2] )
77
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000078#else /* linux */
79#undef VFAT_IOCTL_READDIR_BOTH /* just in case... */
80#endif /* linux */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000081
82/* Chars we don't want to see in DOS file names */
Alexandre Julliard7e56f681996-01-31 19:02:28 +000083#define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000084
Alexandre Julliard829fe321998-07-26 14:27:39 +000085static const DOS_DEVICE DOSFS_Devices[] =
86/* name, device flags (see Int 21/AX=0x4400) */
87{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +000088 { {'C','O','N',0}, 0xc0d3 },
89 { {'P','R','N',0}, 0xa0c0 },
90 { {'N','U','L',0}, 0x80c4 },
91 { {'A','U','X',0}, 0x80c0 },
92 { {'L','P','T','1',0}, 0xa0c0 },
93 { {'L','P','T','2',0}, 0xa0c0 },
94 { {'L','P','T','3',0}, 0xa0c0 },
95 { {'L','P','T','4',0}, 0xc0d3 },
96 { {'C','O','M','1',0}, 0x80c0 },
97 { {'C','O','M','2',0}, 0x80c0 },
98 { {'C','O','M','3',0}, 0x80c0 },
99 { {'C','O','M','4',0}, 0x80c0 },
100 { {'S','C','S','I','M','G','R','$',0}, 0xc0c0 },
101 { {'H','P','S','C','A','N',0}, 0xc0c0 },
102 { {'E','M','M','X','X','X','X','0',0}, 0x0000 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000103};
104
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000105/*
106 * Directory info for DOSFS_ReadDir
107 * contains the names of *all* the files in the directory
108 */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000109typedef struct
110{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000111 int used;
112 int size;
113 char names[1];
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000114} DOS_DIR;
115
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000116/* Info structure for FindFirstFile handle */
117typedef struct
118{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000119 char *path; /* unix path */
120 LPWSTR long_mask;
121 LPWSTR short_mask;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000122 BYTE attr;
123 int drive;
124 int cur_pos;
Mike McCormack963985b2002-07-19 03:17:19 +0000125 union
126 {
127 DOS_DIR *dos_dir;
128 SMB_DIR *smb_dir;
129 } u;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000130} FIND_FIRST_INFO;
131
132
Dominik Strasser4f46b5d2001-04-20 18:38:41 +0000133static WINE_EXCEPTION_FILTER(page_fault)
134{
135 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
136 return EXCEPTION_EXECUTE_HANDLER;
137 return EXCEPTION_CONTINUE_SEARCH;
138}
139
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000140
141/***********************************************************************
142 * DOSFS_ValidDOSName
143 *
144 * Return 1 if Unix file 'name' is also a valid MS-DOS name
145 * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format).
146 * File name can be terminated by '\0', '\\' or '/'.
147 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000148static int DOSFS_ValidDOSName( LPCWSTR name, int ignore_case )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000149{
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000150 static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000151 const WCHAR *p = name;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000152 const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000153 int len = 0;
154
155 if (*p == '.')
156 {
157 /* Check for "." and ".." */
158 p++;
159 if (*p == '.') p++;
160 /* All other names beginning with '.' are invalid */
161 return (IS_END_OF_NAME(*p));
162 }
163 while (!IS_END_OF_NAME(*p))
164 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000165 if (*p < 256 && strchr( invalid, (char)*p )) return 0; /* Invalid char */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000166 if (*p == '.') break; /* Start of the extension */
167 if (++len > 8) return 0; /* Name too long */
168 p++;
169 }
170 if (*p != '.') return 1; /* End of name */
171 p++;
172 if (IS_END_OF_NAME(*p)) return 0; /* Empty extension not allowed */
173 len = 0;
174 while (!IS_END_OF_NAME(*p))
175 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000176 if (*p < 256 && strchr( invalid, (char)*p )) return 0; /* Invalid char */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000177 if (*p == '.') return 0; /* Second extension not allowed */
178 if (++len > 3) return 0; /* Extension too long */
179 p++;
180 }
181 return 1;
182}
183
184
185/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000186 * DOSFS_ToDosFCBFormat
187 *
188 * Convert a file name to DOS FCB format (8+3 chars, padded with blanks),
189 * expanding wild cards and converting to upper-case in the process.
190 * File name can be terminated by '\0', '\\' or '/'.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000191 * Return FALSE if the name is not a valid DOS name.
192 * 'buffer' must be at least 12 characters long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000193 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000194BOOL DOSFS_ToDosFCBFormat( LPCWSTR name, LPWSTR buffer )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000195{
196 static const char invalid_chars[] = INVALID_DOS_CHARS;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000197 LPCWSTR p = name;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000198 int i;
199
György 'Nog' Jeney4610c0a2002-09-27 22:03:44 +0000200 TRACE("(%s, %p)\n", debugstr_w(name), buffer);
201
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000202 /* Check for "." and ".." */
203 if (*p == '.')
204 {
205 p++;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000206 buffer[0] = '.';
207 for(i = 1; i < 11; i++) buffer[i] = ' ';
208 buffer[11] = 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000209 if (*p == '.')
210 {
211 buffer[1] = '.';
212 p++;
213 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000214 return (!*p || (*p == '/') || (*p == '\\'));
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000215 }
216
217 for (i = 0; i < 8; i++)
218 {
219 switch(*p)
220 {
221 case '\0':
222 case '\\':
223 case '/':
224 case '.':
225 buffer[i] = ' ';
226 break;
227 case '?':
228 p++;
229 /* fall through */
230 case '*':
231 buffer[i] = '?';
232 break;
233 default:
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000234 if (*p < 256 && strchr( invalid_chars, (char)*p )) return FALSE;
235 buffer[i] = toupperW(*p);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000236 p++;
237 break;
238 }
239 }
240
241 if (*p == '*')
242 {
243 /* Skip all chars after wildcard up to first dot */
244 while (*p && (*p != '/') && (*p != '\\') && (*p != '.')) p++;
245 }
246 else
247 {
248 /* Check if name too long */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000249 if (*p && (*p != '/') && (*p != '\\') && (*p != '.')) return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000250 }
251 if (*p == '.') p++; /* Skip dot */
252
253 for (i = 8; i < 11; i++)
254 {
255 switch(*p)
256 {
257 case '\0':
258 case '\\':
259 case '/':
260 buffer[i] = ' ';
261 break;
262 case '.':
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000263 return FALSE; /* Second extension not allowed */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000264 case '?':
265 p++;
266 /* fall through */
267 case '*':
268 buffer[i] = '?';
269 break;
270 default:
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000271 if (*p < 256 && strchr( invalid_chars, (char)*p )) return FALSE;
272 buffer[i] = toupperW(*p);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000273 p++;
274 break;
275 }
276 }
277 buffer[11] = '\0';
Stefan Leichter7cc51fa2000-03-26 20:25:59 +0000278
279 /* at most 3 character of the extension are processed
Vincent Béron9a624912002-05-31 23:06:46 +0000280 * is something behind this ?
Stefan Leichter7cc51fa2000-03-26 20:25:59 +0000281 */
Alexandre Julliard199aeba2000-03-28 13:20:32 +0000282 while (*p == '*' || *p == ' ') p++; /* skip wildcards and spaces */
Stefan Leichter7cc51fa2000-03-26 20:25:59 +0000283 return IS_END_OF_NAME(*p);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000284}
285
286
287/***********************************************************************
288 * DOSFS_ToDosDTAFormat
289 *
290 * Convert a file name from FCB to DTA format (name.ext, null-terminated)
291 * converting to upper-case in the process.
292 * File name can be terminated by '\0', '\\' or '/'.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000293 * 'buffer' must be at least 13 characters long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000294 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000295static void DOSFS_ToDosDTAFormat( LPCWSTR name, LPWSTR buffer )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000296{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000297 LPWSTR p;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000298
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000299 memcpy( buffer, name, 8 * sizeof(WCHAR) );
Alexandre Julliard566a52a2001-03-05 19:34:17 +0000300 p = buffer + 8;
301 while ((p > buffer) && (p[-1] == ' ')) p--;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000302 *p++ = '.';
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000303 memcpy( p, name + 8, 3 * sizeof(WCHAR) );
Alexandre Julliard566a52a2001-03-05 19:34:17 +0000304 p += 3;
305 while (p[-1] == ' ') p--;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000306 if (p[-1] == '.') p--;
307 *p = '\0';
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000308}
309
310
311/***********************************************************************
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000312 * DOSFS_MatchShort
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000313 *
314 * Check a DOS file name against a mask (both in FCB format).
315 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000316static int DOSFS_MatchShort( LPCWSTR mask, LPCWSTR name )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000317{
318 int i;
319 for (i = 11; i > 0; i--, mask++, name++)
320 if ((*mask != '?') && (*mask != *name)) return 0;
321 return 1;
322}
323
324
325/***********************************************************************
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000326 * DOSFS_MatchLong
327 *
328 * Check a long file name against a mask.
Andreas Mohr07291052000-09-07 21:03:02 +0000329 *
330 * Tests (done in W95 DOS shell - case insensitive):
331 * *.txt test1.test.txt *
332 * *st1* test1.txt *
333 * *.t??????.t* test1.ta.tornado.txt *
334 * *tornado* test1.ta.tornado.txt *
335 * t*t test1.ta.tornado.txt *
336 * ?est* test1.txt *
337 * ?est??? test1.txt -
Vincent Béron9a624912002-05-31 23:06:46 +0000338 * *test1.txt* test1.txt *
Andreas Mohr07291052000-09-07 21:03:02 +0000339 * h?l?o*t.dat hellothisisatest.dat *
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000340 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000341static int DOSFS_MatchLong( LPCWSTR mask, LPCWSTR name, int case_sensitive )
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000342{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000343 LPCWSTR lastjoker = NULL;
344 LPCWSTR next_to_retry = NULL;
345 static const WCHAR asterisk_dot_asterisk[] = {'*','.','*',0};
Andreas Mohr07291052000-09-07 21:03:02 +0000346
György 'Nog' Jeney4610c0a2002-09-27 22:03:44 +0000347 TRACE("(%s, %s, %x)\n", debugstr_w(mask), debugstr_w(name), case_sensitive);
348
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000349 if (!strcmpW( mask, asterisk_dot_asterisk )) return 1;
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000350 while (*name && *mask)
351 {
352 if (*mask == '*')
353 {
354 mask++;
355 while (*mask == '*') mask++; /* Skip consecutive '*' */
Andreas Mohr07291052000-09-07 21:03:02 +0000356 lastjoker = mask;
357 if (!*mask) return 1; /* end of mask is all '*', so match */
358
359 /* skip to the next match after the joker(s) */
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000360 if (case_sensitive) while (*name && (*name != *mask)) name++;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000361 else while (*name && (toupperW(*name) != toupperW(*mask))) name++;
Andreas Mohr07291052000-09-07 21:03:02 +0000362
Robert W Hall9132a781999-04-18 14:38:17 +0000363 if (!*name) break;
Andreas Mohr07291052000-09-07 21:03:02 +0000364 next_to_retry = name;
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000365 }
366 else if (*mask != '?')
367 {
Andreas Mohr07291052000-09-07 21:03:02 +0000368 int mismatch = 0;
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000369 if (case_sensitive)
370 {
Andreas Mohr07291052000-09-07 21:03:02 +0000371 if (*mask != *name) mismatch = 1;
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000372 }
Andreas Mohr07291052000-09-07 21:03:02 +0000373 else
374 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000375 if (toupperW(*mask) != toupperW(*name)) mismatch = 1;
Andreas Mohr07291052000-09-07 21:03:02 +0000376 }
377 if (!mismatch)
378 {
379 mask++;
380 name++;
381 if (*mask == '\0')
382 {
383 if (*name == '\0')
384 return 1;
385 if (lastjoker)
386 mask = lastjoker;
387 }
388 }
389 else /* mismatch ! */
390 {
391 if (lastjoker) /* we had an '*', so we can try unlimitedly */
392 {
393 mask = lastjoker;
394
395 /* this scan sequence was a mismatch, so restart
396 * 1 char after the first char we checked last time */
397 next_to_retry++;
398 name = next_to_retry;
399 }
400 else
401 return 0; /* bad luck */
402 }
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000403 }
Andreas Mohr07291052000-09-07 21:03:02 +0000404 else /* '?' */
405 {
406 mask++;
407 name++;
408 }
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000409 }
Andreas Mohr07291052000-09-07 21:03:02 +0000410 while ((*mask == '.') || (*mask == '*'))
411 mask++; /* Ignore trailing '.' or '*' in mask */
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000412 return (!*name && !*mask);
413}
414
415
416/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000417 * DOSFS_AddDirEntry
418 *
419 * Used to construct an array of filenames in DOSFS_OpenDir
420 */
421static BOOL DOSFS_AddDirEntry(DOS_DIR **dir, LPCWSTR name, LPCWSTR dosname)
422{
423 int extra1 = (strlenW(name) + 1) * sizeof(WCHAR);
424 int extra2 = (strlenW(dosname) + 1) * sizeof(WCHAR);
425
426 /* if we need more, at minimum double the size */
427 if( (extra1 + extra2 + (*dir)->used) > (*dir)->size)
428 {
429 int more = (*dir)->size;
430 DOS_DIR *t;
431
432 if(more<(extra1+extra2))
433 more = extra1+extra2;
434
435 t = HeapReAlloc(GetProcessHeap(), 0, *dir, sizeof(**dir) + (*dir)->size + more );
436 if(!t)
437 {
438 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
439 ERR("Out of memory caching directory structure %d %d %d\n",
440 (*dir)->size, more, (*dir)->used);
441 return FALSE;
442 }
443 (*dir) = t;
444 (*dir)->size += more;
445 }
446
447 /* at this point, the dir structure is big enough to hold these names */
448 strcpyW((LPWSTR)&(*dir)->names[(*dir)->used], name);
449 (*dir)->used += extra1;
450 strcpyW((LPWSTR)&(*dir)->names[(*dir)->used], dosname);
451 (*dir)->used += extra2;
452
453 return TRUE;
454}
455
456
457/***********************************************************************
458 * DOSFS_OpenDir_VFAT
459 */
460static BOOL DOSFS_OpenDir_VFAT(UINT codepage, DOS_DIR **dir, const char *unix_path)
461{
462#ifdef VFAT_IOCTL_READDIR_BOTH
463 KERNEL_DIRENT de[2];
464 int fd = open( unix_path, O_RDONLY );
465 BOOL r = TRUE;
466
467 /* Check if the VFAT ioctl is supported on this directory */
468
469 if ( fd<0 )
470 return FALSE;
471
472 while (1)
473 {
474 WCHAR long_name[MAX_PATH];
475 WCHAR short_name[12];
476
477 r = (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) != -1);
478 if(!r)
479 break;
480 if (!de[0].d_reclen)
481 break;
482 MultiByteToWideChar(codepage, 0, de[0].d_name, -1, long_name, MAX_PATH);
483 if (!DOSFS_ToDosFCBFormat( long_name, short_name ))
484 short_name[0] = '\0';
485 if (de[1].d_name[0])
486 MultiByteToWideChar(codepage, 0, de[1].d_name, -1, long_name, MAX_PATH);
487 else
488 MultiByteToWideChar(codepage, 0, de[0].d_name, -1, long_name, MAX_PATH);
489 r = DOSFS_AddDirEntry(dir, long_name, short_name );
490 if(!r)
491 break;
492 }
493 if(r)
494 {
495 static const WCHAR empty_strW[] = { 0 };
496 DOSFS_AddDirEntry(dir, empty_strW, empty_strW);
497 }
498 close(fd);
499 return r;
500#else
501 return FALSE;
502#endif /* VFAT_IOCTL_READDIR_BOTH */
503}
504
505
506/***********************************************************************
507 * DOSFS_OpenDir_Normal
508 *
509 * Now use the standard opendir/readdir interface
510 */
511static BOOL DOSFS_OpenDir_Normal( UINT codepage, DOS_DIR **dir, const char *unix_path )
512{
513 DIR *unixdir = opendir( unix_path );
514 BOOL r = TRUE;
515 static const WCHAR empty_strW[] = { 0 };
516
517 if(!unixdir)
518 return FALSE;
519 while(1)
520 {
521 WCHAR long_name[MAX_PATH];
522 struct dirent *de = readdir(unixdir);
523
524 if(!de)
525 break;
526 MultiByteToWideChar(codepage, 0, de->d_name, -1, long_name, MAX_PATH);
527 r = DOSFS_AddDirEntry(dir, long_name, empty_strW);
528 if(!r)
529 break;
530 }
531 if(r)
532 DOSFS_AddDirEntry(dir, empty_strW, empty_strW);
533 closedir(unixdir);
534 return r;
535}
536
537/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000538 * DOSFS_OpenDir
539 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000540static DOS_DIR *DOSFS_OpenDir( UINT codepage, const char *unix_path )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000541{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000542 const int init_size = 0x100;
543 DOS_DIR *dir = HeapAlloc( GetProcessHeap(), 0, sizeof(*dir) + init_size);
544 BOOL r;
545
546 TRACE("%s\n",debugstr_a(unix_path));
547
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000548 if (!dir)
549 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000550 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000551 return NULL;
552 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000553 dir->used = 0;
554 dir->size = init_size;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000555
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000556 /* Treat empty path as root directory. This simplifies path split into
557 directory and mask in several other places */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000558 if (!*unix_path) unix_path = "/";
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000559
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000560 r = DOSFS_OpenDir_VFAT( codepage, &dir, unix_path);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000561
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000562 if(!r)
563 r = DOSFS_OpenDir_Normal( codepage, &dir, unix_path);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000564
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000565 if(!r)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000566 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000567 HeapFree(GetProcessHeap(), 0, dir);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000568 return NULL;
569 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000570 dir->used = 0;
571
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000572 return dir;
573}
574
575
576/***********************************************************************
577 * DOSFS_CloseDir
578 */
579static void DOSFS_CloseDir( DOS_DIR *dir )
580{
Alexandre Julliard90476d62000-02-16 22:47:24 +0000581 HeapFree( GetProcessHeap(), 0, dir );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000582}
583
584
585/***********************************************************************
586 * DOSFS_ReadDir
587 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000588static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCWSTR *long_name,
589 LPCWSTR *short_name )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000590{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000591 LPCWSTR sn, ln;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000592
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000593 if (!dir)
594 return FALSE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000595
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000596 /* the long pathname is first */
597 ln = (LPCWSTR)&dir->names[dir->used];
598 if(ln[0])
599 *long_name = ln;
600 else
601 return FALSE;
602 dir->used += (strlenW(ln) + 1) * sizeof(WCHAR);
603
604 /* followed by the short path name */
605 sn = (LPCWSTR)&dir->names[dir->used];
606 if(sn[0])
607 *short_name = sn;
608 else
609 *short_name = NULL;
610 dir->used += (strlenW(sn) + 1) * sizeof(WCHAR);
611
György 'Nog' Jeney4610c0a2002-09-27 22:03:44 +0000612 TRACE("Read: long_name: %s, short_name: %s\n",
613 debugstr_w(*long_name), debugstr_w(*short_name));
614
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000615 return TRUE;
616}
617
618
619/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000620 * DOSFS_Hash
621 *
622 * Transform a Unix file name into a hashed DOS name. If the name is a valid
623 * DOS name, it is converted to upper-case; otherwise it is replaced by a
624 * hashed version that fits in 8.3 format.
625 * File name can be terminated by '\0', '\\' or '/'.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000626 * 'buffer' must be at least 13 characters long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000627 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000628static void DOSFS_Hash( LPCWSTR name, LPWSTR buffer, BOOL dir_format,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000629 BOOL ignore_case )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000630{
631 static const char invalid_chars[] = INVALID_DOS_CHARS "~.";
632 static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
633
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000634 LPCWSTR p, ext;
635 LPWSTR dst;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000636 unsigned short hash;
637 int i;
638
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000639 if (dir_format)
640 {
641 for(i = 0; i < 11; i++) buffer[i] = ' ';
642 buffer[11] = 0;
643 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000644
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000645 if (DOSFS_ValidDOSName( name, ignore_case ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000646 {
647 /* Check for '.' and '..' */
648 if (*name == '.')
649 {
650 buffer[0] = '.';
651 if (!dir_format) buffer[1] = buffer[2] = '\0';
652 if (name[1] == '.') buffer[1] = '.';
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000653 return;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000654 }
655
656 /* Simply copy the name, converting to uppercase */
657
658 for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000659 *dst++ = toupperW(*name);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000660 if (*name == '.')
661 {
662 if (dir_format) dst = buffer + 8;
663 else *dst++ = '.';
664 for (name++; !IS_END_OF_NAME(*name); name++)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000665 *dst++ = toupperW(*name);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000666 }
667 if (!dir_format) *dst = '\0';
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000668 return;
669 }
670
671 /* Compute the hash code of the file name */
672 /* If you know something about hash functions, feel free to */
673 /* insert a better algorithm here... */
674 if (ignore_case)
675 {
676 for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000677 hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p) ^ (tolowerW(p[1]) << 8);
678 hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p); /* Last character */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000679 }
680 else
681 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000682 for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
683 hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8);
684 hash = (hash << 3) ^ (hash >> 5) ^ *p; /* Last character */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000685 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000686
687 /* Find last dot for start of the extension */
688 for (p = name+1, ext = NULL; !IS_END_OF_NAME(*p); p++)
689 if (*p == '.') ext = p;
690 if (ext && IS_END_OF_NAME(ext[1]))
691 ext = NULL; /* Empty extension ignored */
692
693 /* Copy first 4 chars, replacing invalid chars with '_' */
694 for (i = 4, p = name, dst = buffer; i > 0; i--, p++)
695 {
696 if (IS_END_OF_NAME(*p) || (p == ext)) break;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000697 *dst++ = (*p < 256 && strchr( invalid_chars, (char)*p )) ? '_' : toupperW(*p);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000698 }
699 /* Pad to 5 chars with '~' */
700 while (i-- >= 0) *dst++ = '~';
701
702 /* Insert hash code converted to 3 ASCII chars */
703 *dst++ = hash_chars[(hash >> 10) & 0x1f];
704 *dst++ = hash_chars[(hash >> 5) & 0x1f];
705 *dst++ = hash_chars[hash & 0x1f];
706
707 /* Copy the first 3 chars of the extension (if any) */
708 if (ext)
709 {
710 if (!dir_format) *dst++ = '.';
711 for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000712 *dst++ = (*ext < 256 && strchr( invalid_chars, (char)*ext )) ? '_' : toupperW(*ext);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000713 }
714 if (!dir_format) *dst = '\0';
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000715}
716
717
718/***********************************************************************
719 * DOSFS_FindUnixName
720 *
721 * Find the Unix file name in a given directory that corresponds to
722 * a file name (either in Unix or DOS format).
723 * File name can be terminated by '\0', '\\' or '/'.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000724 * Return TRUE if OK, FALSE if no file name matches.
725 *
726 * 'long_buf' must be at least 'long_len' characters long. If the long name
727 * turns out to be larger than that, the function returns FALSE.
728 * 'short_buf' must be at least 13 characters long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000729 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000730BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf,
731 INT long_len, LPWSTR short_buf, BOOL ignore_case)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000732{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000733 DOS_DIR *dir;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000734 LPCWSTR long_name, short_name;
735 WCHAR dos_name[12], tmp_buf[13];
Alexandre Julliarda3960291999-02-26 11:11:13 +0000736 BOOL ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000737
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000738 LPCWSTR p = strchrW( name, '/' );
739 int len = p ? (int)(p - name) : strlenW(name);
740 if ((p = strchrW( name, '\\' ))) len = min( (int)(p - name), len );
Dave Hawkesbb9e66e2000-06-25 12:46:40 +0000741 /* Ignore trailing dots and spaces */
742 while (len > 1 && (name[len-1] == '.' || name[len-1] == ' ')) len--;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000743 if (long_len < len + 1) return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000744
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000745 TRACE("%s,%s\n", path->long_name, debugstr_w(name) );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000746
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000747 if (!DOSFS_ToDosFCBFormat( name, dos_name )) dos_name[0] = '\0';
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000748
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000749 if (!(dir = DOSFS_OpenDir( DRIVE_GetCodepage(path->drive), path->long_name )))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000750 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000751 WARN("(%s,%s): can't open dir: %s\n",
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000752 path->long_name, debugstr_w(name), strerror(errno) );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000753 return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000754 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000755
756 while ((ret = DOSFS_ReadDir( dir, &long_name, &short_name )))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000757 {
758 /* Check against Unix name */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000759 if (len == strlenW(long_name))
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000760 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000761 if (!ignore_case)
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000762 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000763 if (!strncmpW( long_name, name, len )) break;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000764 }
765 else
766 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000767 if (!strncmpiW( long_name, name, len )) break;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000768 }
769 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000770 if (dos_name[0])
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000771 {
772 /* Check against hashed DOS name */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000773 if (!short_name)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000774 {
775 DOSFS_Hash( long_name, tmp_buf, TRUE, ignore_case );
776 short_name = tmp_buf;
777 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000778 if (!strcmpW( dos_name, short_name )) break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000779 }
780 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000781 if (ret)
782 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000783 if (long_buf) WideCharToMultiByte(DRIVE_GetCodepage(path->drive), 0,
784 long_name, -1, long_buf, long_len, NULL, NULL);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000785 if (short_buf)
786 {
787 if (short_name)
788 DOSFS_ToDosDTAFormat( short_name, short_buf );
789 else
790 DOSFS_Hash( long_name, short_buf, FALSE, ignore_case );
791 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000792 TRACE("(%s,%s) -> %s (%s)\n", path->long_name, debugstr_w(name),
793 debugstr_w(long_name), short_buf ? debugstr_w(short_buf) : "***");
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000794 }
795 else
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000796 WARN("%s not found in '%s'\n", debugstr_w(name), path->long_name);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000797 DOSFS_CloseDir( dir );
798 return ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000799}
800
801
802/***********************************************************************
Alexandre Julliard829fe321998-07-26 14:27:39 +0000803 * DOSFS_GetDevice
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000804 *
Alexandre Julliard829fe321998-07-26 14:27:39 +0000805 * Check if a DOS file name represents a DOS device and return the device.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000806 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000807const DOS_DEVICE *DOSFS_GetDevice( LPCWSTR name )
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000808{
Alexandre Julliard267ca682002-07-31 17:20:00 +0000809 unsigned int i;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000810 const WCHAR *p;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000811
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000812 if (!name) return NULL; /* if FILE_DupUnixHandle was used */
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000813 if (name[0] && (name[1] == ':')) name += 2;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000814 if ((p = strrchrW( name, '/' ))) name = p + 1;
815 if ((p = strrchrW( name, '\\' ))) name = p + 1;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000816 for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++)
817 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000818 const WCHAR *dev = DOSFS_Devices[i].name;
819 if (!strncmpiW( dev, name, strlenW(dev) ))
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000820 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000821 p = name + strlenW( dev );
Lawson Whitneye3178f92000-12-27 03:28:13 +0000822 if (!*p || (*p == '.') || (*p == ':')) return &DOSFS_Devices[i];
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000823 }
824 }
Alexandre Julliard829fe321998-07-26 14:27:39 +0000825 return NULL;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000826}
827
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000828
829/***********************************************************************
830 * DOSFS_GetDeviceByHandle
831 */
Alexandre Julliard267ca682002-07-31 17:20:00 +0000832const DOS_DEVICE *DOSFS_GetDeviceByHandle( HANDLE hFile )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000833{
Alexandre Julliard92643002000-08-31 01:59:51 +0000834 const DOS_DEVICE *ret = NULL;
Alexandre Julliard67a74992001-02-27 02:09:16 +0000835 SERVER_START_REQ( get_file_info )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000836 {
Alexandre Julliard92643002000-08-31 01:59:51 +0000837 req->handle = hFile;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000838 if (!wine_server_call( req ) && (reply->type == FILE_TYPE_UNKNOWN))
Alexandre Julliard92643002000-08-31 01:59:51 +0000839 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000840 if ((reply->attr >= 0) &&
841 (reply->attr < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0])))
842 ret = &DOSFS_Devices[reply->attr];
Alexandre Julliard92643002000-08-31 01:59:51 +0000843 }
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000844 }
Alexandre Julliard92643002000-08-31 01:59:51 +0000845 SERVER_END_REQ;
846 return ret;
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000847}
848
849
Mike McCormack11776c12000-10-13 17:11:30 +0000850/**************************************************************************
851 * DOSFS_CreateCommPort
852 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000853static HANDLE DOSFS_CreateCommPort(LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa)
Mike McCormack11776c12000-10-13 17:11:30 +0000854{
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000855 HANDLE ret;
Mike McCormack11776c12000-10-13 17:11:30 +0000856 char devname[40];
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000857 WCHAR devnameW[40];
858 static const WCHAR serialportsW[] = {'s','e','r','i','a','l','p','o','r','t','s',0};
859 static const WCHAR empty_strW[] = { 0 };
Mike McCormack11776c12000-10-13 17:11:30 +0000860
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000861 TRACE_(file)("%s %lx %lx\n", debugstr_w(name), access, attributes);
Mike McCormack11776c12000-10-13 17:11:30 +0000862
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000863 PROFILE_GetWineIniString(serialportsW, name, empty_strW, devnameW, 40);
864 if(!devnameW[0])
Mike McCormack11776c12000-10-13 17:11:30 +0000865 return 0;
866
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000867 WideCharToMultiByte(CP_ACP, 0, devnameW, -1, devname, sizeof(devname), NULL, NULL);
868
869 TRACE("opening %s as %s\n", devname, debugstr_w(name));
Mike McCormack11776c12000-10-13 17:11:30 +0000870
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000871 SERVER_START_REQ( create_serial )
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000872 {
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000873 req->access = access;
Eric Pouech3bbeb722001-10-14 16:08:45 +0000874 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
Mike McCormack568c67e2001-10-08 20:40:57 +0000875 req->attributes = attributes;
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000876 req->sharing = FILE_SHARE_READ|FILE_SHARE_WRITE;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000877 wine_server_add_data( req, devname, strlen(devname) );
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000878 SetLastError(0);
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000879 wine_server_call_err( req );
880 ret = reply->handle;
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000881 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000882 SERVER_END_REQ;
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000883
Rein Klazes0a788572001-02-20 01:52:41 +0000884 if(!ret)
Andreas Mohre15badb2001-10-21 15:18:15 +0000885 ERR("Couldn't open device '%s' ! (check permissions)\n",devname);
Rein Klazes0a788572001-02-20 01:52:41 +0000886 else
887 TRACE("return %08X\n", ret );
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000888 return ret;
Mike McCormack11776c12000-10-13 17:11:30 +0000889}
890
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000891/***********************************************************************
892 * DOSFS_OpenDevice
893 *
894 * Open a DOS device. This might not map 1:1 into the UNIX device concept.
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000895 * Returns 0 on failure.
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000896 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000897HANDLE DOSFS_OpenDevice( LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000898{
Alexandre Julliard267ca682002-07-31 17:20:00 +0000899 unsigned int i;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000900 const WCHAR *p;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000901 HANDLE handle;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000902
Alexandre Julliard0c126c71996-02-18 18:44:41 +0000903 if (name[0] && (name[1] == ':')) name += 2;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000904 if ((p = strrchrW( name, '/' ))) name = p + 1;
905 if ((p = strrchrW( name, '\\' ))) name = p + 1;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000906 for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++)
907 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000908 const WCHAR *dev = DOSFS_Devices[i].name;
909 if (!strncmpiW( dev, name, strlenW(dev) ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000910 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000911 p = name + strlenW( dev );
Lawson Whitneye3178f92000-12-27 03:28:13 +0000912 if (!*p || (*p == '.') || (*p == ':')) {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000913 static const WCHAR nulW[] = {'N','U','L',0};
914 static const WCHAR conW[] = {'C','O','N',0};
915 static const WCHAR scsimgrW[] = {'S','C','S','I','M','G','R','$',0};
916 static const WCHAR hpscanW[] = {'H','P','S','C','A','N',0};
917 static const WCHAR emmxxxx0W[] = {'E','M','M','X','X','X','X','0',0};
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000918 /* got it */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000919 if (!strcmpiW(DOSFS_Devices[i].name, nulW))
Alexandre Julliard05625391999-01-03 11:55:56 +0000920 return FILE_CreateFile( "/dev/null", access,
Eric Pouech3bbeb722001-10-14 16:08:45 +0000921 FILE_SHARE_READ|FILE_SHARE_WRITE, sa,
Ove Kaaven708a8462001-10-24 00:23:25 +0000922 OPEN_EXISTING, 0, 0, TRUE, DRIVE_UNKNOWN );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000923 if (!strcmpiW(DOSFS_Devices[i].name, conW)) {
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000924 HANDLE to_dup;
Alexandre Julliard05625391999-01-03 11:55:56 +0000925 switch (access & (GENERIC_READ|GENERIC_WRITE)) {
926 case GENERIC_READ:
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000927 to_dup = GetStdHandle( STD_INPUT_HANDLE );
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000928 break;
Alexandre Julliard05625391999-01-03 11:55:56 +0000929 case GENERIC_WRITE:
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000930 to_dup = GetStdHandle( STD_OUTPUT_HANDLE );
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000931 break;
932 default:
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000933 FIXME("can't open CON read/write\n");
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000934 return 0;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000935 }
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000936 if (!DuplicateHandle( GetCurrentProcess(), to_dup, GetCurrentProcess(),
Vincent Béron9a624912002-05-31 23:06:46 +0000937 &handle, 0,
938 sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle,
Eric Pouech3bbeb722001-10-14 16:08:45 +0000939 DUPLICATE_SAME_ACCESS ))
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000940 handle = 0;
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000941 return handle;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000942 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000943 if (!strcmpiW(DOSFS_Devices[i].name, scsimgrW) ||
944 !strcmpiW(DOSFS_Devices[i].name, hpscanW) ||
945 !strcmpiW(DOSFS_Devices[i].name, emmxxxx0W))
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +0000946 {
Eric Pouech3bbeb722001-10-14 16:08:45 +0000947 return FILE_CreateDevice( i, access, sa );
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000948 }
Michael McCormacka8486071999-03-14 12:25:36 +0000949
Eric Pouech3bbeb722001-10-14 16:08:45 +0000950 if( (handle=DOSFS_CreateCommPort(DOSFS_Devices[i].name,access,attributes,sa)) )
Mike McCormack44b5bf52000-09-07 18:39:51 +0000951 return handle;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000952 FIXME("device open %s not supported (yet)\n", debugstr_w(DOSFS_Devices[i].name));
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000953 return 0;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000954 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000955 }
956 }
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000957 return 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000958}
959
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000960
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000961/***********************************************************************
962 * DOSFS_GetPathDrive
963 *
964 * Get the drive specified by a given path name (DOS or Unix format).
965 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000966static int DOSFS_GetPathDrive( LPCWSTR *name )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000967{
968 int drive;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000969 LPCWSTR p = *name;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000970
971 if (*p && (p[1] == ':'))
972 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000973 drive = toupperW(*p) - 'A';
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000974 *name += 2;
975 }
976 else if (*p == '/') /* Absolute Unix path? */
977 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000978 if ((drive = DRIVE_FindDriveRootW( name )) == -1)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000979 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000980 MESSAGE("Warning: %s not accessible from a configured DOS drive\n", debugstr_w(*name) );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000981 /* Assume it really was a DOS name */
Vincent Béron9a624912002-05-31 23:06:46 +0000982 drive = DRIVE_GetCurrentDrive();
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000983 }
984 }
985 else drive = DRIVE_GetCurrentDrive();
986
987 if (!DRIVE_IsValid(drive))
988 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000989 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000990 return -1;
991 }
992 return drive;
993}
994
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000995
996/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000997 * DOSFS_GetFullName
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000998 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000999 * Convert a file name (DOS or mixed DOS/Unix format) to a valid
1000 * Unix name / short DOS name pair.
1001 * Return FALSE if one of the path components does not exist. The last path
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001002 * component is only checked if 'check_last' is non-zero.
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001003 * The buffers pointed to by 'long_buf' and 'short_buf' must be
1004 * at least MAX_PATHNAME_LEN long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001005 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001006BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last, DOS_FULL_NAME *full )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001007{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001008 BOOL found;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001009 UINT flags, codepage;
1010 char *p_l, *root;
1011 LPWSTR p_s;
1012 static const WCHAR driveA_rootW[] = {'A',':','\\',0};
1013 static const WCHAR dos_rootW[] = {'\\',0};
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001014
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001015 TRACE("%s (last=%d)\n", debugstr_w(name), check_last );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001016
Gerard Pateld52e1c42001-02-16 19:05:42 +00001017 if ((!*name) || (*name=='\n'))
1018 { /* error code for Win98 */
1019 SetLastError(ERROR_BAD_PATHNAME);
1020 return FALSE;
1021 }
1022
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001023 if ((full->drive = DOSFS_GetPathDrive( &name )) == -1) return FALSE;
1024 flags = DRIVE_GetFlags( full->drive );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001025 codepage = DRIVE_GetCodepage(full->drive);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001026
Alexandre Julliarda3960291999-02-26 11:11:13 +00001027 lstrcpynA( full->long_name, DRIVE_GetRoot( full->drive ),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001028 sizeof(full->long_name) );
1029 if (full->long_name[1]) root = full->long_name + strlen(full->long_name);
1030 else root = full->long_name; /* root directory */
1031
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001032 strcpyW( full->short_name, driveA_rootW );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001033 full->short_name[0] += full->drive;
1034
1035 if ((*name == '\\') || (*name == '/')) /* Absolute path */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001036 {
1037 while ((*name == '\\') || (*name == '/')) name++;
1038 }
Alexandre Julliarddcf0bea2002-06-20 23:13:06 +00001039 else /* Relative path */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001040 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001041 lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001042 sizeof(full->long_name) - (root - full->long_name) - 1 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001043 if (root[1]) *root = '/';
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001044 lstrcpynW( full->short_name + 3, DRIVE_GetDosCwd( full->drive ),
1045 sizeof(full->short_name)/sizeof(full->short_name[0]) - 3 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001046 }
1047
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001048 p_l = full->long_name[1] ? full->long_name + strlen(full->long_name)
1049 : full->long_name;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001050 p_s = full->short_name[3] ? full->short_name + strlenW(full->short_name)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001051 : full->short_name + 2;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001052 found = TRUE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001053
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001054 while (*name && found)
1055 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001056 /* Check for '.' and '..' */
1057
1058 if (*name == '.')
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001059 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001060 if (IS_END_OF_NAME(name[1]))
1061 {
1062 name++;
1063 while ((*name == '\\') || (*name == '/')) name++;
1064 continue;
1065 }
1066 else if ((name[1] == '.') && IS_END_OF_NAME(name[2]))
1067 {
1068 name += 2;
1069 while ((*name == '\\') || (*name == '/')) name++;
1070 while ((p_l > root) && (*p_l != '/')) p_l--;
1071 while ((p_s > full->short_name + 2) && (*p_s != '\\')) p_s--;
1072 *p_l = *p_s = '\0'; /* Remove trailing separator */
1073 continue;
1074 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001075 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001076
1077 /* Make sure buffers are large enough */
1078
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001079 if ((p_s >= full->short_name + sizeof(full->short_name)/sizeof(full->short_name[0]) - 14) ||
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001080 (p_l >= full->long_name + sizeof(full->long_name) - 1))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001081 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001082 SetLastError( ERROR_PATH_NOT_FOUND );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001083 return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001084 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001085
1086 /* Get the long and short name matching the file name */
1087
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001088 if ((found = DOSFS_FindUnixName( full, name, p_l + 1,
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001089 sizeof(full->long_name) - (p_l - full->long_name) - 1,
1090 p_s + 1, !(flags & DRIVE_CASE_SENSITIVE) )))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001091 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001092 *p_l++ = '/';
1093 p_l += strlen(p_l);
1094 *p_s++ = '\\';
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001095 p_s += strlenW(p_s);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001096 while (!IS_END_OF_NAME(*name)) name++;
1097 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001098 else if (!check_last)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001099 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001100 *p_l++ = '/';
1101 *p_s++ = '\\';
1102 while (!IS_END_OF_NAME(*name) &&
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001103 (p_s < full->short_name + sizeof(full->short_name)/sizeof(full->short_name[0]) - 1) &&
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001104 (p_l < full->long_name + sizeof(full->long_name) - 1))
1105 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001106 WCHAR wch;
1107 *p_s++ = tolowerW(*name);
Alexandre Julliard829fe321998-07-26 14:27:39 +00001108 /* If the drive is case-sensitive we want to create new */
1109 /* files in lower-case otherwise we can't reopen them */
1110 /* under the same short name. */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001111 if (flags & DRIVE_CASE_SENSITIVE) wch = tolowerW(*name);
1112 else wch = *name;
1113 p_l += WideCharToMultiByte(codepage, 0, &wch, 1, p_l, 2, NULL, NULL);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001114 name++;
1115 }
Dave Hawkesbb9e66e2000-06-25 12:46:40 +00001116 /* Ignore trailing dots and spaces */
1117 while(p_l[-1] == '.' || p_l[-1] == ' ') {
1118 --p_l;
1119 --p_s;
1120 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001121 *p_l = '\0';
1122 *p_s = '\0';
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001123 }
1124 while ((*name == '\\') || (*name == '/')) name++;
1125 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001126
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001127 if (!found)
1128 {
Alexander Larssona8745ea1998-12-02 10:04:52 +00001129 if (check_last)
1130 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001131 SetLastError( ERROR_FILE_NOT_FOUND );
Alexander Larssona8745ea1998-12-02 10:04:52 +00001132 return FALSE;
1133 }
Alexander Larsson2772a671998-12-07 16:23:42 +00001134 if (*name) /* Not last */
1135 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001136 SetLastError( ERROR_PATH_NOT_FOUND );
Alexander Larsson2772a671998-12-07 16:23:42 +00001137 return FALSE;
1138 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001139 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001140 if (!full->long_name[0]) strcpy( full->long_name, "/" );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001141 if (!full->short_name[2]) strcpyW( full->short_name + 2, dos_rootW );
1142 TRACE("returning %s = %s\n", full->long_name, debugstr_w(full->short_name) );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001143 return TRUE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001144}
1145
1146
1147/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001148 * GetShortPathNameW (KERNEL32.@)
Juergen Schmied4658e4d1998-11-22 12:21:05 +00001149 *
1150 * NOTES
1151 * observed:
1152 * longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
Francois Gouget60a83ef2001-09-14 00:59:58 +00001153 * longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0
Vincent Béron9a624912002-05-31 23:06:46 +00001154 *
Peter Gantenf22bea01999-03-14 15:15:14 +00001155 * more observations ( with NT 3.51 (WinDD) ):
1156 * longpath <= 8.3 -> just copy longpath to shortpath
Vincent Béron9a624912002-05-31 23:06:46 +00001157 * longpath > 8.3 ->
Peter Gantenf22bea01999-03-14 15:15:14 +00001158 * a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND
1159 * b) file does exist -> set the short filename.
1160 * - trailing slashes are reproduced in the short name, even if the
1161 * file is not a directory
Peter Gantend580b831999-12-12 20:44:07 +00001162 * - the absolute/relative path of the short name is reproduced like found
1163 * in the long name
Francois Gouget60a83ef2001-09-14 00:59:58 +00001164 * - longpath and shortpath may have the same address
Peter Gantenf22bea01999-03-14 15:15:14 +00001165 * Peter Ganten, 1999
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001166 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001167DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001168{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001169 DOS_FULL_NAME full_name;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001170 WCHAR tmpshortpath[MAX_PATHNAME_LEN];
1171 const WCHAR *p;
Peter Gantend580b831999-12-12 20:44:07 +00001172 DWORD sp = 0, lp = 0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001173 int drive;
1174 DWORD tmplen;
Peter Gantend580b831999-12-12 20:44:07 +00001175 UINT flags;
Alexandre Julliard4c5c7e72002-06-21 19:00:13 +00001176 BOOL unixabsolute = *longpath == '/';
Peter Gantend580b831999-12-12 20:44:07 +00001177
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001178 TRACE("%s\n", debugstr_w(longpath));
Peter Gantenf22bea01999-03-14 15:15:14 +00001179
1180 if (!longpath) {
1181 SetLastError(ERROR_INVALID_PARAMETER);
1182 return 0;
1183 }
1184 if (!longpath[0]) {
1185 SetLastError(ERROR_BAD_PATHNAME);
1186 return 0;
1187 }
1188
Alexandre Julliard4c5c7e72002-06-21 19:00:13 +00001189 /* check for drive letter */
1190 if (!unixabsolute && longpath[1] == ':' ) {
1191 tmpshortpath[0] = longpath[0];
1192 tmpshortpath[1] = ':';
1193 sp = 2;
1194 }
1195
Peter Gantend580b831999-12-12 20:44:07 +00001196 if ( ( drive = DOSFS_GetPathDrive ( &longpath )) == -1 ) return 0;
1197 flags = DRIVE_GetFlags ( drive );
Peter Gantenf22bea01999-03-14 15:15:14 +00001198
Alexandre Julliard4c5c7e72002-06-21 19:00:13 +00001199 if (unixabsolute && drive != DRIVE_GetCurrentDrive()) {
1200 tmpshortpath[0] = drive + 'A';
1201 tmpshortpath[1] = ':';
1202 sp = 2;
1203 }
Michael Wetherell70c42d82002-05-08 00:29:17 +00001204
Peter Gantend580b831999-12-12 20:44:07 +00001205 while ( longpath[lp] ) {
Peter Gantenf22bea01999-03-14 15:15:14 +00001206
Peter Gantend580b831999-12-12 20:44:07 +00001207 /* check for path delimiters and reproduce them */
1208 if ( longpath[lp] == '\\' || longpath[lp] == '/' ) {
Vincent Béron9a624912002-05-31 23:06:46 +00001209 if (!sp || tmpshortpath[sp-1]!= '\\')
Uwe Bonnes61f572a2000-04-06 19:31:11 +00001210 {
1211 /* strip double "\\" */
1212 tmpshortpath[sp] = '\\';
1213 sp++;
1214 }
Uwe Bonnes40249c62000-05-12 21:45:52 +00001215 tmpshortpath[sp]=0;/*terminate string*/
Peter Gantend580b831999-12-12 20:44:07 +00001216 lp++;
Peter Gantenf22bea01999-03-14 15:15:14 +00001217 continue;
1218 }
1219
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001220 tmplen = 0;
1221 for(p = longpath + lp; *p && *p != '/' && *p != '\\'; p++)
1222 tmplen++;
1223 lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1);
Vincent Béron9a624912002-05-31 23:06:46 +00001224
Peter Gantend580b831999-12-12 20:44:07 +00001225 /* Check, if the current element is a valid dos name */
1226 if ( DOSFS_ValidDOSName ( longpath + lp, !(flags & DRIVE_CASE_SENSITIVE) ) ) {
1227 sp += tmplen;
1228 lp += tmplen;
1229 continue;
Peter Gantenf22bea01999-03-14 15:15:14 +00001230 }
Peter Gantend580b831999-12-12 20:44:07 +00001231
1232 /* Check if the file exists and use the existing file name */
1233 if ( DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001234 strcpyW(tmpshortpath + sp, strrchrW(full_name.short_name, '\\') + 1);
1235 sp += strlenW(tmpshortpath + sp);
Peter Gantend580b831999-12-12 20:44:07 +00001236 lp += tmplen;
1237 continue;
1238 }
1239
1240 TRACE("not found!\n" );
1241 SetLastError ( ERROR_FILE_NOT_FOUND );
1242 return 0;
Peter Gantenf22bea01999-03-14 15:15:14 +00001243 }
Uwe Bonnes61f572a2000-04-06 19:31:11 +00001244 tmpshortpath[sp] = 0;
Peter Gantend580b831999-12-12 20:44:07 +00001245
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001246 tmplen = strlenW(tmpshortpath) + 1;
1247 if (tmplen <= shortlen)
1248 {
1249 strcpyW(shortpath, tmpshortpath);
1250 TRACE("returning %s\n", debugstr_w(shortpath));
1251 tmplen--; /* length without 0 */
1252 }
Vincent Béron9a624912002-05-31 23:06:46 +00001253
Peter Gantend580b831999-12-12 20:44:07 +00001254 return tmplen;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001255}
1256
1257
1258/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001259 * GetShortPathNameA (KERNEL32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001260 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001261DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001262{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001263 UNICODE_STRING longpathW;
1264 WCHAR shortpathW[MAX_PATH];
1265 DWORD ret, retW;
Juergen Schmied4658e4d1998-11-22 12:21:05 +00001266
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001267 if (!longpath)
1268 {
1269 SetLastError(ERROR_INVALID_PARAMETER);
1270 return 0;
1271 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001272
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001273 TRACE("%s\n", debugstr_a(longpath));
Peter Gantenf22bea01999-03-14 15:15:14 +00001274
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001275 if (!RtlCreateUnicodeStringFromAsciiz(&longpathW, longpath))
1276 {
1277 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1278 return 0;
1279 }
1280
1281 retW = GetShortPathNameW(longpathW.Buffer, shortpathW, MAX_PATH);
1282
1283 if (!retW)
1284 ret = 0;
1285 else if (retW > MAX_PATH)
1286 {
1287 SetLastError(ERROR_FILENAME_EXCED_RANGE);
1288 ret = 0;
1289 }
1290 else
1291 {
1292 ret = WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, NULL, 0, NULL, NULL);
1293 if (ret <= shortlen)
1294 {
1295 WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, shortpath, shortlen, NULL, NULL);
1296 ret--; /* length without 0 */
1297 }
1298 }
1299
1300 RtlFreeUnicodeString(&longpathW);
Peter Gantenf22bea01999-03-14 15:15:14 +00001301 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001302}
1303
1304
1305/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001306 * GetLongPathNameW (KERNEL32.@)
Francois Gouget60a83ef2001-09-14 00:59:58 +00001307 *
1308 * NOTES
1309 * observed (Win2000):
1310 * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
1311 * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0
Alexandre Julliarde658d821997-11-30 17:45:40 +00001312 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001313DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen )
Alexandre Julliarde658d821997-11-30 17:45:40 +00001314{
1315 DOS_FULL_NAME full_name;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001316 const char *root;
1317 LPWSTR p;
1318 int drive;
1319 UINT codepage;
1320 DWORD ret, len = 0;
Francois Gouget60a83ef2001-09-14 00:59:58 +00001321
1322 if (!shortpath) {
1323 SetLastError(ERROR_INVALID_PARAMETER);
1324 return 0;
1325 }
1326 if (!shortpath[0]) {
1327 SetLastError(ERROR_PATH_NOT_FOUND);
1328 return 0;
1329 }
1330
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001331 TRACE("%s,%p,%ld\n", debugstr_w(shortpath), longpath, longlen);
1332
Mike McCormack963985b2002-07-19 03:17:19 +00001333 if(shortpath[0]=='\\' && shortpath[1]=='\\')
1334 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001335 ERR("UNC pathname %s\n",debugstr_w(shortpath));
1336 lstrcpynW( longpath, full_name.short_name, longlen );
1337 return strlenW(longpath);
Mike McCormack963985b2002-07-19 03:17:19 +00001338 }
1339
Alexandre Julliarde658d821997-11-30 17:45:40 +00001340 if (!DOSFS_GetFullName( shortpath, TRUE, &full_name )) return 0;
Petr Tomasek788a9f72000-02-20 19:14:17 +00001341
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001342 root = full_name.long_name;
1343 drive = DRIVE_FindDriveRoot(&root);
1344 codepage = DRIVE_GetCodepage(drive);
Petr Tomasek788a9f72000-02-20 19:14:17 +00001345
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001346 ret = MultiByteToWideChar(codepage, 0, root, -1, NULL, 0);
1347 ret += 3; /* A:\ */
1348 /* reproduce terminating slash */
1349 if (ret > 4) /* if not drive root */
1350 {
1351 len = strlenW(shortpath);
1352 if (shortpath[len - 1] == '\\' || shortpath[len - 1] == '/')
1353 len = 1;
Alexander Larssonc1190fe1998-10-11 13:57:09 +00001354 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001355 ret += len;
1356 if (ret <= longlen)
1357 {
1358 longpath[0] = 'A' + drive;
1359 longpath[1] = ':';
1360 MultiByteToWideChar(codepage, 0, root, -1, longpath + 2, longlen - 2);
1361 for (p = longpath; *p; p++) if (*p == '/') *p = '\\';
1362 if (len)
1363 {
1364 longpath[ret - 2] = '\\';
1365 longpath[ret - 1] = 0;
1366 }
1367 TRACE("returning %s\n", debugstr_w(longpath));
1368 ret--; /* length without 0 */
1369 }
1370 return ret;
Alexandre Julliarde658d821997-11-30 17:45:40 +00001371}
1372
1373
1374/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001375 * GetLongPathNameA (KERNEL32.@)
Alexandre Julliarde658d821997-11-30 17:45:40 +00001376 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001377DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen )
Alexandre Julliarde658d821997-11-30 17:45:40 +00001378{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001379 UNICODE_STRING shortpathW;
1380 WCHAR longpathW[MAX_PATH];
1381 DWORD ret, retW;
Alexandre Julliarde658d821997-11-30 17:45:40 +00001382
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001383 if (!shortpath)
Alexandre Julliarde658d821997-11-30 17:45:40 +00001384 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001385 SetLastError(ERROR_INVALID_PARAMETER);
1386 return 0;
Alexandre Julliarde658d821997-11-30 17:45:40 +00001387 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001388
1389 TRACE("%s\n", debugstr_a(shortpath));
1390
1391 if (!RtlCreateUnicodeStringFromAsciiz(&shortpathW, shortpath))
1392 {
1393 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1394 return 0;
1395 }
1396
1397 retW = GetLongPathNameW(shortpathW.Buffer, longpathW, MAX_PATH);
1398
1399 if (!retW)
1400 ret = 0;
1401 else if (retW > MAX_PATH)
1402 {
1403 SetLastError(ERROR_FILENAME_EXCED_RANGE);
1404 ret = 0;
1405 }
1406 else
1407 {
1408 ret = WideCharToMultiByte(CP_ACP, 0, longpathW, -1, NULL, 0, NULL, NULL);
1409 if (ret <= longlen)
1410 {
1411 WideCharToMultiByte(CP_ACP, 0, longpathW, -1, longpath, longlen, NULL, NULL);
1412 ret--; /* length without 0 */
1413 }
1414 }
1415
1416 RtlFreeUnicodeString(&shortpathW);
Alexandre Julliarde658d821997-11-30 17:45:40 +00001417 return ret;
1418}
1419
1420
1421/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001422 * DOSFS_DoGetFullPathName
1423 *
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001424 * Implementation of GetFullPathNameA/W.
Uwe Bonnes59b5f782000-02-27 13:58:12 +00001425 *
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001426 * bon@elektron 000331:
Vincent Béron9a624912002-05-31 23:06:46 +00001427 * A test for GetFullPathName with many pathological cases
Huw D M Daviesd0f8bfd2000-12-15 20:54:01 +00001428 * now gives identical output for Wine and OSR2
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001429 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001430static DWORD DOSFS_DoGetFullPathName( LPCWSTR name, DWORD len, LPWSTR result )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001431{
Juergen Schmied86407161999-01-03 16:12:01 +00001432 DWORD ret;
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001433 DOS_FULL_NAME full_name;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001434 LPWSTR p, q;
1435 char *p_l;
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001436 const char * root;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001437 WCHAR drivecur[] = {'C',':','.',0};
1438 WCHAR driveletter=0;
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001439 int namelen,drive=0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001440 static const WCHAR bkslashW[] = {'\\',0};
1441 static const WCHAR dotW[] = {'.',0};
1442 static const WCHAR updir_slashW[] = {'\\','.','.','\\',0};
1443 static const WCHAR curdirW[] = {'\\','.','\\',0};
1444 static const WCHAR updirW[] = {'\\','.','.',0};
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001445
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001446 if (!name[0])
1447 {
1448 SetLastError(ERROR_BAD_PATHNAME);
1449 return 0;
1450 }
Alexandre Julliard1bb69a02002-04-02 02:46:27 +00001451
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001452 TRACE("passed %s\n", debugstr_w(name));
Jason Edmeadesffb3d782002-05-05 21:01:43 +00001453
Alexandre Julliard1bb69a02002-04-02 02:46:27 +00001454 if (name[1]==':')
1455 /*drive letter given */
Uwe Bonnes59b5f782000-02-27 13:58:12 +00001456 {
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001457 driveletter = name[0];
1458 }
Alexandre Julliard1bb69a02002-04-02 02:46:27 +00001459 if ((name[1]==':') && ((name[2]=='\\') || (name[2]=='/')))
1460 /*absolute path given */
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001461 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001462 strncpyW(full_name.short_name, name, MAX_PATHNAME_LEN);
1463 full_name.short_name[MAX_PATHNAME_LEN - 1] = 0; /* ensure 0 termination */
1464 drive = toupperW(name[0]) - 'A';
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001465 }
1466 else
1467 {
1468 if (driveletter)
1469 drivecur[0]=driveletter;
Jason Edmeadesffb3d782002-05-05 21:01:43 +00001470 else if ((name[0]=='\\') || (name[0]=='/'))
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001471 strcpyW(drivecur, bkslashW);
Jason Edmeadesffb3d782002-05-05 21:01:43 +00001472 else
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001473 strcpyW(drivecur, dotW);
Jason Edmeadesffb3d782002-05-05 21:01:43 +00001474
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001475 if (!DOSFS_GetFullName( drivecur, FALSE, &full_name ))
1476 {
1477 FIXME("internal: error getting drive/path\n");
1478 return 0;
1479 }
1480 /* find path that drive letter substitutes*/
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001481 drive = toupperW(full_name.short_name[0]) - 'A';
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001482 root= DRIVE_GetRoot(drive);
Uwe Bonnes594a0dc2000-06-15 00:30:26 +00001483 if (!root)
1484 {
1485 FIXME("internal: error getting DOS Drive Root\n");
1486 return 0;
1487 }
Marcus Meissner7f0490e2000-10-23 00:37:06 +00001488 if (!strcmp(root,"/"))
1489 {
1490 /* we have just the last / and we need it. */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001491 p_l = full_name.long_name;
Marcus Meissner7f0490e2000-10-23 00:37:06 +00001492 }
1493 else
1494 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001495 p_l = full_name.long_name + strlen(root);
Marcus Meissner7f0490e2000-10-23 00:37:06 +00001496 }
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001497 /* append long name (= unix name) to drive */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001498 MultiByteToWideChar(DRIVE_GetCodepage(drive), 0, p_l, -1,
1499 full_name.short_name + 2, MAX_PATHNAME_LEN - 3);
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001500 /* append name to treat */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001501 namelen= strlenW(full_name.short_name);
1502 p = (LPWSTR)name;
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001503 if (driveletter)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001504 p += 2; /* skip drive name when appending */
1505 if (namelen + 2 + strlenW(p) > MAX_PATHNAME_LEN)
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001506 {
1507 FIXME("internal error: buffer too small\n");
1508 return 0;
1509 }
1510 full_name.short_name[namelen++] ='\\';
1511 full_name.short_name[namelen] = 0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001512 strncpyW(full_name.short_name + namelen, p, MAX_PATHNAME_LEN - namelen);
1513 full_name.short_name[MAX_PATHNAME_LEN - 1] = 0; /* ensure 0 termination */
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001514 }
1515 /* reverse all slashes */
1516 for (p=full_name.short_name;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001517 p < full_name.short_name + strlenW(full_name.short_name);
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001518 p++)
1519 {
1520 if ( *p == '/' )
1521 *p = '\\';
1522 }
Andreas Mohr9cef2d02001-11-19 02:30:01 +00001523 /* Use memmove, as areas overlap */
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001524 /* Delete .. */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001525 while ((p = strstrW(full_name.short_name, updir_slashW)))
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001526 {
1527 if (p > full_name.short_name+2)
1528 {
1529 *p = 0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001530 q = strrchrW(full_name.short_name, '\\');
1531 memmove(q+1, p+4, (strlenW(p+4)+1) * sizeof(WCHAR));
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001532 }
1533 else
1534 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001535 memmove(full_name.short_name+3, p+4, (strlenW(p+4)+1) * sizeof(WCHAR));
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001536 }
1537 }
1538 if ((full_name.short_name[2]=='.')&&(full_name.short_name[3]=='.'))
1539 {
1540 /* This case istn't treated yet : c:..\test */
1541 memmove(full_name.short_name+2,full_name.short_name+4,
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001542 (strlenW(full_name.short_name+4)+1) * sizeof(WCHAR));
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001543 }
1544 /* Delete . */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001545 while ((p = strstrW(full_name.short_name, curdirW)))
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001546 {
1547 *(p+1) = 0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001548 memmove(p+1, p+3, (strlenW(p+3)+1) * sizeof(WCHAR));
Uwe Bonnes59b5f782000-02-27 13:58:12 +00001549 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001550 if (!(DRIVE_GetFlags(drive) & DRIVE_CASE_PRESERVING))
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001551 for (p = full_name.short_name; *p; p++) *p = toupperW(*p);
1552 namelen = strlenW(full_name.short_name);
1553 if (!strcmpW(full_name.short_name+namelen-3, updirW))
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001554 {
Vincent Béron9a624912002-05-31 23:06:46 +00001555 /* one more strange case: "c:\test\test1\.."
Andreas Mohr9cef2d02001-11-19 02:30:01 +00001556 return "c:\test" */
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001557 *(full_name.short_name+namelen-3)=0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001558 q = strrchrW(full_name.short_name, '\\');
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001559 *q =0;
1560 }
1561 if (full_name.short_name[namelen-1]=='.')
1562 full_name.short_name[(namelen--)-1] =0;
1563 if (!driveletter)
1564 if (full_name.short_name[namelen-1]=='\\')
1565 full_name.short_name[(namelen--)-1] =0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001566 TRACE("got %s\n", debugstr_w(full_name.short_name));
Uwe Bonnesd3b890f2000-04-28 20:48:54 +00001567
Vincent Béron9a624912002-05-31 23:06:46 +00001568 /* If the lpBuffer buffer is too small, the return value is the
1569 size of the buffer, in characters, required to hold the path
Andreas Mohr9cef2d02001-11-19 02:30:01 +00001570 plus the terminating \0 (tested against win95osr2, bon 001118)
Uwe Bonnes59b5f782000-02-27 13:58:12 +00001571 . */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001572 ret = strlenW(full_name.short_name);
Uwe Bonnes59b5f782000-02-27 13:58:12 +00001573 if (ret >= len )
1574 {
1575 /* don't touch anything when the buffer is not large enough */
1576 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1577 return ret+1;
1578 }
Alexandre Julliard08b9b4f1999-06-06 17:09:21 +00001579 if (result)
1580 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001581 strncpyW( result, full_name.short_name, len );
1582 result[len - 1] = 0; /* ensure 0 termination */
Alexandre Julliard08b9b4f1999-06-06 17:09:21 +00001583 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001584
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001585 TRACE("returning %s\n", debugstr_w(full_name.short_name) );
Juergen Schmied86407161999-01-03 16:12:01 +00001586 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001587}
1588
1589
1590/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001591 * GetFullPathNameA (KERNEL32.@)
Juergen Schmied86407161999-01-03 16:12:01 +00001592 * NOTES
Vincent Béron9a624912002-05-31 23:06:46 +00001593 * if the path closed with '\', *lastpart is 0
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001594 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001595DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001596 LPSTR *lastpart )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001597{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001598 UNICODE_STRING nameW;
1599 WCHAR bufferW[MAX_PATH];
1600 DWORD ret, retW;
Juergen Schmied30f503f1998-12-15 17:28:26 +00001601
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001602 if (!name)
1603 {
1604 SetLastError(ERROR_INVALID_PARAMETER);
1605 return 0;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001606 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001607
1608 if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name))
1609 {
1610 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1611 return 0;
1612 }
1613
1614 retW = GetFullPathNameW( nameW.Buffer, MAX_PATH, bufferW, NULL);
1615
1616 if (!retW)
1617 ret = 0;
1618 else if (retW > MAX_PATH)
1619 {
1620 SetLastError(ERROR_FILENAME_EXCED_RANGE);
1621 ret = 0;
1622 }
1623 else
1624 {
1625 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1626 if (ret <= len)
1627 {
1628 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, len, NULL, NULL);
1629 ret--; /* length without 0 */
1630
1631 if (lastpart)
1632 {
1633 LPSTR p = buffer + strlen(buffer);
1634
1635 if (*p != '\\')
1636 {
1637 while ((p > buffer + 2) && (*p != '\\')) p--;
1638 *lastpart = p + 1;
1639 }
1640 else *lastpart = NULL;
1641 }
1642 }
1643 }
1644
1645 RtlFreeUnicodeString(&nameW);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001646 return ret;
1647}
1648
1649
1650/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001651 * GetFullPathNameW (KERNEL32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001652 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001653DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001654 LPWSTR *lastpart )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001655{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001656 DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer );
Uwe Bonnes59b5f782000-02-27 13:58:12 +00001657 if (ret && (ret<=len) && buffer && lastpart)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001658 {
Alexandre Julliarde101f6d2000-08-14 14:42:41 +00001659 LPWSTR p = buffer + strlenW(buffer);
Juergen Schmied86407161999-01-03 16:12:01 +00001660 if (*p != (WCHAR)'\\')
1661 {
1662 while ((p > buffer + 2) && (*p != (WCHAR)'\\')) p--;
1663 *lastpart = p + 1;
1664 }
Vincent Béron9a624912002-05-31 23:06:46 +00001665 else *lastpart = NULL;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001666 }
1667 return ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001668}
1669
Alexandre Julliard3a0f8b72000-12-01 20:48:41 +00001670
1671/***********************************************************************
Patrik Stridvall044855c2001-07-11 18:56:41 +00001672 * wine_get_unix_file_name (KERNEL32.@) Not a Windows API
Alexandre Julliard3a0f8b72000-12-01 20:48:41 +00001673 *
1674 * Return the full Unix file name for a given path.
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001675 * FIXME: convert dos file name to unicode
Alexandre Julliard3a0f8b72000-12-01 20:48:41 +00001676 */
1677BOOL WINAPI wine_get_unix_file_name( LPCSTR dos, LPSTR buffer, DWORD len )
1678{
1679 BOOL ret;
1680 DOS_FULL_NAME path;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001681 WCHAR dosW[MAX_PATHNAME_LEN];
1682
1683 MultiByteToWideChar(CP_ACP, 0, dos, -1, dosW, MAX_PATHNAME_LEN);
1684 ret = DOSFS_GetFullName( dosW, FALSE, &path );
1685 if (ret && len)
1686 {
1687 strncpy( buffer, path.long_name, len );
1688 buffer[len - 1] = 0; /* ensure 0 termination */
1689 }
Alexandre Julliard3a0f8b72000-12-01 20:48:41 +00001690 return ret;
1691}
1692
1693
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001694/***********************************************************************
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001695 * DOSFS_FindNextEx
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001696 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001697static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001698{
Andreas Mohr220312e2000-10-19 20:38:38 +00001699 DWORD attr = info->attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY | FILE_ATTRIBUTE_SYMLINK;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001700 UINT flags = DRIVE_GetFlags( info->drive );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001701 char *p, buffer[MAX_PATHNAME_LEN];
1702 const char *drive_path;
1703 int drive_root;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001704 LPCWSTR long_name, short_name;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001705 BY_HANDLE_FILE_INFORMATION fileinfo;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001706 WCHAR dos_name[13];
Alexandre Julliard1e37a181996-08-18 16:21:52 +00001707
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001708 if ((info->attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001709 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001710 if (info->cur_pos) return 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001711 entry->dwFileAttributes = FILE_ATTRIBUTE_LABEL;
Alexandre Julliard16688702002-09-12 22:28:01 +00001712 RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftCreationTime );
1713 RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftLastAccessTime );
1714 RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftLastWriteTime );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001715 entry->nFileSizeHigh = 0;
1716 entry->nFileSizeLow = 0;
1717 entry->dwReserved0 = 0;
1718 entry->dwReserved1 = 0;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001719 DOSFS_ToDosDTAFormat( DRIVE_GetLabel( info->drive ), entry->cFileName );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001720 strcpyW( entry->cAlternateFileName, entry->cFileName );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001721 info->cur_pos++;
Stefan Leichtereb0ab1b2000-08-18 23:45:46 +00001722 TRACE("returning %s (%s) as label\n",
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001723 debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName));
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001724 return 1;
1725 }
1726
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001727 drive_path = info->path + strlen(DRIVE_GetRoot( info->drive ));
1728 while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++;
1729 drive_root = !*drive_path;
1730
Alexandre Julliarda3960291999-02-26 11:11:13 +00001731 lstrcpynA( buffer, info->path, sizeof(buffer) - 1 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001732 strcat( buffer, "/" );
1733 p = buffer + strlen(buffer);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001734
Mike McCormack963985b2002-07-19 03:17:19 +00001735 while (DOSFS_ReadDir( info->u.dos_dir, &long_name, &short_name ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001736 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001737 info->cur_pos++;
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001738
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001739 /* Don't return '.' and '..' in the root of the drive */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001740 if (drive_root && (long_name[0] == '.') &&
1741 (!long_name[1] || ((long_name[1] == '.') && !long_name[2])))
1742 continue;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001743
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001744 /* Check the long mask */
1745
György 'Nog' Jeney4610c0a2002-09-27 22:03:44 +00001746 if (info->long_mask && *info->long_mask)
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001747 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001748 if (!DOSFS_MatchLong( info->long_mask, long_name,
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001749 flags & DRIVE_CASE_SENSITIVE )) continue;
1750 }
1751
1752 /* Check the short mask */
1753
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001754 if (info->short_mask)
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001755 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001756 if (!short_name)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001757 {
1758 DOSFS_Hash( long_name, dos_name, TRUE,
1759 !(flags & DRIVE_CASE_SENSITIVE) );
1760 short_name = dos_name;
1761 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001762 if (!DOSFS_MatchShort( info->short_mask, short_name )) continue;
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001763 }
1764
1765 /* Check the file attributes */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001766 WideCharToMultiByte(DRIVE_GetCodepage(info->drive), 0, long_name, -1,
1767 p, sizeof(buffer) - (int)(p - buffer), NULL, NULL);
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001768 if (!FILE_Stat( buffer, &fileinfo ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001769 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001770 WARN("can't stat %s\n", buffer);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001771 continue;
1772 }
Andreas Mohr220312e2000-10-19 20:38:38 +00001773 if ((fileinfo.dwFileAttributes & FILE_ATTRIBUTE_SYMLINK) &&
1774 (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1775 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001776 static const WCHAR wineW[] = {'w','i','n','e',0};
1777 static const WCHAR ShowDirSymlinksW[] = {'S','h','o','w','D','i','r','S','y','m','l','i','n','k','s',0};
Andreas Mohr220312e2000-10-19 20:38:38 +00001778 static int show_dir_symlinks = -1;
1779 if (show_dir_symlinks == -1)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001780 show_dir_symlinks = PROFILE_GetWineIniBool(wineW, ShowDirSymlinksW, 0);
Andreas Mohr220312e2000-10-19 20:38:38 +00001781 if (!show_dir_symlinks) continue;
1782 }
1783
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001784 if (fileinfo.dwFileAttributes & ~attr) continue;
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001785
1786 /* We now have a matching entry; fill the result and return */
1787
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001788 entry->dwFileAttributes = fileinfo.dwFileAttributes;
1789 entry->ftCreationTime = fileinfo.ftCreationTime;
1790 entry->ftLastAccessTime = fileinfo.ftLastAccessTime;
1791 entry->ftLastWriteTime = fileinfo.ftLastWriteTime;
1792 entry->nFileSizeHigh = fileinfo.nFileSizeHigh;
1793 entry->nFileSizeLow = fileinfo.nFileSizeLow;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001794
1795 if (short_name)
1796 DOSFS_ToDosDTAFormat( short_name, entry->cAlternateFileName );
1797 else
1798 DOSFS_Hash( long_name, entry->cAlternateFileName, FALSE,
1799 !(flags & DRIVE_CASE_SENSITIVE) );
1800
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001801 lstrcpynW( entry->cFileName, long_name, sizeof(entry->cFileName)/sizeof(entry->cFileName[0]) );
1802 if (!(flags & DRIVE_CASE_PRESERVING)) strlwrW( entry->cFileName );
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001803 TRACE("returning %s (%s) %02lx %ld\n",
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001804 debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName),
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001805 entry->dwFileAttributes, entry->nFileSizeLow );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001806 return 1;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001807 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001808 return 0; /* End of directory */
1809}
Alexandre Julliardca22b331996-07-12 19:02:39 +00001810
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001811/***********************************************************************
1812 * DOSFS_FindNext
1813 *
1814 * Find the next matching file. Return the number of entries read to find
1815 * the matching one, or 0 if no more entries.
1816 * 'short_mask' is the 8.3 mask (in FCB format), 'long_mask' is the long
1817 * file name mask. Either or both can be NULL.
1818 *
1819 * NOTE: This is supposed to be only called by the int21 emulation
1820 * routines. Thus, we should own the Win16Mutex anyway.
1821 * Nevertheless, we explicitly enter it to ensure the static
1822 * directory cache is protected.
1823 */
1824int DOSFS_FindNext( const char *path, const char *short_mask,
1825 const char *long_mask, int drive, BYTE attr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001826 int skip, WIN32_FIND_DATAA *entry )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001827{
Joerg Mayer959d73e2000-10-22 23:56:32 +00001828 static FIND_FIRST_INFO info;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001829 LPCWSTR short_name, long_name;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001830 int count;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001831 UNICODE_STRING short_maskW, long_maskW;
1832 WIN32_FIND_DATAW entryW;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001833
György 'Nog' Jeney4610c0a2002-09-27 22:03:44 +00001834 TRACE("(%s, %s, %s, %x, %x, %x, %p)\n", debugstr_a(path),
1835 debugstr_a(short_mask), debugstr_a(long_mask), drive, attr, skip,
1836 entry);
1837
Alexandre Julliardab687972000-11-15 23:41:46 +00001838 _EnterWin16Lock();
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001839
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001840 RtlCreateUnicodeStringFromAsciiz(&short_maskW, short_mask);
1841 RtlCreateUnicodeStringFromAsciiz(&long_maskW, long_mask);
1842
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001843 /* Check the cached directory */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001844 if (!(info.u.dos_dir && info.path == path && !strcmpW(info.short_mask, short_maskW.Buffer)
1845 && !strcmpW(info.long_mask, long_maskW.Buffer) && info.drive == drive
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001846 && info.attr == attr && info.cur_pos <= skip))
Vincent Béron9a624912002-05-31 23:06:46 +00001847 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001848 /* Not in the cache, open it anew */
Mike McCormack963985b2002-07-19 03:17:19 +00001849 if (info.u.dos_dir) DOSFS_CloseDir( info.u.dos_dir );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001850
1851 info.path = (LPSTR)path;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001852 RtlFreeHeap(GetProcessHeap(), 0, info.long_mask);
1853 RtlFreeHeap(GetProcessHeap(), 0, info.short_mask);
1854 info.long_mask = long_maskW.Buffer;
1855 info.short_mask = short_maskW.Buffer;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001856 info.attr = attr;
1857 info.drive = drive;
1858 info.cur_pos = 0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001859 info.u.dos_dir = DOSFS_OpenDir( DRIVE_GetCodepage(drive), info.path );
1860 }
1861 else
1862 {
1863 RtlFreeUnicodeString(&short_maskW);
1864 RtlFreeUnicodeString(&long_maskW);
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001865 }
1866
1867 /* Skip to desired position */
1868 while (info.cur_pos < skip)
Mike McCormack963985b2002-07-19 03:17:19 +00001869 if (info.u.dos_dir && DOSFS_ReadDir( info.u.dos_dir, &long_name, &short_name ))
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001870 info.cur_pos++;
1871 else
1872 break;
1873
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001874 if (info.u.dos_dir && info.cur_pos == skip && DOSFS_FindNextEx( &info, &entryW ))
1875 {
1876 WideCharToMultiByte(CP_ACP, 0, entryW.cFileName, -1,
1877 entry->cFileName, sizeof(entry->cFileName), NULL, NULL);
1878 WideCharToMultiByte(CP_ACP, 0, entryW.cAlternateFileName, -1,
1879 entry->cAlternateFileName, sizeof(entry->cAlternateFileName), NULL, NULL);
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001880 count = info.cur_pos - skip;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001881 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001882 else
1883 count = 0;
1884
1885 if (!count)
1886 {
Mike McCormack963985b2002-07-19 03:17:19 +00001887 if (info.u.dos_dir) DOSFS_CloseDir( info.u.dos_dir );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001888 memset( &info, '\0', sizeof(info) );
1889 }
1890
Alexandre Julliardab687972000-11-15 23:41:46 +00001891 _LeaveWin16Lock();
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001892
1893 return count;
1894}
1895
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001896/*************************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001897 * FindFirstFileExW (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001898 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001899HANDLE WINAPI FindFirstFileExW(
1900 LPCWSTR lpFileName,
Juergen Schmied2250f122000-06-01 23:17:42 +00001901 FINDEX_INFO_LEVELS fInfoLevelId,
1902 LPVOID lpFindFileData,
1903 FINDEX_SEARCH_OPS fSearchOp,
1904 LPVOID lpSearchFilter,
1905 DWORD dwAdditionalFlags)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001906{
Juergen Schmied2250f122000-06-01 23:17:42 +00001907 HGLOBAL handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001908 FIND_FIRST_INFO *info;
Vincent Béron9a624912002-05-31 23:06:46 +00001909
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001910 if (!lpFileName)
1911 {
1912 SetLastError(ERROR_PATH_NOT_FOUND);
1913 return INVALID_HANDLE_VALUE;
1914 }
1915
Juergen Schmied2250f122000-06-01 23:17:42 +00001916 if ((fSearchOp != FindExSearchNameMatch) || (dwAdditionalFlags != 0))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001917 {
Juergen Schmied2250f122000-06-01 23:17:42 +00001918 FIXME("options not implemented 0x%08x 0x%08lx\n", fSearchOp, dwAdditionalFlags );
1919 return INVALID_HANDLE_VALUE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001920 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001921
Juergen Schmied2250f122000-06-01 23:17:42 +00001922 switch(fInfoLevelId)
1923 {
1924 case FindExInfoStandard:
1925 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001926 WIN32_FIND_DATAW * data = (WIN32_FIND_DATAW *) lpFindFileData;
1927 char *p;
1928 INT long_mask_len;
1929 UINT codepage;
1930
Juergen Schmied2250f122000-06-01 23:17:42 +00001931 data->dwReserved0 = data->dwReserved1 = 0x0;
1932 if (!lpFileName) return 0;
Mike McCormack963985b2002-07-19 03:17:19 +00001933 if (lpFileName[0] == '\\' && lpFileName[1] == '\\')
1934 {
1935 ERR("UNC path name\n");
1936 if (!(handle = GlobalAlloc(GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO)))) break;
1937
1938 info = (FIND_FIRST_INFO *)GlobalLock( handle );
1939 info->u.smb_dir = SMB_FindFirst(lpFileName);
Marcus Meissner2a5c1462002-09-16 19:27:15 +00001940 if(!info->u.smb_dir)
Mike McCormack963985b2002-07-19 03:17:19 +00001941 {
1942 GlobalUnlock( handle );
1943 GlobalFree(handle);
1944 break;
1945 }
1946
1947 info->drive = -1;
1948
1949 GlobalUnlock( handle );
1950 }
1951 else
1952 {
1953 DOS_FULL_NAME full_name;
1954
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001955 if (!DOSFS_GetFullName( lpFileName, FALSE, &full_name )) break;
1956 if (!(handle = GlobalAlloc(GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO)))) break;
1957 info = (FIND_FIRST_INFO *)GlobalLock( handle );
1958 info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
1959 strcpy( info->path, full_name.long_name );
Juergen Schmied2250f122000-06-01 23:17:42 +00001960
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001961 codepage = DRIVE_GetCodepage(full_name.drive);
1962 p = strrchr( info->path, '/' );
1963 *p++ = '\0';
1964 long_mask_len = MultiByteToWideChar(codepage, 0, p, -1, NULL, 0);
1965 info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) );
1966 MultiByteToWideChar(codepage, 0, p, -1, info->long_mask, long_mask_len);
1967
1968 info->short_mask = NULL;
1969 info->attr = 0xff;
1970 info->drive = full_name.drive;
1971 info->cur_pos = 0;
1972
1973 info->u.dos_dir = DOSFS_OpenDir( codepage, info->path );
1974 GlobalUnlock( handle );
Mike McCormack963985b2002-07-19 03:17:19 +00001975 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001976 if (!FindNextFileW( handle, data ))
Juergen Schmied2250f122000-06-01 23:17:42 +00001977 {
1978 FindClose( handle );
1979 SetLastError( ERROR_NO_MORE_FILES );
1980 break;
1981 }
1982 return handle;
1983 }
1984 break;
1985 default:
1986 FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId );
1987 }
1988 return INVALID_HANDLE_VALUE;
1989}
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001990
1991/*************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001992 * FindFirstFileA (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001993 */
Juergen Schmied2250f122000-06-01 23:17:42 +00001994HANDLE WINAPI FindFirstFileA(
1995 LPCSTR lpFileName,
1996 WIN32_FIND_DATAA *lpFindData )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001997{
Juergen Schmied2250f122000-06-01 23:17:42 +00001998 return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
1999 FindExSearchNameMatch, NULL, 0);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002000}
2001
Juergen Schmied2250f122000-06-01 23:17:42 +00002002/*************************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002003 * FindFirstFileExA (KERNEL32.@)
Juergen Schmied2250f122000-06-01 23:17:42 +00002004 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002005HANDLE WINAPI FindFirstFileExA(
2006 LPCSTR lpFileName,
Juergen Schmied2250f122000-06-01 23:17:42 +00002007 FINDEX_INFO_LEVELS fInfoLevelId,
2008 LPVOID lpFindFileData,
2009 FINDEX_SEARCH_OPS fSearchOp,
2010 LPVOID lpSearchFilter,
2011 DWORD dwAdditionalFlags)
2012{
2013 HANDLE handle;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002014 WIN32_FIND_DATAA *dataA;
2015 WIN32_FIND_DATAW dataW;
2016 UNICODE_STRING pathW;
Juergen Schmied2250f122000-06-01 23:17:42 +00002017
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002018 if (!lpFileName)
Juergen Schmied2250f122000-06-01 23:17:42 +00002019 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002020 SetLastError(ERROR_PATH_NOT_FOUND);
Juergen Schmied2250f122000-06-01 23:17:42 +00002021 return INVALID_HANDLE_VALUE;
2022 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002023
2024 if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
2025 {
2026 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2027 return INVALID_HANDLE_VALUE;
2028 }
2029
2030 handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
2031 RtlFreeUnicodeString(&pathW);
2032 if (handle == INVALID_HANDLE_VALUE) return handle;
2033
2034 dataA = (WIN32_FIND_DATAA *) lpFindFileData;
2035 dataA->dwFileAttributes = dataW.dwFileAttributes;
2036 dataA->ftCreationTime = dataW.ftCreationTime;
2037 dataA->ftLastAccessTime = dataW.ftLastAccessTime;
2038 dataA->ftLastWriteTime = dataW.ftLastWriteTime;
2039 dataA->nFileSizeHigh = dataW.nFileSizeHigh;
2040 dataA->nFileSizeLow = dataW.nFileSizeLow;
2041 WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
2042 dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
2043 WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
2044 dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
Juergen Schmied2250f122000-06-01 23:17:42 +00002045 return handle;
2046}
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002047
2048/*************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002049 * FindFirstFileW (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002050 */
Juergen Schmied2250f122000-06-01 23:17:42 +00002051HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002052{
Juergen Schmied2250f122000-06-01 23:17:42 +00002053 return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
2054 FindExSearchNameMatch, NULL, 0);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002055}
2056
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002057/*************************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002058 * FindNextFileW (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002059 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002060BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002061{
2062 FIND_FIRST_INFO *info;
Mike McCormack963985b2002-07-19 03:17:19 +00002063 BOOL ret = FALSE;
Rein Klazese1db8bd2002-07-20 18:53:09 +00002064 DWORD gle = ERROR_NO_MORE_FILES;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002065
Vincent Béron9a624912002-05-31 23:06:46 +00002066 if ((handle == INVALID_HANDLE_VALUE) ||
Juergen Schmied2250f122000-06-01 23:17:42 +00002067 !(info = (FIND_FIRST_INFO *)GlobalLock( handle )))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002068 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00002069 SetLastError( ERROR_INVALID_HANDLE );
Mike McCormack963985b2002-07-19 03:17:19 +00002070 return ret;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002071 }
Mike McCormack963985b2002-07-19 03:17:19 +00002072 if (info->drive == -1)
2073 {
2074 ret = SMB_FindNext( info->u.smb_dir, data );
2075 if(!ret)
2076 {
2077 SMB_CloseDir( info->u.smb_dir );
2078 HeapFree( GetProcessHeap(), 0, info->path );
Mike McCormack963985b2002-07-19 03:17:19 +00002079 }
2080 goto done;
2081 }
2082 else if (!info->path || !info->u.dos_dir)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002083 {
Rein Klazese1db8bd2002-07-20 18:53:09 +00002084 goto done;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002085 }
Mike McCormack963985b2002-07-19 03:17:19 +00002086 else if (!DOSFS_FindNextEx( info, data ))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002087 {
Mike McCormack963985b2002-07-19 03:17:19 +00002088 DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL;
Alexandre Julliard90476d62000-02-16 22:47:24 +00002089 HeapFree( GetProcessHeap(), 0, info->path );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002090 info->path = NULL;
2091 HeapFree( GetProcessHeap(), 0, info->long_mask );
2092 info->long_mask = NULL;
2093 goto done;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002094 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002095 ret = TRUE;
Mike McCormack963985b2002-07-19 03:17:19 +00002096done:
2097 GlobalUnlock( handle );
Rein Klazese1db8bd2002-07-20 18:53:09 +00002098 if( !ret ) SetLastError( gle );
Mike McCormack963985b2002-07-19 03:17:19 +00002099 return ret;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002100}
2101
2102
2103/*************************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002104 * FindNextFileA (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002105 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002106BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002107{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002108 WIN32_FIND_DATAW dataW;
2109 if (!FindNextFileW( handle, &dataW )) return FALSE;
2110 data->dwFileAttributes = dataW.dwFileAttributes;
2111 data->ftCreationTime = dataW.ftCreationTime;
2112 data->ftLastAccessTime = dataW.ftLastAccessTime;
2113 data->ftLastWriteTime = dataW.ftLastWriteTime;
2114 data->nFileSizeHigh = dataW.nFileSizeHigh;
2115 data->nFileSizeLow = dataW.nFileSizeLow;
2116 WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
2117 data->cFileName, sizeof(data->cFileName), NULL, NULL );
2118 WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
Alexandre Julliard072dfb52000-09-25 23:30:56 +00002119 data->cAlternateFileName,
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002120 sizeof(data->cAlternateFileName), NULL, NULL );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002121 return TRUE;
2122}
2123
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002124/*************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002125 * FindClose (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002126 */
Juergen Schmied2250f122000-06-01 23:17:42 +00002127BOOL WINAPI FindClose( HANDLE handle )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002128{
2129 FIND_FIRST_INFO *info;
2130
Marcus Meissner77fbbcf2002-05-04 18:28:36 +00002131 if (handle == INVALID_HANDLE_VALUE) goto error;
2132
Dominik Strasser4f46b5d2001-04-20 18:38:41 +00002133 __TRY
2134 {
Marcus Meissner77fbbcf2002-05-04 18:28:36 +00002135 if ((info = (FIND_FIRST_INFO *)GlobalLock( handle )))
2136 {
Mike McCormack963985b2002-07-19 03:17:19 +00002137 if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir );
Marcus Meissner77fbbcf2002-05-04 18:28:36 +00002138 if (info->path) HeapFree( GetProcessHeap(), 0, info->path );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002139 if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask );
Marcus Meissner77fbbcf2002-05-04 18:28:36 +00002140 }
Dominik Strasser4f46b5d2001-04-20 18:38:41 +00002141 }
2142 __EXCEPT(page_fault)
2143 {
2144 WARN("Illegal handle %x\n", handle);
2145 SetLastError( ERROR_INVALID_HANDLE );
2146 return FALSE;
2147 }
2148 __ENDTRY
Marcus Meissner77fbbcf2002-05-04 18:28:36 +00002149 if (!info) goto error;
Juergen Schmied2250f122000-06-01 23:17:42 +00002150 GlobalUnlock( handle );
2151 GlobalFree( handle );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002152 return TRUE;
Marcus Meissner77fbbcf2002-05-04 18:28:36 +00002153
2154 error:
2155 SetLastError( ERROR_INVALID_HANDLE );
2156 return FALSE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002157}
2158
Alexandre Julliardca22b331996-07-12 19:02:39 +00002159/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002160 * DOSFS_UnixTimeToFileTime
2161 *
2162 * Convert a Unix time to FILETIME format.
2163 * The FILETIME structure is a 64-bit value representing the number of
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002164 * 100-nanosecond intervals since January 1, 1601, 0:00.
2165 * 'remainder' is the nonnegative number of 100-ns intervals
2166 * corresponding to the time fraction smaller than 1 second that
2167 * couldn't be stored in the time_t value.
Alexandre Julliardca22b331996-07-12 19:02:39 +00002168 */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002169void DOSFS_UnixTimeToFileTime( time_t unix_time, FILETIME *filetime,
2170 DWORD remainder )
Alexandre Julliardca22b331996-07-12 19:02:39 +00002171{
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002172 /* NOTES:
2173
Vincent Béron9a624912002-05-31 23:06:46 +00002174 CONSTANTS:
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002175 The time difference between 1 January 1601, 00:00:00 and
2176 1 January 1970, 00:00:00 is 369 years, plus the leap years
2177 from 1604 to 1968, excluding 1700, 1800, 1900.
2178 This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
2179 of 134774 days.
2180
2181 Any day in that period had 24 * 60 * 60 = 86400 seconds.
2182
2183 The time difference is 134774 * 86400 * 10000000, which can be written
2184 116444736000000000
2185 27111902 * 2^32 + 3577643008
2186 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768
2187
2188 If you find that these constants are buggy, please change them in all
2189 instances in both conversion functions.
2190
2191 VERSIONS:
2192 There are two versions, one of them uses long long variables and
2193 is presumably faster but not ISO C. The other one uses standard C
2194 data types and operations but relies on the assumption that negative
2195 numbers are stored as 2's complement (-1 is 0xffff....). If this
2196 assumption is violated, dates before 1970 will not convert correctly.
2197 This should however work on any reasonable architecture where WINE
2198 will run.
2199
2200 DETAILS:
Vincent Béron9a624912002-05-31 23:06:46 +00002201
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002202 Take care not to remove the casts. I have tested these functions
2203 (in both versions) for a lot of numbers. I would be interested in
2204 results on other compilers than GCC.
2205
2206 The operations have been designed to account for the possibility
2207 of 64-bit time_t in future UNICES. Even the versions without
2208 internal long long numbers will work if time_t only is 64 bit.
2209 A 32-bit shift, which was necessary for that operation, turned out
2210 not to work correctly in GCC, besides giving the warning. So I
2211 used a double 16-bit shift instead. Numbers are in the ISO version
2212 represented by three limbs, the most significant with 32 bit, the
2213 other two with 16 bit each.
2214
2215 As the modulo-operator % is not well-defined for negative numbers,
2216 negative divisors have been avoided in DOSFS_FileTimeToUnixTime.
2217
2218 There might be quicker ways to do this in C. Certainly so in
2219 assembler.
2220
2221 Claus Fischer, fischer@iue.tuwien.ac.at
2222 */
2223
Patrik Stridvall96336321999-10-24 22:13:47 +00002224#if SIZEOF_LONG_LONG >= 8
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002225# define USE_LONG_LONG 1
2226#else
2227# define USE_LONG_LONG 0
2228#endif
2229
2230#if USE_LONG_LONG /* gcc supports long long type */
2231
2232 long long int t = unix_time;
2233 t *= 10000000;
2234 t += 116444736000000000LL;
2235 t += remainder;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002236 filetime->dwLowDateTime = (UINT)t;
2237 filetime->dwHighDateTime = (UINT)(t >> 32);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002238
2239#else /* ISO version */
2240
Alexandre Julliarda3960291999-02-26 11:11:13 +00002241 UINT a0; /* 16 bit, low bits */
2242 UINT a1; /* 16 bit, medium bits */
2243 UINT a2; /* 32 bit, high bits */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002244
2245 /* Copy the unix time to a2/a1/a0 */
2246 a0 = unix_time & 0xffff;
2247 a1 = (unix_time >> 16) & 0xffff;
2248 /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
2249 Do not replace this by >> 32, it gives a compiler warning and it does
2250 not work. */
2251 a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 :
2252 ~((~unix_time >> 16) >> 16));
2253
2254 /* Multiply a by 10000000 (a = a2/a1/a0)
2255 Split the factor into 10000 * 1000 which are both less than 0xffff. */
2256 a0 *= 10000;
2257 a1 = a1 * 10000 + (a0 >> 16);
2258 a2 = a2 * 10000 + (a1 >> 16);
2259 a0 &= 0xffff;
2260 a1 &= 0xffff;
2261
2262 a0 *= 1000;
2263 a1 = a1 * 1000 + (a0 >> 16);
2264 a2 = a2 * 1000 + (a1 >> 16);
2265 a0 &= 0xffff;
2266 a1 &= 0xffff;
2267
2268 /* Add the time difference and the remainder */
2269 a0 += 32768 + (remainder & 0xffff);
2270 a1 += 54590 + (remainder >> 16 ) + (a0 >> 16);
2271 a2 += 27111902 + (a1 >> 16);
2272 a0 &= 0xffff;
2273 a1 &= 0xffff;
2274
2275 /* Set filetime */
2276 filetime->dwLowDateTime = (a1 << 16) + a0;
2277 filetime->dwHighDateTime = a2;
2278#endif
Alexandre Julliardca22b331996-07-12 19:02:39 +00002279}
2280
2281
2282/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002283 * DOSFS_FileTimeToUnixTime
2284 *
2285 * Convert a FILETIME format to Unix time.
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002286 * If not NULL, 'remainder' contains the fractional part of the filetime,
2287 * in the range of [0..9999999] (even if time_t is negative).
Alexandre Julliardca22b331996-07-12 19:02:39 +00002288 */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002289time_t DOSFS_FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder )
Alexandre Julliardca22b331996-07-12 19:02:39 +00002290{
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002291 /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
2292#if USE_LONG_LONG
2293
2294 long long int t = filetime->dwHighDateTime;
2295 t <<= 32;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002296 t += (UINT)filetime->dwLowDateTime;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002297 t -= 116444736000000000LL;
2298 if (t < 0)
2299 {
2300 if (remainder) *remainder = 9999999 - (-t - 1) % 10000000;
2301 return -1 - ((-t - 1) / 10000000);
2302 }
2303 else
2304 {
2305 if (remainder) *remainder = t % 10000000;
2306 return t / 10000000;
2307 }
2308
2309#else /* ISO version */
2310
Alexandre Julliarda3960291999-02-26 11:11:13 +00002311 UINT a0; /* 16 bit, low bits */
2312 UINT a1; /* 16 bit, medium bits */
2313 UINT a2; /* 32 bit, high bits */
2314 UINT r; /* remainder of division */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002315 unsigned int carry; /* carry bit for subtraction */
2316 int negative; /* whether a represents a negative value */
2317
2318 /* Copy the time values to a2/a1/a0 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002319 a2 = (UINT)filetime->dwHighDateTime;
2320 a1 = ((UINT)filetime->dwLowDateTime ) >> 16;
2321 a0 = ((UINT)filetime->dwLowDateTime ) & 0xffff;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002322
2323 /* Subtract the time difference */
2324 if (a0 >= 32768 ) a0 -= 32768 , carry = 0;
2325 else a0 += (1 << 16) - 32768 , carry = 1;
2326
2327 if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0;
2328 else a1 += (1 << 16) - 54590 - carry, carry = 1;
2329
2330 a2 -= 27111902 + carry;
Vincent Béron9a624912002-05-31 23:06:46 +00002331
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002332 /* If a is negative, replace a by (-1-a) */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002333 negative = (a2 >= ((UINT)1) << 31);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002334 if (negative)
2335 {
2336 /* Set a to -a - 1 (a is a2/a1/a0) */
2337 a0 = 0xffff - a0;
2338 a1 = 0xffff - a1;
2339 a2 = ~a2;
2340 }
2341
2342 /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
2343 Split the divisor into 10000 * 1000 which are both less than 0xffff. */
2344 a1 += (a2 % 10000) << 16;
2345 a2 /= 10000;
2346 a0 += (a1 % 10000) << 16;
2347 a1 /= 10000;
2348 r = a0 % 10000;
2349 a0 /= 10000;
2350
2351 a1 += (a2 % 1000) << 16;
2352 a2 /= 1000;
2353 a0 += (a1 % 1000) << 16;
2354 a1 /= 1000;
2355 r += (a0 % 1000) * 10000;
2356 a0 /= 1000;
2357
2358 /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
2359 if (negative)
2360 {
2361 /* Set a to -a - 1 (a is a2/a1/a0) */
2362 a0 = 0xffff - a0;
2363 a1 = 0xffff - a1;
2364 a2 = ~a2;
2365
2366 r = 9999999 - r;
2367 }
2368
2369 if (remainder) *remainder = r;
2370
2371 /* Do not replace this by << 32, it gives a compiler warning and it does
2372 not work. */
2373 return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0;
2374#endif
Alexandre Julliardb1bac321996-12-15 19:45:59 +00002375}
2376
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002377
2378/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002379 * MulDiv (KERNEL32.@)
Alexandre Julliard15467bf2000-08-01 22:03:18 +00002380 * RETURNS
2381 * Result of multiplication and division
2382 * -1: Overflow occurred or Divisor was 0
2383 */
2384INT WINAPI MulDiv(
Vincent Béron9a624912002-05-31 23:06:46 +00002385 INT nMultiplicand,
Alexandre Julliard15467bf2000-08-01 22:03:18 +00002386 INT nMultiplier,
2387 INT nDivisor)
2388{
2389#if SIZEOF_LONG_LONG >= 8
2390 long long ret;
2391
2392 if (!nDivisor) return -1;
2393
2394 /* We want to deal with a positive divisor to simplify the logic. */
2395 if (nDivisor < 0)
2396 {
2397 nMultiplicand = - nMultiplicand;
2398 nDivisor = -nDivisor;
2399 }
2400
2401 /* If the result is positive, we "add" to round. else, we subtract to round. */
2402 if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) ||
2403 ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
2404 ret = (((long long)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
2405 else
2406 ret = (((long long)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
2407
2408 if ((ret > 2147483647) || (ret < -2147483647)) return -1;
2409 return ret;
2410#else
2411 if (!nDivisor) return -1;
2412
2413 /* We want to deal with a positive divisor to simplify the logic. */
2414 if (nDivisor < 0)
2415 {
2416 nMultiplicand = - nMultiplicand;
2417 nDivisor = -nDivisor;
2418 }
2419
2420 /* If the result is positive, we "add" to round. else, we subtract to round. */
2421 if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) ||
2422 ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
2423 return ((nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
Vincent Béron9a624912002-05-31 23:06:46 +00002424
Alexandre Julliard15467bf2000-08-01 22:03:18 +00002425 return ((nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
Vincent Béron9a624912002-05-31 23:06:46 +00002426
Alexandre Julliard15467bf2000-08-01 22:03:18 +00002427#endif
2428}
2429
2430
2431/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002432 * DosDateTimeToFileTime (KERNEL32.@)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002433 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002434BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, LPFILETIME ft)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002435{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002436 struct tm newtm;
Vincent Bérona0322772002-05-30 20:05:48 +00002437#ifndef HAVE_TIMEGM
2438 struct tm *gtm;
2439 time_t time1, time2;
2440#endif
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002441
2442 newtm.tm_sec = (fattime & 0x1f) * 2;
2443 newtm.tm_min = (fattime >> 5) & 0x3f;
2444 newtm.tm_hour = (fattime >> 11);
2445 newtm.tm_mday = (fatdate & 0x1f);
2446 newtm.tm_mon = ((fatdate >> 5) & 0x0f) - 1;
2447 newtm.tm_year = (fatdate >> 9) + 80;
Vincent Bérona0322772002-05-30 20:05:48 +00002448#ifdef HAVE_TIMEGM
Alexandre Julliard16688702002-09-12 22:28:01 +00002449 RtlSecondsSince1970ToTime( timegm(&newtm), (LARGE_INTEGER *)ft );
Vincent Bérona0322772002-05-30 20:05:48 +00002450#else
2451 time1 = mktime(&newtm);
2452 gtm = gmtime(&time1);
2453 time2 = mktime(gtm);
Alexandre Julliard16688702002-09-12 22:28:01 +00002454 RtlSecondsSince1970ToTime( 2*time1-time2, (LARGE_INTEGER *)ft );
Vincent Bérona0322772002-05-30 20:05:48 +00002455#endif
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002456 return TRUE;
2457}
2458
2459
2460/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002461 * FileTimeToDosDateTime (KERNEL32.@)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002462 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002463BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002464 LPWORD fattime )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002465{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002466 time_t unixtime = DOSFS_FileTimeToUnixTime( ft, NULL );
Vincent Bérona0322772002-05-30 20:05:48 +00002467 struct tm *tm = gmtime( &unixtime );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002468 if (fattime)
2469 *fattime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2);
2470 if (fatdate)
2471 *fatdate = ((tm->tm_year - 80) << 9) + ((tm->tm_mon + 1) << 5)
2472 + tm->tm_mday;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002473 return TRUE;
2474}
2475
2476
2477/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002478 * LocalFileTimeToFileTime (KERNEL32.@)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002479 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002480BOOL WINAPI LocalFileTimeToFileTime( const FILETIME *localft,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002481 LPFILETIME utcft )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002482{
2483 struct tm *xtm;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002484 DWORD remainder;
Vincent Bérona0322772002-05-30 20:05:48 +00002485 time_t utctime;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002486
Vincent Bérona0322772002-05-30 20:05:48 +00002487 /* Converts from local to UTC. */
2488 time_t localtime = DOSFS_FileTimeToUnixTime( localft, &remainder );
2489 xtm = gmtime( &localtime );
2490 utctime = mktime(xtm);
2491 if(xtm->tm_isdst > 0) utctime-=3600;
2492 DOSFS_UnixTimeToFileTime( utctime, utcft, remainder );
Vincent Béron9a624912002-05-31 23:06:46 +00002493 return TRUE;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002494}
2495
2496
2497/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002498 * FileTimeToLocalFileTime (KERNEL32.@)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002499 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002500BOOL WINAPI FileTimeToLocalFileTime( const FILETIME *utcft,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002501 LPFILETIME localft )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002502{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002503 DWORD remainder;
Vincent Bérona0322772002-05-30 20:05:48 +00002504 /* Converts from UTC to local. */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002505 time_t unixtime = DOSFS_FileTimeToUnixTime( utcft, &remainder );
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002506#ifdef HAVE_TIMEGM
2507 struct tm *xtm = localtime( &unixtime );
2508 time_t localtime;
2509
2510 localtime = timegm(xtm);
2511 DOSFS_UnixTimeToFileTime( localtime, localft, remainder );
2512
2513#else
Vincent Bérona0322772002-05-30 20:05:48 +00002514 struct tm *xtm;
2515 time_t time;
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002516
Vincent Bérona0322772002-05-30 20:05:48 +00002517 xtm = gmtime( &unixtime );
2518 time = mktime(xtm);
2519 if(xtm->tm_isdst > 0) time-=3600;
2520 DOSFS_UnixTimeToFileTime( 2*unixtime-time, localft, remainder );
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002521#endif
Vincent Béron9a624912002-05-31 23:06:46 +00002522 return TRUE;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002523}
2524
2525
2526/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002527 * FileTimeToSystemTime (KERNEL32.@)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002528 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002529BOOL WINAPI FileTimeToSystemTime( const FILETIME *ft, LPSYSTEMTIME syst )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002530{
2531 struct tm *xtm;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002532 DWORD remainder;
2533 time_t xtime = DOSFS_FileTimeToUnixTime( ft, &remainder );
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002534 xtm = gmtime(&xtime);
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002535 syst->wYear = xtm->tm_year+1900;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +00002536 syst->wMonth = xtm->tm_mon + 1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002537 syst->wDayOfWeek = xtm->tm_wday;
2538 syst->wDay = xtm->tm_mday;
2539 syst->wHour = xtm->tm_hour;
2540 syst->wMinute = xtm->tm_min;
2541 syst->wSecond = xtm->tm_sec;
2542 syst->wMilliseconds = remainder / 10000;
Vincent Béron9a624912002-05-31 23:06:46 +00002543 return TRUE;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002544}
2545
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002546/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002547 * QueryDosDeviceA (KERNEL32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002548 *
2549 * returns array of strings terminated by \0, terminated by \0
2550 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002551DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002552{
2553 LPSTR s;
2554 char buffer[200];
2555
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002556 TRACE("(%s,...)\n", devname ? devname : "<null>");
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002557 if (!devname) {
2558 /* return known MSDOS devices */
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00002559 static const char devices[24] = "CON\0COM1\0COM2\0LPT1\0NUL\0\0";
2560 memcpy( target, devices, min(bufsize,sizeof(devices)) );
2561 return min(bufsize,sizeof(devices));
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002562 }
Marcus Meissner04d5efd2001-05-25 20:39:45 +00002563 /* In theory all that are possible and have been defined.
2564 * Now just those below, since mirc uses it to check for special files.
2565 *
Vincent Béron9a624912002-05-31 23:06:46 +00002566 * (It is more complex, and supports netmounted stuff, and \\.\ stuff,
Marcus Meissner04d5efd2001-05-25 20:39:45 +00002567 * but currently we just ignore that.)
2568 */
2569#define CHECK(x) (strstr(devname,#x)==devname)
2570 if (CHECK(con) || CHECK(com) || CHECK(lpt) || CHECK(nul)) {
2571 strcpy(buffer,"\\DEV\\");
2572 strcat(buffer,devname);
2573 if ((s=strchr(buffer,':'))) *s='\0';
2574 lstrcpynA(target,buffer,bufsize);
2575 return strlen(buffer)+1;
2576 } else {
2577 if (strchr(devname,':') || devname[0]=='\\') {
2578 /* This might be a DOS device we do not handle yet ... */
2579 FIXME("(%s) not detected as DOS device!\n",devname);
2580 }
2581 SetLastError(ERROR_DEV_NOT_EXIST);
2582 return 0;
2583 }
2584
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002585}
2586
2587
2588/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002589 * QueryDosDeviceW (KERNEL32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002590 *
2591 * returns array of strings terminated by \0, terminated by \0
2592 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002593DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002594{
2595 LPSTR devnameA = devname?HEAP_strdupWtoA(GetProcessHeap(),0,devname):NULL;
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +00002596 LPSTR targetA = (LPSTR)HeapAlloc(GetProcessHeap(),0,bufsize);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002597 DWORD ret = QueryDosDeviceA(devnameA,targetA,bufsize);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002598
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00002599 ret = MultiByteToWideChar( CP_ACP, 0, targetA, ret, target, bufsize );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002600 if (devnameA) HeapFree(GetProcessHeap(),0,devnameA);
2601 if (targetA) HeapFree(GetProcessHeap(),0,targetA);
2602 return ret;
2603}
2604
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002605
2606/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002607 * SystemTimeToFileTime (KERNEL32.@)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002608 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002609BOOL WINAPI SystemTimeToFileTime( const SYSTEMTIME *syst, LPFILETIME ft )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002610{
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002611#ifdef HAVE_TIMEGM
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002612 struct tm xtm;
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002613 time_t utctime;
2614#else
Vincent Bérona0322772002-05-30 20:05:48 +00002615 struct tm xtm,*utc_tm;
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002616 time_t localtim,utctime;
2617#endif
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002618
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002619 xtm.tm_year = syst->wYear-1900;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +00002620 xtm.tm_mon = syst->wMonth - 1;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002621 xtm.tm_wday = syst->wDayOfWeek;
2622 xtm.tm_mday = syst->wDay;
2623 xtm.tm_hour = syst->wHour;
2624 xtm.tm_min = syst->wMinute;
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002625 xtm.tm_sec = syst->wSecond; /* this is UTC */
2626 xtm.tm_isdst = -1;
2627#ifdef HAVE_TIMEGM
2628 utctime = timegm(&xtm);
Vincent Béron9a624912002-05-31 23:06:46 +00002629 DOSFS_UnixTimeToFileTime( utctime, ft,
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002630 syst->wMilliseconds * 10000 );
2631#else
2632 localtim = mktime(&xtm); /* now we've got local time */
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002633 utc_tm = gmtime(&localtim);
2634 utctime = mktime(utc_tm);
Vincent Béron9a624912002-05-31 23:06:46 +00002635 DOSFS_UnixTimeToFileTime( 2*localtim -utctime, ft,
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002636 syst->wMilliseconds * 10000 );
2637#endif
Vincent Béron9a624912002-05-31 23:06:46 +00002638 return TRUE;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002639}
Marcus Meissner575a1651998-10-21 16:47:29 +00002640
Patrik Stridvall3a9c4761999-10-31 02:07:05 +00002641/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002642 * DefineDosDeviceA (KERNEL32.@)
Patrik Stridvall3a9c4761999-10-31 02:07:05 +00002643 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002644BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002645 FIXME("(0x%08lx,%s,%s),stub!\n",flags,devname,targetpath);
Marcus Meissner575a1651998-10-21 16:47:29 +00002646 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2647 return FALSE;
2648}
Juergen Schmied2250f122000-06-01 23:17:42 +00002649
2650/*
2651 --- 16 bit functions ---
2652*/
2653
2654/*************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002655 * FindFirstFile (KERNEL.413)
Juergen Schmied2250f122000-06-01 23:17:42 +00002656 */
2657HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data )
2658{
2659 DOS_FULL_NAME full_name;
2660 HGLOBAL16 handle;
2661 FIND_FIRST_INFO *info;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002662 WCHAR pathW[MAX_PATH];
2663 char *p;
2664 INT long_mask_len;
2665 UINT codepage;
Juergen Schmied2250f122000-06-01 23:17:42 +00002666
2667 data->dwReserved0 = data->dwReserved1 = 0x0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002668 if (!path) return INVALID_HANDLE_VALUE16;
2669 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, MAX_PATH);
2670 if (!DOSFS_GetFullName( pathW, FALSE, &full_name ))
Juergen Schmied2250f122000-06-01 23:17:42 +00002671 return INVALID_HANDLE_VALUE16;
2672 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO) )))
2673 return INVALID_HANDLE_VALUE16;
2674 info = (FIND_FIRST_INFO *)GlobalLock16( handle );
Alexandre Julliard5f728ca2001-07-24 21:45:22 +00002675 info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
2676 strcpy( info->path, full_name.long_name );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002677
2678 codepage = DRIVE_GetCodepage(full_name.drive);
2679 p = strrchr( info->path, '/' );
2680 *p++ = '\0';
2681 long_mask_len = MultiByteToWideChar(codepage, 0, p, -1, NULL, 0);
2682 info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) );
2683 MultiByteToWideChar(codepage, 0, p, -1, info->long_mask, long_mask_len);
2684
Juergen Schmied2250f122000-06-01 23:17:42 +00002685 info->short_mask = NULL;
2686 info->attr = 0xff;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002687 info->drive = full_name.drive;
Juergen Schmied2250f122000-06-01 23:17:42 +00002688 info->cur_pos = 0;
2689
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002690 info->u.dos_dir = DOSFS_OpenDir( codepage, info->path );
Juergen Schmied2250f122000-06-01 23:17:42 +00002691
2692 GlobalUnlock16( handle );
2693 if (!FindNextFile16( handle, data ))
2694 {
2695 FindClose16( handle );
2696 SetLastError( ERROR_NO_MORE_FILES );
2697 return INVALID_HANDLE_VALUE16;
2698 }
2699 return handle;
2700}
2701
2702/*************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002703 * FindNextFile (KERNEL.414)
Juergen Schmied2250f122000-06-01 23:17:42 +00002704 */
2705BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data )
2706{
2707 FIND_FIRST_INFO *info;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002708 WIN32_FIND_DATAW dataW;
2709 BOOL ret = FALSE;
2710 DWORD gle = ERROR_NO_MORE_FILES;
Juergen Schmied2250f122000-06-01 23:17:42 +00002711
2712 if ((handle == INVALID_HANDLE_VALUE16) ||
2713 !(info = (FIND_FIRST_INFO *)GlobalLock16( handle )))
2714 {
2715 SetLastError( ERROR_INVALID_HANDLE );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002716 return ret;
Juergen Schmied2250f122000-06-01 23:17:42 +00002717 }
Mike McCormack963985b2002-07-19 03:17:19 +00002718 if (!info->path || !info->u.dos_dir)
Juergen Schmied2250f122000-06-01 23:17:42 +00002719 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002720 goto done;
Juergen Schmied2250f122000-06-01 23:17:42 +00002721 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002722 if (!DOSFS_FindNextEx( info, &dataW ))
Juergen Schmied2250f122000-06-01 23:17:42 +00002723 {
Mike McCormack963985b2002-07-19 03:17:19 +00002724 DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL;
Alexandre Julliard61d32b42001-02-23 01:35:36 +00002725 HeapFree( GetProcessHeap(), 0, info->path );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002726 info->path = NULL;
2727 HeapFree( GetProcessHeap(), 0, info->long_mask );
2728 info->long_mask = NULL;
2729 goto done;
Juergen Schmied2250f122000-06-01 23:17:42 +00002730 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002731
2732 ret = TRUE;
2733
2734 data->dwFileAttributes = dataW.dwFileAttributes;
2735 data->ftCreationTime = dataW.ftCreationTime;
2736 data->ftLastAccessTime = dataW.ftLastAccessTime;
2737 data->ftLastWriteTime = dataW.ftLastWriteTime;
2738 data->nFileSizeHigh = dataW.nFileSizeHigh;
2739 data->nFileSizeLow = dataW.nFileSizeLow;
2740 WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
2741 data->cFileName, sizeof(data->cFileName), NULL, NULL );
2742 WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
2743 data->cAlternateFileName,
2744 sizeof(data->cAlternateFileName), NULL, NULL );
2745done:
2746 if( !ret ) SetLastError( gle );
2747 GlobalUnlock16( handle );
2748
2749 return ret;
Juergen Schmied2250f122000-06-01 23:17:42 +00002750}
2751
2752/*************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002753 * FindClose (KERNEL.415)
Juergen Schmied2250f122000-06-01 23:17:42 +00002754 */
2755BOOL16 WINAPI FindClose16( HANDLE16 handle )
2756{
2757 FIND_FIRST_INFO *info;
2758
2759 if ((handle == INVALID_HANDLE_VALUE16) ||
2760 !(info = (FIND_FIRST_INFO *)GlobalLock16( handle )))
2761 {
2762 SetLastError( ERROR_INVALID_HANDLE );
2763 return FALSE;
2764 }
Mike McCormack963985b2002-07-19 03:17:19 +00002765 if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir );
Alexandre Julliard61d32b42001-02-23 01:35:36 +00002766 if (info->path) HeapFree( GetProcessHeap(), 0, info->path );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00002767 if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask );
Juergen Schmied2250f122000-06-01 23:17:42 +00002768 GlobalUnlock16( handle );
2769 GlobalFree16( handle );
2770 return TRUE;
2771}