Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1 | /* |
| 2 | * DOS file system functions |
| 3 | * |
| 4 | * Copyright 1993 Erik Bos |
| 5 | * Copyright 1996 Alexandre Julliard |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 6 | * |
| 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 20 | */ |
| 21 | |
Alexandre Julliard | c7c217b | 1998-04-13 12:21:30 +0000 | [diff] [blame] | 22 | #include "config.h" |
Patrik Stridvall | 33929be | 2001-07-18 21:04:23 +0000 | [diff] [blame] | 23 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 24 | #include <sys/types.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 25 | #include <ctype.h> |
| 26 | #include <dirent.h> |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 27 | #include <errno.h> |
Howard Abrams | 1327748 | 1999-07-10 13:16:29 +0000 | [diff] [blame] | 28 | #ifdef HAVE_SYS_ERRNO_H |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 29 | #include <sys/errno.h> |
Howard Abrams | 1327748 | 1999-07-10 13:16:29 +0000 | [diff] [blame] | 30 | #endif |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 31 | #include <fcntl.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 32 | #include <string.h> |
| 33 | #include <stdlib.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 34 | #include <sys/stat.h> |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 35 | #ifdef HAVE_SYS_IOCTL_H |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 36 | #include <sys/ioctl.h> |
Steven Edwards | 48ac89b | 2002-05-19 22:25:02 +0000 | [diff] [blame] | 37 | #endif |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 38 | #include <time.h> |
Patrik Stridvall | d016f81 | 2002-08-17 00:43:16 +0000 | [diff] [blame] | 39 | #ifdef HAVE_UNISTD_H |
| 40 | # include <unistd.h> |
| 41 | #endif |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 42 | |
Marcus Meissner | 317af32 | 1999-02-17 13:51:06 +0000 | [diff] [blame] | 43 | #include "windef.h" |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 44 | #include "winerror.h" |
Patrik Stridvall | 33929be | 2001-07-18 21:04:23 +0000 | [diff] [blame] | 45 | #include "wingdi.h" |
| 46 | |
| 47 | #include "wine/unicode.h" |
| 48 | #include "wine/winbase16.h" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 49 | #include "drive.h" |
| 50 | #include "file.h" |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 51 | #include "heap.h" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 52 | #include "msdos.h" |
Patrik Stridvall | 9c1de6d | 2002-09-12 22:07:02 +0000 | [diff] [blame] | 53 | #include "winternl.h" |
Alexandre Julliard | 37e9503 | 2001-07-19 00:39:09 +0000 | [diff] [blame] | 54 | #include "wine/server.h" |
Peter Hunnisett | 73ab649 | 2002-02-25 20:10:35 +0000 | [diff] [blame] | 55 | #include "msvcrt/excpt.h" |
Patrik Stridvall | 33929be | 2001-07-18 21:04:23 +0000 | [diff] [blame] | 56 | |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 57 | #include "smb.h" |
| 58 | |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 59 | #include "wine/debug.h" |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 60 | |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 61 | WINE_DEFAULT_DEBUG_CHANNEL(dosfs); |
| 62 | WINE_DECLARE_DEBUG_CHANNEL(file); |
Patrik Stridvall | b4b9fae | 1999-04-19 14:56:29 +0000 | [diff] [blame] | 63 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 64 | /* Define the VFAT ioctl to get both short and long file names */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 65 | /* FIXME: is it possible to get this to work on other systems? */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 66 | #ifdef linux |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 67 | /* We want the real kernel dirent structure, not the libc one */ |
| 68 | typedef 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 Ganten | 0bac5e9 | 1999-09-27 11:46:27 +0000 | [diff] [blame] | 76 | #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, KERNEL_DIRENT [2] ) |
| 77 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 78 | #else /* linux */ |
| 79 | #undef VFAT_IOCTL_READDIR_BOTH /* just in case... */ |
| 80 | #endif /* linux */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 81 | |
| 82 | /* Chars we don't want to see in DOS file names */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 83 | #define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 84 | |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 85 | static const DOS_DEVICE DOSFS_Devices[] = |
| 86 | /* name, device flags (see Int 21/AX=0x4400) */ |
| 87 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 88 | { {'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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 103 | }; |
| 104 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 105 | /* |
| 106 | * Directory info for DOSFS_ReadDir |
| 107 | * contains the names of *all* the files in the directory |
| 108 | */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 109 | typedef struct |
| 110 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 111 | int used; |
| 112 | int size; |
| 113 | char names[1]; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 114 | } DOS_DIR; |
| 115 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 116 | /* Info structure for FindFirstFile handle */ |
| 117 | typedef struct |
| 118 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 119 | char *path; /* unix path */ |
| 120 | LPWSTR long_mask; |
| 121 | LPWSTR short_mask; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 122 | BYTE attr; |
| 123 | int drive; |
| 124 | int cur_pos; |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 125 | union |
| 126 | { |
| 127 | DOS_DIR *dos_dir; |
| 128 | SMB_DIR *smb_dir; |
| 129 | } u; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 130 | } FIND_FIRST_INFO; |
| 131 | |
| 132 | |
Dominik Strasser | 4f46b5d | 2001-04-20 18:38:41 +0000 | [diff] [blame] | 133 | static 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 140 | |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 148 | static int DOSFS_ValidDOSName( LPCWSTR name, int ignore_case ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 149 | { |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 150 | static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 151 | const WCHAR *p = name; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 152 | const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 153 | 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 165 | if (*p < 256 && strchr( invalid, (char)*p )) return 0; /* Invalid char */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 166 | 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 176 | if (*p < 256 && strchr( invalid, (char)*p )) return 0; /* Invalid char */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 177 | 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 186 | * 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 191 | * Return FALSE if the name is not a valid DOS name. |
| 192 | * 'buffer' must be at least 12 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 193 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 194 | BOOL DOSFS_ToDosFCBFormat( LPCWSTR name, LPWSTR buffer ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 195 | { |
| 196 | static const char invalid_chars[] = INVALID_DOS_CHARS; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 197 | LPCWSTR p = name; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 198 | int i; |
| 199 | |
György 'Nog' Jeney | 4610c0a | 2002-09-27 22:03:44 +0000 | [diff] [blame] | 200 | TRACE("(%s, %p)\n", debugstr_w(name), buffer); |
| 201 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 202 | /* Check for "." and ".." */ |
| 203 | if (*p == '.') |
| 204 | { |
| 205 | p++; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 206 | buffer[0] = '.'; |
| 207 | for(i = 1; i < 11; i++) buffer[i] = ' '; |
| 208 | buffer[11] = 0; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 209 | if (*p == '.') |
| 210 | { |
| 211 | buffer[1] = '.'; |
| 212 | p++; |
| 213 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 214 | return (!*p || (*p == '/') || (*p == '\\')); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 215 | } |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 234 | if (*p < 256 && strchr( invalid_chars, (char)*p )) return FALSE; |
| 235 | buffer[i] = toupperW(*p); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 236 | 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 249 | if (*p && (*p != '/') && (*p != '\\') && (*p != '.')) return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 250 | } |
| 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 263 | return FALSE; /* Second extension not allowed */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 264 | case '?': |
| 265 | p++; |
| 266 | /* fall through */ |
| 267 | case '*': |
| 268 | buffer[i] = '?'; |
| 269 | break; |
| 270 | default: |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 271 | if (*p < 256 && strchr( invalid_chars, (char)*p )) return FALSE; |
| 272 | buffer[i] = toupperW(*p); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 273 | p++; |
| 274 | break; |
| 275 | } |
| 276 | } |
| 277 | buffer[11] = '\0'; |
Stefan Leichter | 7cc51fa | 2000-03-26 20:25:59 +0000 | [diff] [blame] | 278 | |
| 279 | /* at most 3 character of the extension are processed |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 280 | * is something behind this ? |
Stefan Leichter | 7cc51fa | 2000-03-26 20:25:59 +0000 | [diff] [blame] | 281 | */ |
Alexandre Julliard | 199aeba | 2000-03-28 13:20:32 +0000 | [diff] [blame] | 282 | while (*p == '*' || *p == ' ') p++; /* skip wildcards and spaces */ |
Stefan Leichter | 7cc51fa | 2000-03-26 20:25:59 +0000 | [diff] [blame] | 283 | return IS_END_OF_NAME(*p); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 284 | } |
| 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 293 | * 'buffer' must be at least 13 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 294 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 295 | static void DOSFS_ToDosDTAFormat( LPCWSTR name, LPWSTR buffer ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 296 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 297 | LPWSTR p; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 298 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 299 | memcpy( buffer, name, 8 * sizeof(WCHAR) ); |
Alexandre Julliard | 566a52a | 2001-03-05 19:34:17 +0000 | [diff] [blame] | 300 | p = buffer + 8; |
| 301 | while ((p > buffer) && (p[-1] == ' ')) p--; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 302 | *p++ = '.'; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 303 | memcpy( p, name + 8, 3 * sizeof(WCHAR) ); |
Alexandre Julliard | 566a52a | 2001-03-05 19:34:17 +0000 | [diff] [blame] | 304 | p += 3; |
| 305 | while (p[-1] == ' ') p--; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 306 | if (p[-1] == '.') p--; |
| 307 | *p = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 308 | } |
| 309 | |
| 310 | |
| 311 | /*********************************************************************** |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 312 | * DOSFS_MatchShort |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 313 | * |
| 314 | * Check a DOS file name against a mask (both in FCB format). |
| 315 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 316 | static int DOSFS_MatchShort( LPCWSTR mask, LPCWSTR name ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 317 | { |
| 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 Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 326 | * DOSFS_MatchLong |
| 327 | * |
| 328 | * Check a long file name against a mask. |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 329 | * |
| 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éron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 338 | * *test1.txt* test1.txt * |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 339 | * h?l?o*t.dat hellothisisatest.dat * |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 340 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 341 | static int DOSFS_MatchLong( LPCWSTR mask, LPCWSTR name, int case_sensitive ) |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 342 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 343 | LPCWSTR lastjoker = NULL; |
| 344 | LPCWSTR next_to_retry = NULL; |
| 345 | static const WCHAR asterisk_dot_asterisk[] = {'*','.','*',0}; |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 346 | |
György 'Nog' Jeney | 4610c0a | 2002-09-27 22:03:44 +0000 | [diff] [blame] | 347 | TRACE("(%s, %s, %x)\n", debugstr_w(mask), debugstr_w(name), case_sensitive); |
| 348 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 349 | if (!strcmpW( mask, asterisk_dot_asterisk )) return 1; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 350 | while (*name && *mask) |
| 351 | { |
| 352 | if (*mask == '*') |
| 353 | { |
| 354 | mask++; |
| 355 | while (*mask == '*') mask++; /* Skip consecutive '*' */ |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 356 | 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 Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 360 | if (case_sensitive) while (*name && (*name != *mask)) name++; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 361 | else while (*name && (toupperW(*name) != toupperW(*mask))) name++; |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 362 | |
Robert W Hall | 9132a78 | 1999-04-18 14:38:17 +0000 | [diff] [blame] | 363 | if (!*name) break; |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 364 | next_to_retry = name; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 365 | } |
| 366 | else if (*mask != '?') |
| 367 | { |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 368 | int mismatch = 0; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 369 | if (case_sensitive) |
| 370 | { |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 371 | if (*mask != *name) mismatch = 1; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 372 | } |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 373 | else |
| 374 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 375 | if (toupperW(*mask) != toupperW(*name)) mismatch = 1; |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 376 | } |
| 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 Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 403 | } |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 404 | else /* '?' */ |
| 405 | { |
| 406 | mask++; |
| 407 | name++; |
| 408 | } |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 409 | } |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 410 | while ((*mask == '.') || (*mask == '*')) |
| 411 | mask++; /* Ignore trailing '.' or '*' in mask */ |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 412 | return (!*name && !*mask); |
| 413 | } |
| 414 | |
| 415 | |
| 416 | /*********************************************************************** |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 417 | * DOSFS_AddDirEntry |
| 418 | * |
| 419 | * Used to construct an array of filenames in DOSFS_OpenDir |
| 420 | */ |
| 421 | static 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 | */ |
| 460 | static 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 | */ |
| 511 | static 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 Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 538 | * DOSFS_OpenDir |
| 539 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 540 | static DOS_DIR *DOSFS_OpenDir( UINT codepage, const char *unix_path ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 541 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 542 | 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 Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 548 | if (!dir) |
| 549 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 550 | SetLastError( ERROR_NOT_ENOUGH_MEMORY ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 551 | return NULL; |
| 552 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 553 | dir->used = 0; |
| 554 | dir->size = init_size; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 555 | |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 556 | /* Treat empty path as root directory. This simplifies path split into |
| 557 | directory and mask in several other places */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 558 | if (!*unix_path) unix_path = "/"; |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 559 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 560 | r = DOSFS_OpenDir_VFAT( codepage, &dir, unix_path); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 561 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 562 | if(!r) |
| 563 | r = DOSFS_OpenDir_Normal( codepage, &dir, unix_path); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 564 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 565 | if(!r) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 566 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 567 | HeapFree(GetProcessHeap(), 0, dir); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 568 | return NULL; |
| 569 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 570 | dir->used = 0; |
| 571 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 572 | return dir; |
| 573 | } |
| 574 | |
| 575 | |
| 576 | /*********************************************************************** |
| 577 | * DOSFS_CloseDir |
| 578 | */ |
| 579 | static void DOSFS_CloseDir( DOS_DIR *dir ) |
| 580 | { |
Alexandre Julliard | 90476d6 | 2000-02-16 22:47:24 +0000 | [diff] [blame] | 581 | HeapFree( GetProcessHeap(), 0, dir ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 582 | } |
| 583 | |
| 584 | |
| 585 | /*********************************************************************** |
| 586 | * DOSFS_ReadDir |
| 587 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 588 | static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCWSTR *long_name, |
| 589 | LPCWSTR *short_name ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 590 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 591 | LPCWSTR sn, ln; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 592 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 593 | if (!dir) |
| 594 | return FALSE; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 595 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 596 | /* 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' Jeney | 4610c0a | 2002-09-27 22:03:44 +0000 | [diff] [blame] | 612 | TRACE("Read: long_name: %s, short_name: %s\n", |
| 613 | debugstr_w(*long_name), debugstr_w(*short_name)); |
| 614 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 615 | return TRUE; |
| 616 | } |
| 617 | |
| 618 | |
| 619 | /*********************************************************************** |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 620 | * 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 626 | * 'buffer' must be at least 13 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 627 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 628 | static void DOSFS_Hash( LPCWSTR name, LPWSTR buffer, BOOL dir_format, |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 629 | BOOL ignore_case ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 630 | { |
| 631 | static const char invalid_chars[] = INVALID_DOS_CHARS "~."; |
| 632 | static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; |
| 633 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 634 | LPCWSTR p, ext; |
| 635 | LPWSTR dst; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 636 | unsigned short hash; |
| 637 | int i; |
| 638 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 639 | if (dir_format) |
| 640 | { |
| 641 | for(i = 0; i < 11; i++) buffer[i] = ' '; |
| 642 | buffer[11] = 0; |
| 643 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 644 | |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 645 | if (DOSFS_ValidDOSName( name, ignore_case )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 646 | { |
| 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 653 | return; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 654 | } |
| 655 | |
| 656 | /* Simply copy the name, converting to uppercase */ |
| 657 | |
| 658 | for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++) |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 659 | *dst++ = toupperW(*name); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 660 | if (*name == '.') |
| 661 | { |
| 662 | if (dir_format) dst = buffer + 8; |
| 663 | else *dst++ = '.'; |
| 664 | for (name++; !IS_END_OF_NAME(*name); name++) |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 665 | *dst++ = toupperW(*name); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 666 | } |
| 667 | if (!dir_format) *dst = '\0'; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 668 | 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 677 | hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p) ^ (tolowerW(p[1]) << 8); |
| 678 | hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p); /* Last character */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 679 | } |
| 680 | else |
| 681 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 682 | 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 685 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 686 | |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 697 | *dst++ = (*p < 256 && strchr( invalid_chars, (char)*p )) ? '_' : toupperW(*p); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 698 | } |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 712 | *dst++ = (*ext < 256 && strchr( invalid_chars, (char)*ext )) ? '_' : toupperW(*ext); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 713 | } |
| 714 | if (!dir_format) *dst = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 715 | } |
| 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 724 | * 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 729 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 730 | BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf, |
| 731 | INT long_len, LPWSTR short_buf, BOOL ignore_case) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 732 | { |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 733 | DOS_DIR *dir; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 734 | LPCWSTR long_name, short_name; |
| 735 | WCHAR dos_name[12], tmp_buf[13]; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 736 | BOOL ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 737 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 738 | 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 Hawkes | bb9e66e | 2000-06-25 12:46:40 +0000 | [diff] [blame] | 741 | /* Ignore trailing dots and spaces */ |
| 742 | while (len > 1 && (name[len-1] == '.' || name[len-1] == ' ')) len--; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 743 | if (long_len < len + 1) return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 744 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 745 | TRACE("%s,%s\n", path->long_name, debugstr_w(name) ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 746 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 747 | if (!DOSFS_ToDosFCBFormat( name, dos_name )) dos_name[0] = '\0'; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 748 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 749 | if (!(dir = DOSFS_OpenDir( DRIVE_GetCodepage(path->drive), path->long_name ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 750 | { |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 751 | WARN("(%s,%s): can't open dir: %s\n", |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 752 | path->long_name, debugstr_w(name), strerror(errno) ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 753 | return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 754 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 755 | |
| 756 | while ((ret = DOSFS_ReadDir( dir, &long_name, &short_name ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 757 | { |
| 758 | /* Check against Unix name */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 759 | if (len == strlenW(long_name)) |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 760 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 761 | if (!ignore_case) |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 762 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 763 | if (!strncmpW( long_name, name, len )) break; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 764 | } |
| 765 | else |
| 766 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 767 | if (!strncmpiW( long_name, name, len )) break; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 768 | } |
| 769 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 770 | if (dos_name[0]) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 771 | { |
| 772 | /* Check against hashed DOS name */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 773 | if (!short_name) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 774 | { |
| 775 | DOSFS_Hash( long_name, tmp_buf, TRUE, ignore_case ); |
| 776 | short_name = tmp_buf; |
| 777 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 778 | if (!strcmpW( dos_name, short_name )) break; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 779 | } |
| 780 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 781 | if (ret) |
| 782 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 783 | if (long_buf) WideCharToMultiByte(DRIVE_GetCodepage(path->drive), 0, |
| 784 | long_name, -1, long_buf, long_len, NULL, NULL); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 785 | 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 792 | TRACE("(%s,%s) -> %s (%s)\n", path->long_name, debugstr_w(name), |
| 793 | debugstr_w(long_name), short_buf ? debugstr_w(short_buf) : "***"); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 794 | } |
| 795 | else |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 796 | WARN("%s not found in '%s'\n", debugstr_w(name), path->long_name); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 797 | DOSFS_CloseDir( dir ); |
| 798 | return ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 799 | } |
| 800 | |
| 801 | |
| 802 | /*********************************************************************** |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 803 | * DOSFS_GetDevice |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 804 | * |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 805 | * Check if a DOS file name represents a DOS device and return the device. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 806 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 807 | const DOS_DEVICE *DOSFS_GetDevice( LPCWSTR name ) |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 808 | { |
Alexandre Julliard | 267ca68 | 2002-07-31 17:20:00 +0000 | [diff] [blame] | 809 | unsigned int i; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 810 | const WCHAR *p; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 811 | |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 812 | if (!name) return NULL; /* if FILE_DupUnixHandle was used */ |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 813 | if (name[0] && (name[1] == ':')) name += 2; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 814 | if ((p = strrchrW( name, '/' ))) name = p + 1; |
| 815 | if ((p = strrchrW( name, '\\' ))) name = p + 1; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 816 | for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) |
| 817 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 818 | const WCHAR *dev = DOSFS_Devices[i].name; |
| 819 | if (!strncmpiW( dev, name, strlenW(dev) )) |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 820 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 821 | p = name + strlenW( dev ); |
Lawson Whitney | e3178f9 | 2000-12-27 03:28:13 +0000 | [diff] [blame] | 822 | if (!*p || (*p == '.') || (*p == ':')) return &DOSFS_Devices[i]; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 823 | } |
| 824 | } |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 825 | return NULL; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 826 | } |
| 827 | |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 828 | |
| 829 | /*********************************************************************** |
| 830 | * DOSFS_GetDeviceByHandle |
| 831 | */ |
Alexandre Julliard | 267ca68 | 2002-07-31 17:20:00 +0000 | [diff] [blame] | 832 | const DOS_DEVICE *DOSFS_GetDeviceByHandle( HANDLE hFile ) |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 833 | { |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 834 | const DOS_DEVICE *ret = NULL; |
Alexandre Julliard | 67a7499 | 2001-02-27 02:09:16 +0000 | [diff] [blame] | 835 | SERVER_START_REQ( get_file_info ) |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 836 | { |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 837 | req->handle = hFile; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 838 | if (!wine_server_call( req ) && (reply->type == FILE_TYPE_UNKNOWN)) |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 839 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 840 | if ((reply->attr >= 0) && |
| 841 | (reply->attr < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]))) |
| 842 | ret = &DOSFS_Devices[reply->attr]; |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 843 | } |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 844 | } |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 845 | SERVER_END_REQ; |
| 846 | return ret; |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 847 | } |
| 848 | |
| 849 | |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 850 | /************************************************************************** |
| 851 | * DOSFS_CreateCommPort |
| 852 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 853 | static HANDLE DOSFS_CreateCommPort(LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa) |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 854 | { |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 855 | HANDLE ret; |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 856 | char devname[40]; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 857 | 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 McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 860 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 861 | TRACE_(file)("%s %lx %lx\n", debugstr_w(name), access, attributes); |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 862 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 863 | PROFILE_GetWineIniString(serialportsW, name, empty_strW, devnameW, 40); |
| 864 | if(!devnameW[0]) |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 865 | return 0; |
| 866 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 867 | WideCharToMultiByte(CP_ACP, 0, devnameW, -1, devname, sizeof(devname), NULL, NULL); |
| 868 | |
| 869 | TRACE("opening %s as %s\n", devname, debugstr_w(name)); |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 870 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 871 | SERVER_START_REQ( create_serial ) |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 872 | { |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 873 | req->access = access; |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 874 | req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); |
Mike McCormack | 568c67e | 2001-10-08 20:40:57 +0000 | [diff] [blame] | 875 | req->attributes = attributes; |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 876 | req->sharing = FILE_SHARE_READ|FILE_SHARE_WRITE; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 877 | wine_server_add_data( req, devname, strlen(devname) ); |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 878 | SetLastError(0); |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 879 | wine_server_call_err( req ); |
| 880 | ret = reply->handle; |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 881 | } |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 882 | SERVER_END_REQ; |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 883 | |
Rein Klazes | 0a78857 | 2001-02-20 01:52:41 +0000 | [diff] [blame] | 884 | if(!ret) |
Andreas Mohr | e15badb | 2001-10-21 15:18:15 +0000 | [diff] [blame] | 885 | ERR("Couldn't open device '%s' ! (check permissions)\n",devname); |
Rein Klazes | 0a78857 | 2001-02-20 01:52:41 +0000 | [diff] [blame] | 886 | else |
| 887 | TRACE("return %08X\n", ret ); |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 888 | return ret; |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 889 | } |
| 890 | |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 891 | /*********************************************************************** |
| 892 | * DOSFS_OpenDevice |
| 893 | * |
| 894 | * Open a DOS device. This might not map 1:1 into the UNIX device concept. |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 895 | * Returns 0 on failure. |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 896 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 897 | HANDLE DOSFS_OpenDevice( LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 898 | { |
Alexandre Julliard | 267ca68 | 2002-07-31 17:20:00 +0000 | [diff] [blame] | 899 | unsigned int i; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 900 | const WCHAR *p; |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 901 | HANDLE handle; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 902 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 903 | if (name[0] && (name[1] == ':')) name += 2; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 904 | if ((p = strrchrW( name, '/' ))) name = p + 1; |
| 905 | if ((p = strrchrW( name, '\\' ))) name = p + 1; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 906 | for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) |
| 907 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 908 | const WCHAR *dev = DOSFS_Devices[i].name; |
| 909 | if (!strncmpiW( dev, name, strlenW(dev) )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 910 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 911 | p = name + strlenW( dev ); |
Lawson Whitney | e3178f9 | 2000-12-27 03:28:13 +0000 | [diff] [blame] | 912 | if (!*p || (*p == '.') || (*p == ':')) { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 913 | 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 Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 918 | /* got it */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 919 | if (!strcmpiW(DOSFS_Devices[i].name, nulW)) |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 920 | return FILE_CreateFile( "/dev/null", access, |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 921 | FILE_SHARE_READ|FILE_SHARE_WRITE, sa, |
Ove Kaaven | 708a846 | 2001-10-24 00:23:25 +0000 | [diff] [blame] | 922 | OPEN_EXISTING, 0, 0, TRUE, DRIVE_UNKNOWN ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 923 | if (!strcmpiW(DOSFS_Devices[i].name, conW)) { |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 924 | HANDLE to_dup; |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 925 | switch (access & (GENERIC_READ|GENERIC_WRITE)) { |
| 926 | case GENERIC_READ: |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 927 | to_dup = GetStdHandle( STD_INPUT_HANDLE ); |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 928 | break; |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 929 | case GENERIC_WRITE: |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 930 | to_dup = GetStdHandle( STD_OUTPUT_HANDLE ); |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 931 | break; |
| 932 | default: |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 933 | FIXME("can't open CON read/write\n"); |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 934 | return 0; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 935 | } |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 936 | if (!DuplicateHandle( GetCurrentProcess(), to_dup, GetCurrentProcess(), |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 937 | &handle, 0, |
| 938 | sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle, |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 939 | DUPLICATE_SAME_ACCESS )) |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 940 | handle = 0; |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 941 | return handle; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 942 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 943 | if (!strcmpiW(DOSFS_Devices[i].name, scsimgrW) || |
| 944 | !strcmpiW(DOSFS_Devices[i].name, hpscanW) || |
| 945 | !strcmpiW(DOSFS_Devices[i].name, emmxxxx0W)) |
Alexandre Julliard | fbe63ad | 1998-12-30 12:10:06 +0000 | [diff] [blame] | 946 | { |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 947 | return FILE_CreateDevice( i, access, sa ); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 948 | } |
Michael McCormack | a848607 | 1999-03-14 12:25:36 +0000 | [diff] [blame] | 949 | |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 950 | if( (handle=DOSFS_CreateCommPort(DOSFS_Devices[i].name,access,attributes,sa)) ) |
Mike McCormack | 44b5bf5 | 2000-09-07 18:39:51 +0000 | [diff] [blame] | 951 | return handle; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 952 | FIXME("device open %s not supported (yet)\n", debugstr_w(DOSFS_Devices[i].name)); |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 953 | return 0; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 954 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 955 | } |
| 956 | } |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 957 | return 0; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 958 | } |
| 959 | |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 960 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 961 | /*********************************************************************** |
| 962 | * DOSFS_GetPathDrive |
| 963 | * |
| 964 | * Get the drive specified by a given path name (DOS or Unix format). |
| 965 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 966 | static int DOSFS_GetPathDrive( LPCWSTR *name ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 967 | { |
| 968 | int drive; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 969 | LPCWSTR p = *name; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 970 | |
| 971 | if (*p && (p[1] == ':')) |
| 972 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 973 | drive = toupperW(*p) - 'A'; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 974 | *name += 2; |
| 975 | } |
| 976 | else if (*p == '/') /* Absolute Unix path? */ |
| 977 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 978 | if ((drive = DRIVE_FindDriveRootW( name )) == -1) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 979 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 980 | MESSAGE("Warning: %s not accessible from a configured DOS drive\n", debugstr_w(*name) ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 981 | /* Assume it really was a DOS name */ |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 982 | drive = DRIVE_GetCurrentDrive(); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 983 | } |
| 984 | } |
| 985 | else drive = DRIVE_GetCurrentDrive(); |
| 986 | |
| 987 | if (!DRIVE_IsValid(drive)) |
| 988 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 989 | SetLastError( ERROR_INVALID_DRIVE ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 990 | return -1; |
| 991 | } |
| 992 | return drive; |
| 993 | } |
| 994 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 995 | |
| 996 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 997 | * DOSFS_GetFullName |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 998 | * |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 999 | * 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1002 | * component is only checked if 'check_last' is non-zero. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1003 | * The buffers pointed to by 'long_buf' and 'short_buf' must be |
| 1004 | * at least MAX_PATHNAME_LEN long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1005 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1006 | BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last, DOS_FULL_NAME *full ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1007 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1008 | BOOL found; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1009 | 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1014 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1015 | TRACE("%s (last=%d)\n", debugstr_w(name), check_last ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1016 | |
Gerard Patel | d52e1c4 | 2001-02-16 19:05:42 +0000 | [diff] [blame] | 1017 | if ((!*name) || (*name=='\n')) |
| 1018 | { /* error code for Win98 */ |
| 1019 | SetLastError(ERROR_BAD_PATHNAME); |
| 1020 | return FALSE; |
| 1021 | } |
| 1022 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1023 | if ((full->drive = DOSFS_GetPathDrive( &name )) == -1) return FALSE; |
| 1024 | flags = DRIVE_GetFlags( full->drive ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1025 | codepage = DRIVE_GetCodepage(full->drive); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1026 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1027 | lstrcpynA( full->long_name, DRIVE_GetRoot( full->drive ), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1028 | 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1032 | strcpyW( full->short_name, driveA_rootW ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1033 | full->short_name[0] += full->drive; |
| 1034 | |
| 1035 | if ((*name == '\\') || (*name == '/')) /* Absolute path */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1036 | { |
| 1037 | while ((*name == '\\') || (*name == '/')) name++; |
| 1038 | } |
Alexandre Julliard | dcf0bea | 2002-06-20 23:13:06 +0000 | [diff] [blame] | 1039 | else /* Relative path */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1040 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1041 | lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1042 | sizeof(full->long_name) - (root - full->long_name) - 1 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1043 | if (root[1]) *root = '/'; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1044 | lstrcpynW( full->short_name + 3, DRIVE_GetDosCwd( full->drive ), |
| 1045 | sizeof(full->short_name)/sizeof(full->short_name[0]) - 3 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1046 | } |
| 1047 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1048 | p_l = full->long_name[1] ? full->long_name + strlen(full->long_name) |
| 1049 | : full->long_name; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1050 | p_s = full->short_name[3] ? full->short_name + strlenW(full->short_name) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1051 | : full->short_name + 2; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1052 | found = TRUE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1053 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1054 | while (*name && found) |
| 1055 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1056 | /* Check for '.' and '..' */ |
| 1057 | |
| 1058 | if (*name == '.') |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1059 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1060 | 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1075 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1076 | |
| 1077 | /* Make sure buffers are large enough */ |
| 1078 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1079 | if ((p_s >= full->short_name + sizeof(full->short_name)/sizeof(full->short_name[0]) - 14) || |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1080 | (p_l >= full->long_name + sizeof(full->long_name) - 1)) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1081 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1082 | SetLastError( ERROR_PATH_NOT_FOUND ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1083 | return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1084 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1085 | |
| 1086 | /* Get the long and short name matching the file name */ |
| 1087 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1088 | if ((found = DOSFS_FindUnixName( full, name, p_l + 1, |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1089 | sizeof(full->long_name) - (p_l - full->long_name) - 1, |
| 1090 | p_s + 1, !(flags & DRIVE_CASE_SENSITIVE) ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1091 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1092 | *p_l++ = '/'; |
| 1093 | p_l += strlen(p_l); |
| 1094 | *p_s++ = '\\'; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1095 | p_s += strlenW(p_s); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1096 | while (!IS_END_OF_NAME(*name)) name++; |
| 1097 | } |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 1098 | else if (!check_last) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1099 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1100 | *p_l++ = '/'; |
| 1101 | *p_s++ = '\\'; |
| 1102 | while (!IS_END_OF_NAME(*name) && |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1103 | (p_s < full->short_name + sizeof(full->short_name)/sizeof(full->short_name[0]) - 1) && |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1104 | (p_l < full->long_name + sizeof(full->long_name) - 1)) |
| 1105 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1106 | WCHAR wch; |
| 1107 | *p_s++ = tolowerW(*name); |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 1108 | /* 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1111 | 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1114 | name++; |
| 1115 | } |
Dave Hawkes | bb9e66e | 2000-06-25 12:46:40 +0000 | [diff] [blame] | 1116 | /* Ignore trailing dots and spaces */ |
| 1117 | while(p_l[-1] == '.' || p_l[-1] == ' ') { |
| 1118 | --p_l; |
| 1119 | --p_s; |
| 1120 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1121 | *p_l = '\0'; |
| 1122 | *p_s = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1123 | } |
| 1124 | while ((*name == '\\') || (*name == '/')) name++; |
| 1125 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1126 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1127 | if (!found) |
| 1128 | { |
Alexander Larsson | a8745ea | 1998-12-02 10:04:52 +0000 | [diff] [blame] | 1129 | if (check_last) |
| 1130 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1131 | SetLastError( ERROR_FILE_NOT_FOUND ); |
Alexander Larsson | a8745ea | 1998-12-02 10:04:52 +0000 | [diff] [blame] | 1132 | return FALSE; |
| 1133 | } |
Alexander Larsson | 2772a67 | 1998-12-07 16:23:42 +0000 | [diff] [blame] | 1134 | if (*name) /* Not last */ |
| 1135 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1136 | SetLastError( ERROR_PATH_NOT_FOUND ); |
Alexander Larsson | 2772a67 | 1998-12-07 16:23:42 +0000 | [diff] [blame] | 1137 | return FALSE; |
| 1138 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1139 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1140 | if (!full->long_name[0]) strcpy( full->long_name, "/" ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1141 | 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1143 | return TRUE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1144 | } |
| 1145 | |
| 1146 | |
| 1147 | /*********************************************************************** |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1148 | * GetShortPathNameW (KERNEL32.@) |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 1149 | * |
| 1150 | * NOTES |
| 1151 | * observed: |
| 1152 | * longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 |
Francois Gouget | 60a83ef | 2001-09-14 00:59:58 +0000 | [diff] [blame] | 1153 | * longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0 |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1154 | * |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1155 | * more observations ( with NT 3.51 (WinDD) ): |
| 1156 | * longpath <= 8.3 -> just copy longpath to shortpath |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1157 | * longpath > 8.3 -> |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1158 | * 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 Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1162 | * - the absolute/relative path of the short name is reproduced like found |
| 1163 | * in the long name |
Francois Gouget | 60a83ef | 2001-09-14 00:59:58 +0000 | [diff] [blame] | 1164 | * - longpath and shortpath may have the same address |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1165 | * Peter Ganten, 1999 |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1166 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1167 | DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1168 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1169 | DOS_FULL_NAME full_name; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1170 | WCHAR tmpshortpath[MAX_PATHNAME_LEN]; |
| 1171 | const WCHAR *p; |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1172 | DWORD sp = 0, lp = 0; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1173 | int drive; |
| 1174 | DWORD tmplen; |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1175 | UINT flags; |
Alexandre Julliard | 4c5c7e7 | 2002-06-21 19:00:13 +0000 | [diff] [blame] | 1176 | BOOL unixabsolute = *longpath == '/'; |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1177 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1178 | TRACE("%s\n", debugstr_w(longpath)); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1179 | |
| 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 Julliard | 4c5c7e7 | 2002-06-21 19:00:13 +0000 | [diff] [blame] | 1189 | /* check for drive letter */ |
| 1190 | if (!unixabsolute && longpath[1] == ':' ) { |
| 1191 | tmpshortpath[0] = longpath[0]; |
| 1192 | tmpshortpath[1] = ':'; |
| 1193 | sp = 2; |
| 1194 | } |
| 1195 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1196 | if ( ( drive = DOSFS_GetPathDrive ( &longpath )) == -1 ) return 0; |
| 1197 | flags = DRIVE_GetFlags ( drive ); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1198 | |
Alexandre Julliard | 4c5c7e7 | 2002-06-21 19:00:13 +0000 | [diff] [blame] | 1199 | if (unixabsolute && drive != DRIVE_GetCurrentDrive()) { |
| 1200 | tmpshortpath[0] = drive + 'A'; |
| 1201 | tmpshortpath[1] = ':'; |
| 1202 | sp = 2; |
| 1203 | } |
Michael Wetherell | 70c42d8 | 2002-05-08 00:29:17 +0000 | [diff] [blame] | 1204 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1205 | while ( longpath[lp] ) { |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1206 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1207 | /* check for path delimiters and reproduce them */ |
| 1208 | if ( longpath[lp] == '\\' || longpath[lp] == '/' ) { |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1209 | if (!sp || tmpshortpath[sp-1]!= '\\') |
Uwe Bonnes | 61f572a | 2000-04-06 19:31:11 +0000 | [diff] [blame] | 1210 | { |
| 1211 | /* strip double "\\" */ |
| 1212 | tmpshortpath[sp] = '\\'; |
| 1213 | sp++; |
| 1214 | } |
Uwe Bonnes | 40249c6 | 2000-05-12 21:45:52 +0000 | [diff] [blame] | 1215 | tmpshortpath[sp]=0;/*terminate string*/ |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1216 | lp++; |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1217 | continue; |
| 1218 | } |
| 1219 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1220 | tmplen = 0; |
| 1221 | for(p = longpath + lp; *p && *p != '/' && *p != '\\'; p++) |
| 1222 | tmplen++; |
| 1223 | lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1224 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1225 | /* 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 Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1230 | } |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1231 | |
| 1232 | /* Check if the file exists and use the existing file name */ |
| 1233 | if ( DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1234 | strcpyW(tmpshortpath + sp, strrchrW(full_name.short_name, '\\') + 1); |
| 1235 | sp += strlenW(tmpshortpath + sp); |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1236 | lp += tmplen; |
| 1237 | continue; |
| 1238 | } |
| 1239 | |
| 1240 | TRACE("not found!\n" ); |
| 1241 | SetLastError ( ERROR_FILE_NOT_FOUND ); |
| 1242 | return 0; |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1243 | } |
Uwe Bonnes | 61f572a | 2000-04-06 19:31:11 +0000 | [diff] [blame] | 1244 | tmpshortpath[sp] = 0; |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1245 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1246 | 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éron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1253 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1254 | return tmplen; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1255 | } |
| 1256 | |
| 1257 | |
| 1258 | /*********************************************************************** |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1259 | * GetShortPathNameA (KERNEL32.@) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1260 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1261 | DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1262 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1263 | UNICODE_STRING longpathW; |
| 1264 | WCHAR shortpathW[MAX_PATH]; |
| 1265 | DWORD ret, retW; |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 1266 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1267 | if (!longpath) |
| 1268 | { |
| 1269 | SetLastError(ERROR_INVALID_PARAMETER); |
| 1270 | return 0; |
| 1271 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1272 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1273 | TRACE("%s\n", debugstr_a(longpath)); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1274 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1275 | 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 Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1301 | return ret; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1302 | } |
| 1303 | |
| 1304 | |
| 1305 | /*********************************************************************** |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1306 | * GetLongPathNameW (KERNEL32.@) |
Francois Gouget | 60a83ef | 2001-09-14 00:59:58 +0000 | [diff] [blame] | 1307 | * |
| 1308 | * NOTES |
| 1309 | * observed (Win2000): |
| 1310 | * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 |
| 1311 | * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0 |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1312 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1313 | DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen ) |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1314 | { |
| 1315 | DOS_FULL_NAME full_name; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1316 | const char *root; |
| 1317 | LPWSTR p; |
| 1318 | int drive; |
| 1319 | UINT codepage; |
| 1320 | DWORD ret, len = 0; |
Francois Gouget | 60a83ef | 2001-09-14 00:59:58 +0000 | [diff] [blame] | 1321 | |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1331 | TRACE("%s,%p,%ld\n", debugstr_w(shortpath), longpath, longlen); |
| 1332 | |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1333 | if(shortpath[0]=='\\' && shortpath[1]=='\\') |
| 1334 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1335 | ERR("UNC pathname %s\n",debugstr_w(shortpath)); |
| 1336 | lstrcpynW( longpath, full_name.short_name, longlen ); |
| 1337 | return strlenW(longpath); |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1338 | } |
| 1339 | |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1340 | if (!DOSFS_GetFullName( shortpath, TRUE, &full_name )) return 0; |
Petr Tomasek | 788a9f7 | 2000-02-20 19:14:17 +0000 | [diff] [blame] | 1341 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1342 | root = full_name.long_name; |
| 1343 | drive = DRIVE_FindDriveRoot(&root); |
| 1344 | codepage = DRIVE_GetCodepage(drive); |
Petr Tomasek | 788a9f7 | 2000-02-20 19:14:17 +0000 | [diff] [blame] | 1345 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1346 | 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 Larsson | c1190fe | 1998-10-11 13:57:09 +0000 | [diff] [blame] | 1354 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1355 | 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 Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1371 | } |
| 1372 | |
| 1373 | |
| 1374 | /*********************************************************************** |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1375 | * GetLongPathNameA (KERNEL32.@) |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1376 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1377 | DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen ) |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1378 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1379 | UNICODE_STRING shortpathW; |
| 1380 | WCHAR longpathW[MAX_PATH]; |
| 1381 | DWORD ret, retW; |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1382 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1383 | if (!shortpath) |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1384 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1385 | SetLastError(ERROR_INVALID_PARAMETER); |
| 1386 | return 0; |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1387 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1388 | |
| 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 Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1417 | return ret; |
| 1418 | } |
| 1419 | |
| 1420 | |
| 1421 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1422 | * DOSFS_DoGetFullPathName |
| 1423 | * |
Patrik Stridvall | 2d6457c | 2000-03-28 20:22:59 +0000 | [diff] [blame] | 1424 | * Implementation of GetFullPathNameA/W. |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1425 | * |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1426 | * bon@elektron 000331: |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1427 | * A test for GetFullPathName with many pathological cases |
Huw D M Davies | d0f8bfd | 2000-12-15 20:54:01 +0000 | [diff] [blame] | 1428 | * now gives identical output for Wine and OSR2 |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1429 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1430 | static DWORD DOSFS_DoGetFullPathName( LPCWSTR name, DWORD len, LPWSTR result ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1431 | { |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1432 | DWORD ret; |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1433 | DOS_FULL_NAME full_name; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1434 | LPWSTR p, q; |
| 1435 | char *p_l; |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1436 | const char * root; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1437 | WCHAR drivecur[] = {'C',':','.',0}; |
| 1438 | WCHAR driveletter=0; |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1439 | int namelen,drive=0; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1440 | 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 Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1445 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1446 | if (!name[0]) |
| 1447 | { |
| 1448 | SetLastError(ERROR_BAD_PATHNAME); |
| 1449 | return 0; |
| 1450 | } |
Alexandre Julliard | 1bb69a0 | 2002-04-02 02:46:27 +0000 | [diff] [blame] | 1451 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1452 | TRACE("passed %s\n", debugstr_w(name)); |
Jason Edmeades | ffb3d78 | 2002-05-05 21:01:43 +0000 | [diff] [blame] | 1453 | |
Alexandre Julliard | 1bb69a0 | 2002-04-02 02:46:27 +0000 | [diff] [blame] | 1454 | if (name[1]==':') |
| 1455 | /*drive letter given */ |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1456 | { |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1457 | driveletter = name[0]; |
| 1458 | } |
Alexandre Julliard | 1bb69a0 | 2002-04-02 02:46:27 +0000 | [diff] [blame] | 1459 | if ((name[1]==':') && ((name[2]=='\\') || (name[2]=='/'))) |
| 1460 | /*absolute path given */ |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1461 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1462 | 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 Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1465 | } |
| 1466 | else |
| 1467 | { |
| 1468 | if (driveletter) |
| 1469 | drivecur[0]=driveletter; |
Jason Edmeades | ffb3d78 | 2002-05-05 21:01:43 +0000 | [diff] [blame] | 1470 | else if ((name[0]=='\\') || (name[0]=='/')) |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1471 | strcpyW(drivecur, bkslashW); |
Jason Edmeades | ffb3d78 | 2002-05-05 21:01:43 +0000 | [diff] [blame] | 1472 | else |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1473 | strcpyW(drivecur, dotW); |
Jason Edmeades | ffb3d78 | 2002-05-05 21:01:43 +0000 | [diff] [blame] | 1474 | |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1475 | 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1481 | drive = toupperW(full_name.short_name[0]) - 'A'; |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1482 | root= DRIVE_GetRoot(drive); |
Uwe Bonnes | 594a0dc | 2000-06-15 00:30:26 +0000 | [diff] [blame] | 1483 | if (!root) |
| 1484 | { |
| 1485 | FIXME("internal: error getting DOS Drive Root\n"); |
| 1486 | return 0; |
| 1487 | } |
Marcus Meissner | 7f0490e | 2000-10-23 00:37:06 +0000 | [diff] [blame] | 1488 | if (!strcmp(root,"/")) |
| 1489 | { |
| 1490 | /* we have just the last / and we need it. */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1491 | p_l = full_name.long_name; |
Marcus Meissner | 7f0490e | 2000-10-23 00:37:06 +0000 | [diff] [blame] | 1492 | } |
| 1493 | else |
| 1494 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1495 | p_l = full_name.long_name + strlen(root); |
Marcus Meissner | 7f0490e | 2000-10-23 00:37:06 +0000 | [diff] [blame] | 1496 | } |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1497 | /* append long name (= unix name) to drive */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1498 | MultiByteToWideChar(DRIVE_GetCodepage(drive), 0, p_l, -1, |
| 1499 | full_name.short_name + 2, MAX_PATHNAME_LEN - 3); |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1500 | /* append name to treat */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1501 | namelen= strlenW(full_name.short_name); |
| 1502 | p = (LPWSTR)name; |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1503 | if (driveletter) |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1504 | p += 2; /* skip drive name when appending */ |
| 1505 | if (namelen + 2 + strlenW(p) > MAX_PATHNAME_LEN) |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1506 | { |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1512 | 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 Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1514 | } |
| 1515 | /* reverse all slashes */ |
| 1516 | for (p=full_name.short_name; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1517 | p < full_name.short_name + strlenW(full_name.short_name); |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1518 | p++) |
| 1519 | { |
| 1520 | if ( *p == '/' ) |
| 1521 | *p = '\\'; |
| 1522 | } |
Andreas Mohr | 9cef2d0 | 2001-11-19 02:30:01 +0000 | [diff] [blame] | 1523 | /* Use memmove, as areas overlap */ |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1524 | /* Delete .. */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1525 | while ((p = strstrW(full_name.short_name, updir_slashW))) |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1526 | { |
| 1527 | if (p > full_name.short_name+2) |
| 1528 | { |
| 1529 | *p = 0; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1530 | q = strrchrW(full_name.short_name, '\\'); |
| 1531 | memmove(q+1, p+4, (strlenW(p+4)+1) * sizeof(WCHAR)); |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1532 | } |
| 1533 | else |
| 1534 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1535 | memmove(full_name.short_name+3, p+4, (strlenW(p+4)+1) * sizeof(WCHAR)); |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1536 | } |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1542 | (strlenW(full_name.short_name+4)+1) * sizeof(WCHAR)); |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1543 | } |
| 1544 | /* Delete . */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1545 | while ((p = strstrW(full_name.short_name, curdirW))) |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1546 | { |
| 1547 | *(p+1) = 0; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1548 | memmove(p+1, p+3, (strlenW(p+3)+1) * sizeof(WCHAR)); |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1549 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1550 | if (!(DRIVE_GetFlags(drive) & DRIVE_CASE_PRESERVING)) |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1551 | 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 Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1554 | { |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1555 | /* one more strange case: "c:\test\test1\.." |
Andreas Mohr | 9cef2d0 | 2001-11-19 02:30:01 +0000 | [diff] [blame] | 1556 | return "c:\test" */ |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1557 | *(full_name.short_name+namelen-3)=0; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1558 | q = strrchrW(full_name.short_name, '\\'); |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1559 | *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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1566 | TRACE("got %s\n", debugstr_w(full_name.short_name)); |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1567 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1568 | /* 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 Mohr | 9cef2d0 | 2001-11-19 02:30:01 +0000 | [diff] [blame] | 1570 | plus the terminating \0 (tested against win95osr2, bon 001118) |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1571 | . */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1572 | ret = strlenW(full_name.short_name); |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1573 | 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 Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1579 | if (result) |
| 1580 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1581 | strncpyW( result, full_name.short_name, len ); |
| 1582 | result[len - 1] = 0; /* ensure 0 termination */ |
Alexandre Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1583 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1584 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1585 | TRACE("returning %s\n", debugstr_w(full_name.short_name) ); |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1586 | return ret; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1587 | } |
| 1588 | |
| 1589 | |
| 1590 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1591 | * GetFullPathNameA (KERNEL32.@) |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1592 | * NOTES |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1593 | * if the path closed with '\', *lastpart is 0 |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1594 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1595 | DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1596 | LPSTR *lastpart ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1597 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1598 | UNICODE_STRING nameW; |
| 1599 | WCHAR bufferW[MAX_PATH]; |
| 1600 | DWORD ret, retW; |
Juergen Schmied | 30f503f | 1998-12-15 17:28:26 +0000 | [diff] [blame] | 1601 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1602 | if (!name) |
| 1603 | { |
| 1604 | SetLastError(ERROR_INVALID_PARAMETER); |
| 1605 | return 0; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1606 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1607 | |
| 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1646 | return ret; |
| 1647 | } |
| 1648 | |
| 1649 | |
| 1650 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1651 | * GetFullPathNameW (KERNEL32.@) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1652 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1653 | DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1654 | LPWSTR *lastpart ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1655 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1656 | DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer ); |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1657 | if (ret && (ret<=len) && buffer && lastpart) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1658 | { |
Alexandre Julliard | e101f6d | 2000-08-14 14:42:41 +0000 | [diff] [blame] | 1659 | LPWSTR p = buffer + strlenW(buffer); |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1660 | if (*p != (WCHAR)'\\') |
| 1661 | { |
| 1662 | while ((p > buffer + 2) && (*p != (WCHAR)'\\')) p--; |
| 1663 | *lastpart = p + 1; |
| 1664 | } |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1665 | else *lastpart = NULL; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1666 | } |
| 1667 | return ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1668 | } |
| 1669 | |
Alexandre Julliard | 3a0f8b7 | 2000-12-01 20:48:41 +0000 | [diff] [blame] | 1670 | |
| 1671 | /*********************************************************************** |
Patrik Stridvall | 044855c | 2001-07-11 18:56:41 +0000 | [diff] [blame] | 1672 | * wine_get_unix_file_name (KERNEL32.@) Not a Windows API |
Alexandre Julliard | 3a0f8b7 | 2000-12-01 20:48:41 +0000 | [diff] [blame] | 1673 | * |
| 1674 | * Return the full Unix file name for a given path. |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1675 | * FIXME: convert dos file name to unicode |
Alexandre Julliard | 3a0f8b7 | 2000-12-01 20:48:41 +0000 | [diff] [blame] | 1676 | */ |
| 1677 | BOOL WINAPI wine_get_unix_file_name( LPCSTR dos, LPSTR buffer, DWORD len ) |
| 1678 | { |
| 1679 | BOOL ret; |
| 1680 | DOS_FULL_NAME path; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1681 | 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 Julliard | 3a0f8b7 | 2000-12-01 20:48:41 +0000 | [diff] [blame] | 1690 | return ret; |
| 1691 | } |
| 1692 | |
| 1693 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1694 | /*********************************************************************** |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1695 | * DOSFS_FindNextEx |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1696 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1697 | static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1698 | { |
Andreas Mohr | 220312e | 2000-10-19 20:38:38 +0000 | [diff] [blame] | 1699 | DWORD attr = info->attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY | FILE_ATTRIBUTE_SYMLINK; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1700 | UINT flags = DRIVE_GetFlags( info->drive ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1701 | char *p, buffer[MAX_PATHNAME_LEN]; |
| 1702 | const char *drive_path; |
| 1703 | int drive_root; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1704 | LPCWSTR long_name, short_name; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1705 | BY_HANDLE_FILE_INFORMATION fileinfo; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1706 | WCHAR dos_name[13]; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 1707 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1708 | if ((info->attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1709 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1710 | if (info->cur_pos) return 0; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1711 | entry->dwFileAttributes = FILE_ATTRIBUTE_LABEL; |
Alexandre Julliard | 1668870 | 2002-09-12 22:28:01 +0000 | [diff] [blame] | 1712 | 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 Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1715 | entry->nFileSizeHigh = 0; |
| 1716 | entry->nFileSizeLow = 0; |
| 1717 | entry->dwReserved0 = 0; |
| 1718 | entry->dwReserved1 = 0; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1719 | DOSFS_ToDosDTAFormat( DRIVE_GetLabel( info->drive ), entry->cFileName ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1720 | strcpyW( entry->cAlternateFileName, entry->cFileName ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1721 | info->cur_pos++; |
Stefan Leichter | eb0ab1b | 2000-08-18 23:45:46 +0000 | [diff] [blame] | 1722 | TRACE("returning %s (%s) as label\n", |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1723 | debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName)); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1724 | return 1; |
| 1725 | } |
| 1726 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1727 | drive_path = info->path + strlen(DRIVE_GetRoot( info->drive )); |
| 1728 | while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++; |
| 1729 | drive_root = !*drive_path; |
| 1730 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1731 | lstrcpynA( buffer, info->path, sizeof(buffer) - 1 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1732 | strcat( buffer, "/" ); |
| 1733 | p = buffer + strlen(buffer); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1734 | |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1735 | while (DOSFS_ReadDir( info->u.dos_dir, &long_name, &short_name )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1736 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1737 | info->cur_pos++; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1738 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1739 | /* Don't return '.' and '..' in the root of the drive */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1740 | if (drive_root && (long_name[0] == '.') && |
| 1741 | (!long_name[1] || ((long_name[1] == '.') && !long_name[2]))) |
| 1742 | continue; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1743 | |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1744 | /* Check the long mask */ |
| 1745 | |
György 'Nog' Jeney | 4610c0a | 2002-09-27 22:03:44 +0000 | [diff] [blame] | 1746 | if (info->long_mask && *info->long_mask) |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1747 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1748 | if (!DOSFS_MatchLong( info->long_mask, long_name, |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1749 | flags & DRIVE_CASE_SENSITIVE )) continue; |
| 1750 | } |
| 1751 | |
| 1752 | /* Check the short mask */ |
| 1753 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1754 | if (info->short_mask) |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1755 | { |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1756 | if (!short_name) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1757 | { |
| 1758 | DOSFS_Hash( long_name, dos_name, TRUE, |
| 1759 | !(flags & DRIVE_CASE_SENSITIVE) ); |
| 1760 | short_name = dos_name; |
| 1761 | } |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1762 | if (!DOSFS_MatchShort( info->short_mask, short_name )) continue; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1763 | } |
| 1764 | |
| 1765 | /* Check the file attributes */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1766 | WideCharToMultiByte(DRIVE_GetCodepage(info->drive), 0, long_name, -1, |
| 1767 | p, sizeof(buffer) - (int)(p - buffer), NULL, NULL); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1768 | if (!FILE_Stat( buffer, &fileinfo )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1769 | { |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 1770 | WARN("can't stat %s\n", buffer); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1771 | continue; |
| 1772 | } |
Andreas Mohr | 220312e | 2000-10-19 20:38:38 +0000 | [diff] [blame] | 1773 | if ((fileinfo.dwFileAttributes & FILE_ATTRIBUTE_SYMLINK) && |
| 1774 | (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) |
| 1775 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1776 | 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 Mohr | 220312e | 2000-10-19 20:38:38 +0000 | [diff] [blame] | 1778 | static int show_dir_symlinks = -1; |
| 1779 | if (show_dir_symlinks == -1) |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1780 | show_dir_symlinks = PROFILE_GetWineIniBool(wineW, ShowDirSymlinksW, 0); |
Andreas Mohr | 220312e | 2000-10-19 20:38:38 +0000 | [diff] [blame] | 1781 | if (!show_dir_symlinks) continue; |
| 1782 | } |
| 1783 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1784 | if (fileinfo.dwFileAttributes & ~attr) continue; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1785 | |
| 1786 | /* We now have a matching entry; fill the result and return */ |
| 1787 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1788 | 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1794 | |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1801 | lstrcpynW( entry->cFileName, long_name, sizeof(entry->cFileName)/sizeof(entry->cFileName[0]) ); |
| 1802 | if (!(flags & DRIVE_CASE_PRESERVING)) strlwrW( entry->cFileName ); |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 1803 | TRACE("returning %s (%s) %02lx %ld\n", |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1804 | debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName), |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 1805 | entry->dwFileAttributes, entry->nFileSizeLow ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1806 | return 1; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1807 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1808 | return 0; /* End of directory */ |
| 1809 | } |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1810 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1811 | /*********************************************************************** |
| 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 | */ |
| 1824 | int DOSFS_FindNext( const char *path, const char *short_mask, |
| 1825 | const char *long_mask, int drive, BYTE attr, |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1826 | int skip, WIN32_FIND_DATAA *entry ) |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1827 | { |
Joerg Mayer | 959d73e | 2000-10-22 23:56:32 +0000 | [diff] [blame] | 1828 | static FIND_FIRST_INFO info; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1829 | LPCWSTR short_name, long_name; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1830 | int count; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1831 | UNICODE_STRING short_maskW, long_maskW; |
| 1832 | WIN32_FIND_DATAW entryW; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1833 | |
György 'Nog' Jeney | 4610c0a | 2002-09-27 22:03:44 +0000 | [diff] [blame] | 1834 | 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 Julliard | ab68797 | 2000-11-15 23:41:46 +0000 | [diff] [blame] | 1838 | _EnterWin16Lock(); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1839 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1840 | RtlCreateUnicodeStringFromAsciiz(&short_maskW, short_mask); |
| 1841 | RtlCreateUnicodeStringFromAsciiz(&long_maskW, long_mask); |
| 1842 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1843 | /* Check the cached directory */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1844 | 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 Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1846 | && info.attr == attr && info.cur_pos <= skip)) |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1847 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1848 | /* Not in the cache, open it anew */ |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1849 | if (info.u.dos_dir) DOSFS_CloseDir( info.u.dos_dir ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1850 | |
| 1851 | info.path = (LPSTR)path; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1852 | 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 Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1856 | info.attr = attr; |
| 1857 | info.drive = drive; |
| 1858 | info.cur_pos = 0; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1859 | info.u.dos_dir = DOSFS_OpenDir( DRIVE_GetCodepage(drive), info.path ); |
| 1860 | } |
| 1861 | else |
| 1862 | { |
| 1863 | RtlFreeUnicodeString(&short_maskW); |
| 1864 | RtlFreeUnicodeString(&long_maskW); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1865 | } |
| 1866 | |
| 1867 | /* Skip to desired position */ |
| 1868 | while (info.cur_pos < skip) |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1869 | if (info.u.dos_dir && DOSFS_ReadDir( info.u.dos_dir, &long_name, &short_name )) |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1870 | info.cur_pos++; |
| 1871 | else |
| 1872 | break; |
| 1873 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1874 | 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 Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1880 | count = info.cur_pos - skip; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1881 | } |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1882 | else |
| 1883 | count = 0; |
| 1884 | |
| 1885 | if (!count) |
| 1886 | { |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1887 | if (info.u.dos_dir) DOSFS_CloseDir( info.u.dos_dir ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1888 | memset( &info, '\0', sizeof(info) ); |
| 1889 | } |
| 1890 | |
Alexandre Julliard | ab68797 | 2000-11-15 23:41:46 +0000 | [diff] [blame] | 1891 | _LeaveWin16Lock(); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1892 | |
| 1893 | return count; |
| 1894 | } |
| 1895 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1896 | /************************************************************************* |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1897 | * FindFirstFileExW (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1898 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1899 | HANDLE WINAPI FindFirstFileExW( |
| 1900 | LPCWSTR lpFileName, |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1901 | FINDEX_INFO_LEVELS fInfoLevelId, |
| 1902 | LPVOID lpFindFileData, |
| 1903 | FINDEX_SEARCH_OPS fSearchOp, |
| 1904 | LPVOID lpSearchFilter, |
| 1905 | DWORD dwAdditionalFlags) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1906 | { |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1907 | HGLOBAL handle; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1908 | FIND_FIRST_INFO *info; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1909 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1910 | if (!lpFileName) |
| 1911 | { |
| 1912 | SetLastError(ERROR_PATH_NOT_FOUND); |
| 1913 | return INVALID_HANDLE_VALUE; |
| 1914 | } |
| 1915 | |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1916 | if ((fSearchOp != FindExSearchNameMatch) || (dwAdditionalFlags != 0)) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1917 | { |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1918 | FIXME("options not implemented 0x%08x 0x%08lx\n", fSearchOp, dwAdditionalFlags ); |
| 1919 | return INVALID_HANDLE_VALUE; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1920 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1921 | |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1922 | switch(fInfoLevelId) |
| 1923 | { |
| 1924 | case FindExInfoStandard: |
| 1925 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1926 | WIN32_FIND_DATAW * data = (WIN32_FIND_DATAW *) lpFindFileData; |
| 1927 | char *p; |
| 1928 | INT long_mask_len; |
| 1929 | UINT codepage; |
| 1930 | |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1931 | data->dwReserved0 = data->dwReserved1 = 0x0; |
| 1932 | if (!lpFileName) return 0; |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1933 | 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 Meissner | 2a5c146 | 2002-09-16 19:27:15 +0000 | [diff] [blame] | 1940 | if(!info->u.smb_dir) |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1941 | { |
| 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 Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1955 | 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 Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1960 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1961 | 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 McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 1975 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 1976 | if (!FindNextFileW( handle, data )) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1977 | { |
| 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 Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1990 | |
| 1991 | /************************************************************************* |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1992 | * FindFirstFileA (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1993 | */ |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1994 | HANDLE WINAPI FindFirstFileA( |
| 1995 | LPCSTR lpFileName, |
| 1996 | WIN32_FIND_DATAA *lpFindData ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1997 | { |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1998 | return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData, |
| 1999 | FindExSearchNameMatch, NULL, 0); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2000 | } |
| 2001 | |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2002 | /************************************************************************* |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2003 | * FindFirstFileExA (KERNEL32.@) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2004 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2005 | HANDLE WINAPI FindFirstFileExA( |
| 2006 | LPCSTR lpFileName, |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2007 | FINDEX_INFO_LEVELS fInfoLevelId, |
| 2008 | LPVOID lpFindFileData, |
| 2009 | FINDEX_SEARCH_OPS fSearchOp, |
| 2010 | LPVOID lpSearchFilter, |
| 2011 | DWORD dwAdditionalFlags) |
| 2012 | { |
| 2013 | HANDLE handle; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2014 | WIN32_FIND_DATAA *dataA; |
| 2015 | WIN32_FIND_DATAW dataW; |
| 2016 | UNICODE_STRING pathW; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2017 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2018 | if (!lpFileName) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2019 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2020 | SetLastError(ERROR_PATH_NOT_FOUND); |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2021 | return INVALID_HANDLE_VALUE; |
| 2022 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2023 | |
| 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 Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2045 | return handle; |
| 2046 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2047 | |
| 2048 | /************************************************************************* |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2049 | * FindFirstFileW (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2050 | */ |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2051 | HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2052 | { |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2053 | return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData, |
| 2054 | FindExSearchNameMatch, NULL, 0); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2055 | } |
| 2056 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2057 | /************************************************************************* |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2058 | * FindNextFileW (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2059 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2060 | BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2061 | { |
| 2062 | FIND_FIRST_INFO *info; |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2063 | BOOL ret = FALSE; |
Rein Klazes | e1db8bd | 2002-07-20 18:53:09 +0000 | [diff] [blame] | 2064 | DWORD gle = ERROR_NO_MORE_FILES; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2065 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2066 | if ((handle == INVALID_HANDLE_VALUE) || |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2067 | !(info = (FIND_FIRST_INFO *)GlobalLock( handle ))) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2068 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 2069 | SetLastError( ERROR_INVALID_HANDLE ); |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2070 | return ret; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2071 | } |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2072 | 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 McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2079 | } |
| 2080 | goto done; |
| 2081 | } |
| 2082 | else if (!info->path || !info->u.dos_dir) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2083 | { |
Rein Klazes | e1db8bd | 2002-07-20 18:53:09 +0000 | [diff] [blame] | 2084 | goto done; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2085 | } |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2086 | else if (!DOSFS_FindNextEx( info, data )) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2087 | { |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2088 | DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL; |
Alexandre Julliard | 90476d6 | 2000-02-16 22:47:24 +0000 | [diff] [blame] | 2089 | HeapFree( GetProcessHeap(), 0, info->path ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2090 | info->path = NULL; |
| 2091 | HeapFree( GetProcessHeap(), 0, info->long_mask ); |
| 2092 | info->long_mask = NULL; |
| 2093 | goto done; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2094 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2095 | ret = TRUE; |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2096 | done: |
| 2097 | GlobalUnlock( handle ); |
Rein Klazes | e1db8bd | 2002-07-20 18:53:09 +0000 | [diff] [blame] | 2098 | if( !ret ) SetLastError( gle ); |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2099 | return ret; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2100 | } |
| 2101 | |
| 2102 | |
| 2103 | /************************************************************************* |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2104 | * FindNextFileA (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2105 | */ |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2106 | BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2107 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2108 | 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 Julliard | 072dfb5 | 2000-09-25 23:30:56 +0000 | [diff] [blame] | 2119 | data->cAlternateFileName, |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2120 | sizeof(data->cAlternateFileName), NULL, NULL ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2121 | return TRUE; |
| 2122 | } |
| 2123 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2124 | /************************************************************************* |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2125 | * FindClose (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2126 | */ |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2127 | BOOL WINAPI FindClose( HANDLE handle ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2128 | { |
| 2129 | FIND_FIRST_INFO *info; |
| 2130 | |
Marcus Meissner | 77fbbcf | 2002-05-04 18:28:36 +0000 | [diff] [blame] | 2131 | if (handle == INVALID_HANDLE_VALUE) goto error; |
| 2132 | |
Dominik Strasser | 4f46b5d | 2001-04-20 18:38:41 +0000 | [diff] [blame] | 2133 | __TRY |
| 2134 | { |
Marcus Meissner | 77fbbcf | 2002-05-04 18:28:36 +0000 | [diff] [blame] | 2135 | if ((info = (FIND_FIRST_INFO *)GlobalLock( handle ))) |
| 2136 | { |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2137 | if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir ); |
Marcus Meissner | 77fbbcf | 2002-05-04 18:28:36 +0000 | [diff] [blame] | 2138 | if (info->path) HeapFree( GetProcessHeap(), 0, info->path ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2139 | if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask ); |
Marcus Meissner | 77fbbcf | 2002-05-04 18:28:36 +0000 | [diff] [blame] | 2140 | } |
Dominik Strasser | 4f46b5d | 2001-04-20 18:38:41 +0000 | [diff] [blame] | 2141 | } |
| 2142 | __EXCEPT(page_fault) |
| 2143 | { |
| 2144 | WARN("Illegal handle %x\n", handle); |
| 2145 | SetLastError( ERROR_INVALID_HANDLE ); |
| 2146 | return FALSE; |
| 2147 | } |
| 2148 | __ENDTRY |
Marcus Meissner | 77fbbcf | 2002-05-04 18:28:36 +0000 | [diff] [blame] | 2149 | if (!info) goto error; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2150 | GlobalUnlock( handle ); |
| 2151 | GlobalFree( handle ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2152 | return TRUE; |
Marcus Meissner | 77fbbcf | 2002-05-04 18:28:36 +0000 | [diff] [blame] | 2153 | |
| 2154 | error: |
| 2155 | SetLastError( ERROR_INVALID_HANDLE ); |
| 2156 | return FALSE; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 2157 | } |
| 2158 | |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 2159 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2160 | * 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 Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2164 | * 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 Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 2168 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2169 | void DOSFS_UnixTimeToFileTime( time_t unix_time, FILETIME *filetime, |
| 2170 | DWORD remainder ) |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 2171 | { |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2172 | /* NOTES: |
| 2173 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2174 | CONSTANTS: |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2175 | 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éron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2201 | |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2202 | 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 Stridvall | 9633632 | 1999-10-24 22:13:47 +0000 | [diff] [blame] | 2224 | #if SIZEOF_LONG_LONG >= 8 |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2225 | # 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 Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2236 | filetime->dwLowDateTime = (UINT)t; |
| 2237 | filetime->dwHighDateTime = (UINT)(t >> 32); |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2238 | |
| 2239 | #else /* ISO version */ |
| 2240 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2241 | UINT a0; /* 16 bit, low bits */ |
| 2242 | UINT a1; /* 16 bit, medium bits */ |
| 2243 | UINT a2; /* 32 bit, high bits */ |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2244 | |
| 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 Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 2279 | } |
| 2280 | |
| 2281 | |
| 2282 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2283 | * DOSFS_FileTimeToUnixTime |
| 2284 | * |
| 2285 | * Convert a FILETIME format to Unix time. |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2286 | * 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 Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 2288 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2289 | time_t DOSFS_FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder ) |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 2290 | { |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2291 | /* 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 Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2296 | t += (UINT)filetime->dwLowDateTime; |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2297 | 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 Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2311 | 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 Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2315 | 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 Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2319 | a2 = (UINT)filetime->dwHighDateTime; |
| 2320 | a1 = ((UINT)filetime->dwLowDateTime ) >> 16; |
| 2321 | a0 = ((UINT)filetime->dwLowDateTime ) & 0xffff; |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2322 | |
| 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éron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2331 | |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2332 | /* If a is negative, replace a by (-1-a) */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2333 | negative = (a2 >= ((UINT)1) << 31); |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 2334 | 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 Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 2375 | } |
| 2376 | |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2377 | |
| 2378 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2379 | * MulDiv (KERNEL32.@) |
Alexandre Julliard | 15467bf | 2000-08-01 22:03:18 +0000 | [diff] [blame] | 2380 | * RETURNS |
| 2381 | * Result of multiplication and division |
| 2382 | * -1: Overflow occurred or Divisor was 0 |
| 2383 | */ |
| 2384 | INT WINAPI MulDiv( |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2385 | INT nMultiplicand, |
Alexandre Julliard | 15467bf | 2000-08-01 22:03:18 +0000 | [diff] [blame] | 2386 | 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éron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2424 | |
Alexandre Julliard | 15467bf | 2000-08-01 22:03:18 +0000 | [diff] [blame] | 2425 | return ((nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2426 | |
Alexandre Julliard | 15467bf | 2000-08-01 22:03:18 +0000 | [diff] [blame] | 2427 | #endif |
| 2428 | } |
| 2429 | |
| 2430 | |
| 2431 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2432 | * DosDateTimeToFileTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2433 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2434 | BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, LPFILETIME ft) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2435 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2436 | struct tm newtm; |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2437 | #ifndef HAVE_TIMEGM |
| 2438 | struct tm *gtm; |
| 2439 | time_t time1, time2; |
| 2440 | #endif |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2441 | |
| 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éron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2448 | #ifdef HAVE_TIMEGM |
Alexandre Julliard | 1668870 | 2002-09-12 22:28:01 +0000 | [diff] [blame] | 2449 | RtlSecondsSince1970ToTime( timegm(&newtm), (LARGE_INTEGER *)ft ); |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2450 | #else |
| 2451 | time1 = mktime(&newtm); |
| 2452 | gtm = gmtime(&time1); |
| 2453 | time2 = mktime(gtm); |
Alexandre Julliard | 1668870 | 2002-09-12 22:28:01 +0000 | [diff] [blame] | 2454 | RtlSecondsSince1970ToTime( 2*time1-time2, (LARGE_INTEGER *)ft ); |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2455 | #endif |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2456 | return TRUE; |
| 2457 | } |
| 2458 | |
| 2459 | |
| 2460 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2461 | * FileTimeToDosDateTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2462 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2463 | BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 2464 | LPWORD fattime ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2465 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2466 | time_t unixtime = DOSFS_FileTimeToUnixTime( ft, NULL ); |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2467 | struct tm *tm = gmtime( &unixtime ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2468 | 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 Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2473 | return TRUE; |
| 2474 | } |
| 2475 | |
| 2476 | |
| 2477 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2478 | * LocalFileTimeToFileTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2479 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2480 | BOOL WINAPI LocalFileTimeToFileTime( const FILETIME *localft, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 2481 | LPFILETIME utcft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2482 | { |
| 2483 | struct tm *xtm; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2484 | DWORD remainder; |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2485 | time_t utctime; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2486 | |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2487 | /* 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éron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2493 | return TRUE; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2494 | } |
| 2495 | |
| 2496 | |
| 2497 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2498 | * FileTimeToLocalFileTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2499 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2500 | BOOL WINAPI FileTimeToLocalFileTime( const FILETIME *utcft, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 2501 | LPFILETIME localft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2502 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2503 | DWORD remainder; |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2504 | /* Converts from UTC to local. */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2505 | time_t unixtime = DOSFS_FileTimeToUnixTime( utcft, &remainder ); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2506 | #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éron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2514 | struct tm *xtm; |
| 2515 | time_t time; |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2516 | |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2517 | xtm = gmtime( &unixtime ); |
| 2518 | time = mktime(xtm); |
| 2519 | if(xtm->tm_isdst > 0) time-=3600; |
| 2520 | DOSFS_UnixTimeToFileTime( 2*unixtime-time, localft, remainder ); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2521 | #endif |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2522 | return TRUE; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2523 | } |
| 2524 | |
| 2525 | |
| 2526 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2527 | * FileTimeToSystemTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2528 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2529 | BOOL WINAPI FileTimeToSystemTime( const FILETIME *ft, LPSYSTEMTIME syst ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2530 | { |
| 2531 | struct tm *xtm; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2532 | DWORD remainder; |
| 2533 | time_t xtime = DOSFS_FileTimeToUnixTime( ft, &remainder ); |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2534 | xtm = gmtime(&xtime); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2535 | syst->wYear = xtm->tm_year+1900; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 2536 | syst->wMonth = xtm->tm_mon + 1; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2537 | 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éron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2543 | return TRUE; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2544 | } |
| 2545 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2546 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2547 | * QueryDosDeviceA (KERNEL32.@) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2548 | * |
| 2549 | * returns array of strings terminated by \0, terminated by \0 |
| 2550 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2551 | DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2552 | { |
| 2553 | LPSTR s; |
| 2554 | char buffer[200]; |
| 2555 | |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2556 | TRACE("(%s,...)\n", devname ? devname : "<null>"); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2557 | if (!devname) { |
| 2558 | /* return known MSDOS devices */ |
Alexandre Julliard | 24a62ab | 2000-11-28 22:40:56 +0000 | [diff] [blame] | 2559 | 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2562 | } |
Marcus Meissner | 04d5efd | 2001-05-25 20:39:45 +0000 | [diff] [blame] | 2563 | /* 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éron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2566 | * (It is more complex, and supports netmounted stuff, and \\.\ stuff, |
Marcus Meissner | 04d5efd | 2001-05-25 20:39:45 +0000 | [diff] [blame] | 2567 | * 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2585 | } |
| 2586 | |
| 2587 | |
| 2588 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2589 | * QueryDosDeviceW (KERNEL32.@) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2590 | * |
| 2591 | * returns array of strings terminated by \0, terminated by \0 |
| 2592 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2593 | DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2594 | { |
| 2595 | LPSTR devnameA = devname?HEAP_strdupWtoA(GetProcessHeap(),0,devname):NULL; |
Dimitrie O. Paun | abdbced | 2000-04-29 14:20:28 +0000 | [diff] [blame] | 2596 | LPSTR targetA = (LPSTR)HeapAlloc(GetProcessHeap(),0,bufsize); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2597 | DWORD ret = QueryDosDeviceA(devnameA,targetA,bufsize); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2598 | |
Alexandre Julliard | 24a62ab | 2000-11-28 22:40:56 +0000 | [diff] [blame] | 2599 | ret = MultiByteToWideChar( CP_ACP, 0, targetA, ret, target, bufsize ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2600 | if (devnameA) HeapFree(GetProcessHeap(),0,devnameA); |
| 2601 | if (targetA) HeapFree(GetProcessHeap(),0,targetA); |
| 2602 | return ret; |
| 2603 | } |
| 2604 | |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2605 | |
| 2606 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2607 | * SystemTimeToFileTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2608 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2609 | BOOL WINAPI SystemTimeToFileTime( const SYSTEMTIME *syst, LPFILETIME ft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2610 | { |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2611 | #ifdef HAVE_TIMEGM |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2612 | struct tm xtm; |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2613 | time_t utctime; |
| 2614 | #else |
Vincent Béron | a032277 | 2002-05-30 20:05:48 +0000 | [diff] [blame] | 2615 | struct tm xtm,*utc_tm; |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2616 | time_t localtim,utctime; |
| 2617 | #endif |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2618 | |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2619 | xtm.tm_year = syst->wYear-1900; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 2620 | xtm.tm_mon = syst->wMonth - 1; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2621 | xtm.tm_wday = syst->wDayOfWeek; |
| 2622 | xtm.tm_mday = syst->wDay; |
| 2623 | xtm.tm_hour = syst->wHour; |
| 2624 | xtm.tm_min = syst->wMinute; |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2625 | xtm.tm_sec = syst->wSecond; /* this is UTC */ |
| 2626 | xtm.tm_isdst = -1; |
| 2627 | #ifdef HAVE_TIMEGM |
| 2628 | utctime = timegm(&xtm); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2629 | DOSFS_UnixTimeToFileTime( utctime, ft, |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2630 | syst->wMilliseconds * 10000 ); |
| 2631 | #else |
| 2632 | localtim = mktime(&xtm); /* now we've got local time */ |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2633 | utc_tm = gmtime(&localtim); |
| 2634 | utctime = mktime(utc_tm); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2635 | DOSFS_UnixTimeToFileTime( 2*localtim -utctime, ft, |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2636 | syst->wMilliseconds * 10000 ); |
| 2637 | #endif |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2638 | return TRUE; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2639 | } |
Marcus Meissner | 575a165 | 1998-10-21 16:47:29 +0000 | [diff] [blame] | 2640 | |
Patrik Stridvall | 3a9c476 | 1999-10-31 02:07:05 +0000 | [diff] [blame] | 2641 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2642 | * DefineDosDeviceA (KERNEL32.@) |
Patrik Stridvall | 3a9c476 | 1999-10-31 02:07:05 +0000 | [diff] [blame] | 2643 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2644 | BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) { |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2645 | FIXME("(0x%08lx,%s,%s),stub!\n",flags,devname,targetpath); |
Marcus Meissner | 575a165 | 1998-10-21 16:47:29 +0000 | [diff] [blame] | 2646 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| 2647 | return FALSE; |
| 2648 | } |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2649 | |
| 2650 | /* |
| 2651 | --- 16 bit functions --- |
| 2652 | */ |
| 2653 | |
| 2654 | /************************************************************************* |
Patrik Stridvall | 01d5e5b | 2001-07-02 19:59:40 +0000 | [diff] [blame] | 2655 | * FindFirstFile (KERNEL.413) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2656 | */ |
| 2657 | HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data ) |
| 2658 | { |
| 2659 | DOS_FULL_NAME full_name; |
| 2660 | HGLOBAL16 handle; |
| 2661 | FIND_FIRST_INFO *info; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2662 | WCHAR pathW[MAX_PATH]; |
| 2663 | char *p; |
| 2664 | INT long_mask_len; |
| 2665 | UINT codepage; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2666 | |
| 2667 | data->dwReserved0 = data->dwReserved1 = 0x0; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2668 | 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 Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2671 | 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 Julliard | 5f728ca | 2001-07-24 21:45:22 +0000 | [diff] [blame] | 2675 | info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 ); |
| 2676 | strcpy( info->path, full_name.long_name ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2677 | |
| 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 Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2685 | info->short_mask = NULL; |
| 2686 | info->attr = 0xff; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2687 | info->drive = full_name.drive; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2688 | info->cur_pos = 0; |
| 2689 | |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2690 | info->u.dos_dir = DOSFS_OpenDir( codepage, info->path ); |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2691 | |
| 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 Stridvall | 01d5e5b | 2001-07-02 19:59:40 +0000 | [diff] [blame] | 2703 | * FindNextFile (KERNEL.414) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2704 | */ |
| 2705 | BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data ) |
| 2706 | { |
| 2707 | FIND_FIRST_INFO *info; |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2708 | WIN32_FIND_DATAW dataW; |
| 2709 | BOOL ret = FALSE; |
| 2710 | DWORD gle = ERROR_NO_MORE_FILES; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2711 | |
| 2712 | if ((handle == INVALID_HANDLE_VALUE16) || |
| 2713 | !(info = (FIND_FIRST_INFO *)GlobalLock16( handle ))) |
| 2714 | { |
| 2715 | SetLastError( ERROR_INVALID_HANDLE ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2716 | return ret; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2717 | } |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2718 | if (!info->path || !info->u.dos_dir) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2719 | { |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2720 | goto done; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2721 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2722 | if (!DOSFS_FindNextEx( info, &dataW )) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2723 | { |
Mike McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2724 | DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL; |
Alexandre Julliard | 61d32b4 | 2001-02-23 01:35:36 +0000 | [diff] [blame] | 2725 | HeapFree( GetProcessHeap(), 0, info->path ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2726 | info->path = NULL; |
| 2727 | HeapFree( GetProcessHeap(), 0, info->long_mask ); |
| 2728 | info->long_mask = NULL; |
| 2729 | goto done; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2730 | } |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2731 | |
| 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 ); |
| 2745 | done: |
| 2746 | if( !ret ) SetLastError( gle ); |
| 2747 | GlobalUnlock16( handle ); |
| 2748 | |
| 2749 | return ret; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2750 | } |
| 2751 | |
| 2752 | /************************************************************************* |
Patrik Stridvall | 01d5e5b | 2001-07-02 19:59:40 +0000 | [diff] [blame] | 2753 | * FindClose (KERNEL.415) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2754 | */ |
| 2755 | BOOL16 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 McCormack | 963985b | 2002-07-19 03:17:19 +0000 | [diff] [blame] | 2765 | if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir ); |
Alexandre Julliard | 61d32b4 | 2001-02-23 01:35:36 +0000 | [diff] [blame] | 2766 | if (info->path) HeapFree( GetProcessHeap(), 0, info->path ); |
Dmitry Timoshkov | d75aed2 | 2002-08-27 01:13:58 +0000 | [diff] [blame] | 2767 | if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask ); |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2768 | GlobalUnlock16( handle ); |
| 2769 | GlobalFree16( handle ); |
| 2770 | return TRUE; |
| 2771 | } |