Unicodify some comm functions.
[wine] / dlls / kernel / path.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 Erik Bos
5  * Copyright 1996 Alexandre Julliard
6  * Copyright 2003 Eric Pouech
7  *
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.
12  *
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.
17  *
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
21  *
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <stdarg.h>
28
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31 #include "winerror.h"
32 #include "ntstatus.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winreg.h"
36 #include "winternl.h"
37
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(file);
42
43 #define MAX_PATHNAME_LEN        1024
44
45
46 /***********************************************************************
47  *           GetLongPathNameW   (KERNEL32.@)
48  *
49  * NOTES
50  *  observed (Win2000):
51  *  shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
52  *  shortpath="":   LastError=ERROR_PATH_NOT_FOUND, ret=0
53  */
54 DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen )
55 {
56     WCHAR               tmplongpath[MAX_PATHNAME_LEN];
57     LPCWSTR             p;
58     DWORD               sp = 0, lp = 0;
59     DWORD               tmplen;
60     BOOL                unixabsolute = (shortpath[0] == '/');
61     WIN32_FIND_DATAW    wfd;
62     HANDLE              goit;
63
64     if (!shortpath)
65     {
66         SetLastError(ERROR_INVALID_PARAMETER);
67         return 0;
68     }
69     if (!shortpath[0])
70     {
71         SetLastError(ERROR_PATH_NOT_FOUND);
72         return 0;
73     }
74
75     TRACE("%s,%p,%ld\n", debugstr_w(shortpath), longpath, longlen);
76
77     if (shortpath[0] == '\\' && shortpath[1] == '\\')
78     {
79         ERR("UNC pathname %s\n", debugstr_w(shortpath));
80         lstrcpynW( longpath, shortpath, longlen );
81         return strlenW(longpath);
82     }
83
84     /* check for drive letter */
85     if (!unixabsolute && shortpath[1] == ':' )
86     {
87         tmplongpath[0] = shortpath[0];
88         tmplongpath[1] = ':';
89         lp = sp = 2;
90     }
91
92     while (shortpath[sp])
93     {
94         /* check for path delimiters and reproduce them */
95         if (shortpath[sp] == '\\' || shortpath[sp] == '/')
96         {
97             if (!lp || tmplongpath[lp-1] != '\\')
98             {
99                 /* strip double "\\" */
100                 tmplongpath[lp++] = '\\';
101             }
102             tmplongpath[lp] = 0; /* terminate string */
103             sp++;
104             continue;
105         }
106
107         p = shortpath + sp;
108         if (sp == 0 && p[0] == '.' && (p[1] == '/' || p[1] == '\\'))
109         {
110             tmplongpath[lp++] = *p++;
111             tmplongpath[lp++] = *p++;
112         }
113         for (; *p && *p != '/' && *p != '\\'; p++);
114         tmplen = p - (shortpath + sp);
115         lstrcpynW(tmplongpath + lp, shortpath + sp, tmplen + 1);
116         /* Check if the file exists and use the existing file name */
117         goit = FindFirstFileW(tmplongpath, &wfd);
118         if (goit == INVALID_HANDLE_VALUE)
119         {
120             TRACE("not found %s!\n", debugstr_w(tmplongpath));
121             SetLastError ( ERROR_FILE_NOT_FOUND );
122             return 0;
123         }
124         FindClose(goit);
125         strcpyW(tmplongpath + lp, wfd.cFileName);
126         lp += strlenW(tmplongpath + lp);
127         sp += tmplen;
128     }
129     tmplen = strlenW(shortpath) - 1;
130     if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\\') &&
131         (tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\\'))
132         tmplongpath[lp++] = shortpath[tmplen];
133     tmplongpath[lp] = 0;
134
135     tmplen = strlenW(tmplongpath) + 1;
136     if (tmplen <= longlen)
137     {
138         strcpyW(longpath, tmplongpath);
139         TRACE("returning %s\n", debugstr_w(longpath));
140         tmplen--; /* length without 0 */
141     }
142
143     return tmplen;
144 }
145
146 /***********************************************************************
147  *           GetLongPathNameA   (KERNEL32.@)
148  */
149 DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen )
150 {
151     UNICODE_STRING shortpathW;
152     WCHAR longpathW[MAX_PATH];
153     DWORD ret, retW;
154
155     if (!shortpath)
156     {
157         SetLastError(ERROR_INVALID_PARAMETER);
158         return 0;
159     }
160
161     TRACE("%s\n", debugstr_a(shortpath));
162
163     if (!RtlCreateUnicodeStringFromAsciiz(&shortpathW, shortpath))
164     {
165         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
166         return 0;
167     }
168
169     retW = GetLongPathNameW(shortpathW.Buffer, longpathW, MAX_PATH);
170
171     if (!retW)
172         ret = 0;
173     else if (retW > MAX_PATH)
174     {
175         SetLastError(ERROR_FILENAME_EXCED_RANGE);
176         ret = 0;
177     }
178     else
179     {
180         ret = WideCharToMultiByte(CP_ACP, 0, longpathW, -1, NULL, 0, NULL, NULL);
181         if (ret <= longlen)
182         {
183             WideCharToMultiByte(CP_ACP, 0, longpathW, -1, longpath, longlen, NULL, NULL);
184             ret--; /* length without 0 */
185         }
186     }
187
188     RtlFreeUnicodeString(&shortpathW);
189     return ret;
190 }
191
192
193 /***********************************************************************
194  *           GetShortPathNameW   (KERNEL32.@)
195  *
196  * NOTES
197  *  observed:
198  *  longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
199  *  longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0
200  *
201  * more observations ( with NT 3.51 (WinDD) ):
202  * longpath <= 8.3 -> just copy longpath to shortpath
203  * longpath > 8.3  ->
204  *             a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND
205  *             b) file does exist     -> set the short filename.
206  * - trailing slashes are reproduced in the short name, even if the
207  *   file is not a directory
208  * - the absolute/relative path of the short name is reproduced like found
209  *   in the long name
210  * - longpath and shortpath may have the same address
211  * Peter Ganten, 1999
212  */
213 DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen )
214 {
215     WCHAR               tmpshortpath[MAX_PATHNAME_LEN];
216     LPCWSTR             p;
217     DWORD               sp = 0, lp = 0;
218     DWORD               tmplen;
219     BOOL                unixabsolute = (longpath[0] == '/');
220     WIN32_FIND_DATAW    wfd;
221     HANDLE              goit;
222     UNICODE_STRING      ustr;
223     WCHAR               ustr_buf[8+1+3+1];
224
225     TRACE("%s\n", debugstr_w(longpath));
226
227     if (!longpath)
228     {
229         SetLastError(ERROR_INVALID_PARAMETER);
230         return 0;
231     }
232     if (!longpath[0])
233     {
234         SetLastError(ERROR_BAD_PATHNAME);
235         return 0;
236     }
237
238     /* check for drive letter */
239     if (!unixabsolute && longpath[1] == ':' )
240     {
241         tmpshortpath[0] = longpath[0];
242         tmpshortpath[1] = ':';
243         sp = lp = 2;
244     }
245
246     ustr.Buffer = ustr_buf;
247     ustr.Length = 0;
248     ustr.MaximumLength = sizeof(ustr_buf);
249
250     while (longpath[lp])
251     {
252         /* check for path delimiters and reproduce them */
253         if (longpath[lp] == '\\' || longpath[lp] == '/')
254         {
255             if (!sp || tmpshortpath[sp-1] != '\\')
256             {
257                 /* strip double "\\" */
258                 tmpshortpath[sp] = '\\';
259                 sp++;
260             }
261             tmpshortpath[sp] = 0; /* terminate string */
262             lp++;
263             continue;
264         }
265
266         for (p = longpath + lp; *p && *p != '/' && *p != '\\'; p++);
267         tmplen = p - (longpath + lp);
268         lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1);
269         if (tmplen <= 8+1+3+1)
270         {
271             memcpy(ustr_buf, longpath + lp, tmplen * sizeof(WCHAR));
272             ustr_buf[tmplen] = '\0';
273             ustr.Length = tmplen * sizeof(WCHAR);
274             /* Check, if the current element is a valid dos name */
275             if (!RtlIsNameLegalDOS8Dot3(&ustr, NULL, NULL))
276                 goto notfound;
277             sp += tmplen;
278             lp += tmplen;
279             continue;
280         }
281
282         /* Check if the file exists and use the existing file name */
283         goit = FindFirstFileW(tmpshortpath, &wfd);
284         if (goit == INVALID_HANDLE_VALUE) goto notfound;
285         FindClose(goit);
286         strcpyW(tmpshortpath + sp, wfd.cAlternateFileName);
287         sp += strlenW(tmpshortpath + sp);
288         lp += tmplen;
289     }
290     tmpshortpath[sp] = 0;
291
292     tmplen = strlenW(tmpshortpath) + 1;
293     if (tmplen <= shortlen)
294     {
295         strcpyW(shortpath, tmpshortpath);
296         TRACE("returning %s\n", debugstr_w(shortpath));
297         tmplen--; /* length without 0 */
298     }
299
300     return tmplen;
301
302  notfound:
303     TRACE("not found!\n" );
304     SetLastError ( ERROR_FILE_NOT_FOUND );
305     return 0;
306 }
307
308 /***********************************************************************
309  *           GetShortPathNameA   (KERNEL32.@)
310  */
311 DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen )
312 {
313     UNICODE_STRING longpathW;
314     WCHAR shortpathW[MAX_PATH];
315     DWORD ret, retW;
316
317     if (!longpath)
318     {
319         SetLastError(ERROR_INVALID_PARAMETER);
320         return 0;
321     }
322
323     TRACE("%s\n", debugstr_a(longpath));
324
325     if (!RtlCreateUnicodeStringFromAsciiz(&longpathW, longpath))
326     {
327         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
328         return 0;
329     }
330
331     retW = GetShortPathNameW(longpathW.Buffer, shortpathW, MAX_PATH);
332
333     if (!retW)
334         ret = 0;
335     else if (retW > MAX_PATH)
336     {
337         SetLastError(ERROR_FILENAME_EXCED_RANGE);
338         ret = 0;
339     }
340     else
341     {
342         ret = WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, NULL, 0, NULL, NULL);
343         if (ret <= shortlen)
344         {
345             WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, shortpath, shortlen, NULL, NULL);
346             ret--; /* length without 0 */
347         }
348     }
349
350     RtlFreeUnicodeString(&longpathW);
351     return ret;
352 }