2 * File handling functions
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
6 * Copyright 2003 Eric Pouech
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "wine/port.h"
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(file
);
43 #define MAX_PATHNAME_LEN 1024
45 /***********************************************************************
46 * GetFullPathNameW (KERNEL32.@)
48 * if the path closed with '\', *lastpart is 0
50 DWORD WINAPI
GetFullPathNameW( LPCWSTR name
, DWORD len
, LPWSTR buffer
,
53 return RtlGetFullPathName_U(name
, len
* sizeof(WCHAR
), buffer
, lastpart
) / sizeof(WCHAR
);
56 /***********************************************************************
57 * GetFullPathNameA (KERNEL32.@)
59 * if the path closed with '\', *lastpart is 0
61 DWORD WINAPI
GetFullPathNameA( LPCSTR name
, DWORD len
, LPSTR buffer
,
65 WCHAR bufferW
[MAX_PATH
];
70 SetLastError(ERROR_INVALID_PARAMETER
);
74 if (!RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
76 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
80 retW
= GetFullPathNameW( nameW
.Buffer
, MAX_PATH
, bufferW
, NULL
);
84 else if (retW
> MAX_PATH
)
86 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
91 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
92 if (ret
&& ret
<= len
)
94 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, len
, NULL
, NULL
);
95 ret
--; /* length without 0 */
99 LPSTR p
= buffer
+ strlen(buffer
) - 1;
103 while ((p
> buffer
+ 2) && (*p
!= '\\')) p
--;
106 else *lastpart
= NULL
;
111 RtlFreeUnicodeString(&nameW
);
116 /***********************************************************************
117 * GetLongPathNameW (KERNEL32.@)
120 * observed (Win2000):
121 * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
122 * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0
124 DWORD WINAPI
GetLongPathNameW( LPCWSTR shortpath
, LPWSTR longpath
, DWORD longlen
)
126 WCHAR tmplongpath
[MAX_PATHNAME_LEN
];
128 DWORD sp
= 0, lp
= 0;
130 BOOL unixabsolute
= (shortpath
[0] == '/');
131 WIN32_FIND_DATAW wfd
;
136 SetLastError(ERROR_INVALID_PARAMETER
);
141 SetLastError(ERROR_PATH_NOT_FOUND
);
145 TRACE("%s,%p,%ld\n", debugstr_w(shortpath
), longpath
, longlen
);
147 if (shortpath
[0] == '\\' && shortpath
[1] == '\\')
149 ERR("UNC pathname %s\n", debugstr_w(shortpath
));
150 lstrcpynW( longpath
, shortpath
, longlen
);
151 return strlenW(longpath
);
154 /* check for drive letter */
155 if (!unixabsolute
&& shortpath
[1] == ':' )
157 tmplongpath
[0] = shortpath
[0];
158 tmplongpath
[1] = ':';
162 while (shortpath
[sp
])
164 /* check for path delimiters and reproduce them */
165 if (shortpath
[sp
] == '\\' || shortpath
[sp
] == '/')
167 if (!lp
|| tmplongpath
[lp
-1] != '\\')
169 /* strip double "\\" */
170 tmplongpath
[lp
++] = '\\';
172 tmplongpath
[lp
] = 0; /* terminate string */
178 if (sp
== 0 && p
[0] == '.' && (p
[1] == '/' || p
[1] == '\\'))
180 tmplongpath
[lp
++] = *p
++;
181 tmplongpath
[lp
++] = *p
++;
183 for (; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
184 tmplen
= p
- (shortpath
+ sp
);
185 lstrcpynW(tmplongpath
+ lp
, shortpath
+ sp
, tmplen
+ 1);
186 /* Check if the file exists and use the existing file name */
187 goit
= FindFirstFileW(tmplongpath
, &wfd
);
188 if (goit
== INVALID_HANDLE_VALUE
)
190 TRACE("not found %s!\n", debugstr_w(tmplongpath
));
191 SetLastError ( ERROR_FILE_NOT_FOUND
);
195 strcpyW(tmplongpath
+ lp
, wfd
.cFileName
);
196 lp
+= strlenW(tmplongpath
+ lp
);
199 tmplen
= strlenW(shortpath
) - 1;
200 if ((shortpath
[tmplen
] == '/' || shortpath
[tmplen
] == '\\') &&
201 (tmplongpath
[lp
- 1] != '/' && tmplongpath
[lp
- 1] != '\\'))
202 tmplongpath
[lp
++] = shortpath
[tmplen
];
205 tmplen
= strlenW(tmplongpath
) + 1;
206 if (tmplen
<= longlen
)
208 strcpyW(longpath
, tmplongpath
);
209 TRACE("returning %s\n", debugstr_w(longpath
));
210 tmplen
--; /* length without 0 */
216 /***********************************************************************
217 * GetLongPathNameA (KERNEL32.@)
219 DWORD WINAPI
GetLongPathNameA( LPCSTR shortpath
, LPSTR longpath
, DWORD longlen
)
221 UNICODE_STRING shortpathW
;
222 WCHAR longpathW
[MAX_PATH
];
227 SetLastError(ERROR_INVALID_PARAMETER
);
231 TRACE("%s\n", debugstr_a(shortpath
));
233 if (!RtlCreateUnicodeStringFromAsciiz(&shortpathW
, shortpath
))
235 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
239 retW
= GetLongPathNameW(shortpathW
.Buffer
, longpathW
, MAX_PATH
);
243 else if (retW
> MAX_PATH
)
245 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
250 ret
= WideCharToMultiByte(CP_ACP
, 0, longpathW
, -1, NULL
, 0, NULL
, NULL
);
253 WideCharToMultiByte(CP_ACP
, 0, longpathW
, -1, longpath
, longlen
, NULL
, NULL
);
254 ret
--; /* length without 0 */
258 RtlFreeUnicodeString(&shortpathW
);
263 /***********************************************************************
264 * GetShortPathNameW (KERNEL32.@)
268 * longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
269 * longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0
271 * more observations ( with NT 3.51 (WinDD) ):
272 * longpath <= 8.3 -> just copy longpath to shortpath
274 * a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND
275 * b) file does exist -> set the short filename.
276 * - trailing slashes are reproduced in the short name, even if the
277 * file is not a directory
278 * - the absolute/relative path of the short name is reproduced like found
280 * - longpath and shortpath may have the same address
283 DWORD WINAPI
GetShortPathNameW( LPCWSTR longpath
, LPWSTR shortpath
, DWORD shortlen
)
285 WCHAR tmpshortpath
[MAX_PATHNAME_LEN
];
287 DWORD sp
= 0, lp
= 0;
289 BOOL unixabsolute
= (longpath
[0] == '/');
290 WIN32_FIND_DATAW wfd
;
293 WCHAR ustr_buf
[8+1+3+1];
295 TRACE("%s\n", debugstr_w(longpath
));
299 SetLastError(ERROR_INVALID_PARAMETER
);
304 SetLastError(ERROR_BAD_PATHNAME
);
308 /* check for drive letter */
309 if (!unixabsolute
&& longpath
[1] == ':' )
311 tmpshortpath
[0] = longpath
[0];
312 tmpshortpath
[1] = ':';
316 ustr
.Buffer
= ustr_buf
;
318 ustr
.MaximumLength
= sizeof(ustr_buf
);
322 /* check for path delimiters and reproduce them */
323 if (longpath
[lp
] == '\\' || longpath
[lp
] == '/')
325 if (!sp
|| tmpshortpath
[sp
-1] != '\\')
327 /* strip double "\\" */
328 tmpshortpath
[sp
] = '\\';
331 tmpshortpath
[sp
] = 0; /* terminate string */
336 for (p
= longpath
+ lp
; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
337 tmplen
= p
- (longpath
+ lp
);
338 lstrcpynW(tmpshortpath
+ sp
, longpath
+ lp
, tmplen
+ 1);
339 /* Check, if the current element is a valid dos name */
340 if (tmplen
<= 8+1+3+1)
342 memcpy(ustr_buf
, longpath
+ lp
, tmplen
* sizeof(WCHAR
));
343 ustr_buf
[tmplen
] = '\0';
344 ustr
.Length
= tmplen
* sizeof(WCHAR
);
345 if (RtlIsNameLegalDOS8Dot3(&ustr
, NULL
, NULL
))
353 /* Check if the file exists and use the existing short file name */
354 goit
= FindFirstFileW(tmpshortpath
, &wfd
);
355 if (goit
== INVALID_HANDLE_VALUE
) goto notfound
;
357 strcpyW(tmpshortpath
+ sp
, wfd
.cAlternateFileName
);
358 sp
+= strlenW(tmpshortpath
+ sp
);
361 tmpshortpath
[sp
] = 0;
363 tmplen
= strlenW(tmpshortpath
) + 1;
364 if (tmplen
<= shortlen
)
366 strcpyW(shortpath
, tmpshortpath
);
367 TRACE("returning %s\n", debugstr_w(shortpath
));
368 tmplen
--; /* length without 0 */
374 TRACE("not found!\n" );
375 SetLastError ( ERROR_FILE_NOT_FOUND
);
379 /***********************************************************************
380 * GetShortPathNameA (KERNEL32.@)
382 DWORD WINAPI
GetShortPathNameA( LPCSTR longpath
, LPSTR shortpath
, DWORD shortlen
)
384 UNICODE_STRING longpathW
;
385 WCHAR shortpathW
[MAX_PATH
];
390 SetLastError(ERROR_INVALID_PARAMETER
);
394 TRACE("%s\n", debugstr_a(longpath
));
396 if (!RtlCreateUnicodeStringFromAsciiz(&longpathW
, longpath
))
398 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
402 retW
= GetShortPathNameW(longpathW
.Buffer
, shortpathW
, MAX_PATH
);
406 else if (retW
> MAX_PATH
)
408 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
413 ret
= WideCharToMultiByte(CP_ACP
, 0, shortpathW
, -1, NULL
, 0, NULL
, NULL
);
416 WideCharToMultiByte(CP_ACP
, 0, shortpathW
, -1, shortpath
, shortlen
, NULL
, NULL
);
417 ret
--; /* length without 0 */
421 RtlFreeUnicodeString(&longpathW
);