whoops - silly mistake in templates
[reactos.git] / posix / lib / psxdll / misc / path.c
1 /* $Id: path.c,v 1.2 2002/02/20 09:17:57 hyperion Exp $
2 */
3 /*
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS POSIX+ Subsystem
6 * FILE: subsys/psx/lib/psxdll/misc/path.c
7 * PURPOSE: POSIX subsystem path utilities
8 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
9 * UPDATE HISTORY:
10 * 31/01/2002: Created
11 */
12
13 #include <ddk/ntddk.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <psx/stdlib.h>
17 #include <psx/pdata.h>
18 #include <psx/path.h>
19
20 BOOLEAN
21 __PdxPosixPathGetNextComponent_U
22 (
23 IN UNICODE_STRING PathName,
24 IN OUT PUNICODE_STRING PathComponent,
25 OUT PBOOLEAN TrailingDelimiter OPTIONAL
26 )
27 {
28 int i, j;
29 USHORT l = PathName.Length / sizeof(WCHAR);
30
31 if(PathComponent->Buffer == 0)
32 i = 0;
33 else
34 i = ((ULONG)PathComponent->Buffer - (ULONG)PathName.Buffer + PathComponent->Length) / sizeof(WCHAR);
35
36 /* skip leading empty components */
37 while(1)
38 if(i >= l)
39 {
40 PathComponent->Length = PathComponent->MaximumLength = 0;
41 return (FALSE);
42 }
43 else if(IS_CHAR_DELIMITER_U(PathName.Buffer[i]))
44 i ++;
45 else
46 break;
47
48 if(i > l)
49 {
50 PathComponent->Length = PathComponent->MaximumLength = 0;
51 return (FALSE);
52 }
53
54 PathComponent->Buffer = &PathName.Buffer[i];
55
56 j = i + 1;
57
58 /* advance until the end of the string, or the next delimiter */
59 while(1)
60 {
61 if(j >= l)
62 {
63
64 if(TrailingDelimiter != 0)
65 *TrailingDelimiter = FALSE;
66
67 break;
68 }
69 else if (IS_CHAR_DELIMITER_U(PathName.Buffer[j]))
70 {
71
72 if(TrailingDelimiter != 0)
73 *TrailingDelimiter = TRUE;
74
75 break;
76 }
77 else
78 j ++;
79 }
80
81 PathComponent->Length = PathComponent->MaximumLength = (j - i) * sizeof(WCHAR);
82
83 return (TRUE);
84
85 }
86
87 BOOLEAN
88 __PdxPosixPathResolve_U
89 (
90 IN UNICODE_STRING PathName,
91 OUT PUNICODE_STRING ResolvedPathName,
92 IN WCHAR PathDelimiter OPTIONAL
93 )
94 {
95 UNICODE_STRING wstrThisComponent = {0, 0, NULL};
96 PWCHAR pwcCurPos;
97 PWCHAR pwcStartPos;
98 BOOLEAN bIsDirectory;
99
100 if(PathDelimiter == 0)
101 PathDelimiter = L'/';
102
103 /* start from the beginning of the return buffer */
104 pwcCurPos = ResolvedPathName->Buffer;
105
106 /* path begins with a delimiter (absolute path) */
107 if(IS_CHAR_DELIMITER_U(PathName.Buffer[0]))
108 {
109 /* put a delimiter in front of the return buffer */
110 *pwcCurPos = PathDelimiter;
111 /* move to next character */
112 pwcCurPos ++;
113 }
114
115 pwcStartPos = pwcCurPos;
116
117 /* repeat until the end of the path string */
118 while(__PdxPosixPathGetNextComponent_U(PathName, &wstrThisComponent, &bIsDirectory))
119 {
120 /* ".": skip */
121 if(IS_COMPONENT_DOT_U(wstrThisComponent))
122 continue;
123 /* "..": go back to the last component */
124 else if(IS_COMPONENT_DOTDOT_U(wstrThisComponent))
125 {
126 if(pwcCurPos == pwcStartPos)
127 continue;
128
129 /* skip the last (undefined) character */
130 pwcCurPos --;
131 /* down to the previous path delimiter */
132 do{ pwcCurPos --; }while(!IS_CHAR_DELIMITER_U(*pwcCurPos));
133 /* include the delimiter */
134 pwcCurPos ++;
135 }
136 else
137 {
138 /* copy this component into the return string */
139 memcpy
140 (
141 pwcCurPos,
142 wstrThisComponent.Buffer,
143 wstrThisComponent.Length
144 );
145
146 /* move the current position to the end of the string */
147 pwcCurPos = (PWCHAR)((PBYTE)pwcCurPos + wstrThisComponent.Length);
148
149 /* component had a trailing delimiter */
150 if(bIsDirectory)
151 {
152 /* append a delimiter */
153 *pwcCurPos = PathDelimiter;
154 /* on to next character */
155 pwcCurPos ++;
156 }
157 }
158 }
159
160 /* set the return string's length as the byte offset between the initial buffer
161 position and the current position */
162 ResolvedPathName->Length = ((ULONG)pwcCurPos - (ULONG)ResolvedPathName->Buffer);
163
164 return (TRUE);
165
166 }
167
168 BOOLEAN
169 __PdxPosixPathGetNextComponent_A
170 (
171 IN ANSI_STRING PathName,
172 IN OUT PANSI_STRING PathComponent,
173 OUT PBOOLEAN TrailingDelimiter OPTIONAL
174 )
175 {
176 int i, j;
177
178 if(PathComponent->Buffer == 0)
179 i = 0;
180 else
181 i = ((ULONG)PathComponent->Buffer - (ULONG)PathName.Buffer + PathComponent->Length);
182
183 /* skip leading empty components */
184 while(1)
185 if(i >= PathName.Length)
186 {
187 PathComponent->Length = PathComponent->MaximumLength = 0;
188 return (FALSE);
189 }
190 else if(IS_CHAR_DELIMITER_A(PathName.Buffer[i]))
191 i ++;
192 else
193 break;
194
195 if(i > PathName.Length)
196 {
197 PathComponent->Length = PathComponent->MaximumLength = 0;
198 return (FALSE);
199 }
200
201 PathComponent->Buffer = &PathName.Buffer[i];
202
203 j = i + 1;
204
205 /* advance until the end of the string, or the next delimiter */
206 while(1)
207 {
208 if(j >= PathName.Length)
209 {
210
211 if(TrailingDelimiter != 0)
212 *TrailingDelimiter = FALSE;
213
214 break;
215 }
216 else if (IS_CHAR_DELIMITER_A(PathName.Buffer[j]))
217 {
218
219 if(TrailingDelimiter != 0)
220 *TrailingDelimiter = TRUE;
221
222 break;
223 }
224 else
225 j ++;
226 }
227
228 PathComponent->Length = PathComponent->MaximumLength = j - i;
229
230 return (TRUE);
231
232 }
233
234 BOOLEAN
235 __PdxPosixPathResolve_A
236 (
237 IN ANSI_STRING PathName,
238 OUT PANSI_STRING ResolvedPathName,
239 IN CHAR PathDelimiter OPTIONAL
240 )
241 {
242 ANSI_STRING strThisComponent = {0, 0, NULL};
243 PCHAR pcCurPos;
244 PCHAR pcStartPos;
245 BOOLEAN bIsDirectory;
246
247 if(PathDelimiter == 0)
248 PathDelimiter = '/';
249
250 /* start from the beginning of the return buffer */
251 pcCurPos = ResolvedPathName->Buffer;
252
253 /* path begins with a delimiter (absolute path) */
254 if(IS_CHAR_DELIMITER_A(PathName.Buffer[0]))
255 {
256 /* put a delimiter in front of the return buffer */
257 *pcCurPos = PathDelimiter;
258 /* move to next character */
259 pcCurPos ++;
260 }
261
262 pcStartPos = pcCurPos;
263
264 /* repeat until the end of the path string */
265 while(__PdxPosixPathGetNextComponent_A(PathName, &strThisComponent, &bIsDirectory))
266 {
267 /* ".": skip */
268 if(IS_COMPONENT_DOT_A(strThisComponent))
269 continue;
270 /* "..": go back to the last component */
271 else if(IS_COMPONENT_DOTDOT_A(strThisComponent))
272 {
273 if(pcCurPos == pcStartPos)
274 continue;
275
276 /* skip the last (undefined) character */
277 pcCurPos --;
278 /* down to the previous path delimiter */
279 do{ pcCurPos --; }while(!IS_CHAR_DELIMITER_A(*pcCurPos));
280 /* include the delimiter */
281 pcCurPos ++;
282 }
283 else
284 {
285 /* copy this component into the return string */
286 strncpy
287 (
288 pcCurPos,
289 strThisComponent.Buffer,
290 strThisComponent.Length
291 );
292
293 /* move the current position to the end of the string */
294 pcCurPos = (PCHAR)((PBYTE)pcCurPos + strThisComponent.Length);
295
296 /* component had a trailing delimiter */
297 if(bIsDirectory)
298 {
299 /* append a delimiter */
300 *pcCurPos = PathDelimiter;
301 /* on to next character */
302 pcCurPos ++;
303 }
304 }
305 }
306
307 /* set the return string's length as the byte offset between the initial buffer
308 position and the current position */
309 ResolvedPathName->Length = ((ULONG)pcCurPos - (ULONG)ResolvedPathName->Buffer);
310
311 return (TRUE);
312
313 }
314
315 BOOLEAN
316 __PdxPosixPathNameToNtPathName
317 (
318 IN PWCHAR PosixPath,
319 OUT PUNICODE_STRING NativePath,
320 IN PUNICODE_STRING CurDir OPTIONAL,
321 IN PUNICODE_STRING RootDir OPTIONAL
322 )
323 {
324 UNICODE_STRING wstrPosixPath;
325 UNICODE_STRING wstrTempString;
326
327 /* parameter validation */
328 if
329 (
330 PosixPath == 0 ||
331 NativePath == 0 ||
332 NativePath->Buffer == 0 ||
333 NativePath->MaximumLength == 0 ||
334 (RootDir != 0 && RootDir->Buffer == 0)
335 )
336 {
337 errno = EINVAL;
338 return (FALSE);
339 }
340
341 RtlInitUnicodeString(&wstrPosixPath, PosixPath);
342
343 /* path is null */
344 if(0 == wstrPosixPath.Length)
345 {
346 errno = EINVAL;
347 return (FALSE);
348 }
349
350 /* first, copy the root path into the return buffer */
351 /* if no root dir passed by the caller... */
352 if(RootDir == 0)
353 /* return buffer too small */
354 if(NativePath->MaximumLength < sizeof(WCHAR))
355 {
356 errno = ENOBUFS;
357 return (FALSE);
358 }
359 /* set the first character to a backslash, and set length accordingly */
360 else
361 {
362 NativePath->Buffer[0] = L'\\';
363 NativePath->Length = sizeof(WCHAR);
364 }
365 /* ... else copy the root dir into the return buffer */
366 else
367 /* return buffer too small */
368 if(NativePath->MaximumLength < RootDir->Length)
369 {
370 errno = ENOBUFS;
371 return (FALSE);
372 }
373 /* copy the root directory into the return buffer, and set length */
374 else
375 {
376 memcpy(NativePath->Buffer, RootDir->Buffer, RootDir->Length);
377 NativePath->Length = RootDir->Length;
378 }
379
380 /* path is "/" - our work is done */
381 if(sizeof(WCHAR) == wstrPosixPath.Length && IS_CHAR_DELIMITER_U(wstrPosixPath.Buffer[0]))
382 return (TRUE);
383
384 /* temp string pointing to the tail of the return buffer */
385 wstrTempString.Length = 0;
386 wstrTempString.MaximumLength = NativePath->MaximumLength - NativePath->Length;
387 wstrTempString.Buffer = (PWCHAR)(((PBYTE)(NativePath->Buffer)) + NativePath->Length);
388
389 /* path begins with '/': absolute path. Append the resolved path to the return buffer */
390 if(IS_CHAR_DELIMITER_U(wstrPosixPath.Buffer[0]))
391 {
392 /* copy the resolved path in the return buffer */
393 __PdxPosixPathResolve_U(wstrPosixPath, &wstrTempString, L'\\');
394
395 return (TRUE);
396 }
397 else
398 {
399 UNICODE_STRING wstrAbsolutePath;
400
401 if(CurDir == 0)
402 CurDir = __PdxGetCurDir();
403
404 /* initialize the buffer for the absolute path */
405 wstrAbsolutePath.Length = 0;
406 wstrAbsolutePath.MaximumLength = 0xFFFF;
407 wstrAbsolutePath.Buffer = __malloc(0xFFFF);
408
409 /* if the current directory is not null... */
410 if(!(CurDir->Buffer == 0 || CurDir->Length == 0))
411 {
412 /* copy it into the absolute path buffer */
413 memcpy(wstrAbsolutePath.Buffer, CurDir->Buffer, CurDir->Length);
414 wstrAbsolutePath.Length += CurDir->Length;
415 }
416
417 /* not enough space to append an extra slash */
418 if((wstrAbsolutePath.MaximumLength - wstrAbsolutePath.Length) < (USHORT)sizeof(WCHAR))
419 {
420 __free(wstrAbsolutePath.Buffer);
421 NativePath->Length = 0;
422 errno = ENOBUFS;
423 return (FALSE);
424 }
425
426 /* append an extra slash */
427 wstrAbsolutePath.Buffer[wstrAbsolutePath.Length / sizeof(WCHAR)] = L'/';
428 wstrAbsolutePath.Length += sizeof(WCHAR);
429
430 /* not enough space to copy the relative path */
431 if((wstrAbsolutePath.MaximumLength - wstrAbsolutePath.Length) < wstrPosixPath.Length)
432 {
433 __free(wstrAbsolutePath.Buffer);
434 NativePath->Length = 0;
435 errno = ENOBUFS;
436 return (FALSE);
437 }
438
439 /* append the relative path to the absolute path */
440 memcpy(
441 (PWCHAR)(((PBYTE)wstrAbsolutePath.Buffer) + wstrAbsolutePath.Length),
442 wstrPosixPath.Buffer,
443 wstrPosixPath.Length
444 );
445 wstrAbsolutePath.Length += wstrPosixPath.Length;
446
447 /* resolve the path */
448 __PdxPosixPathResolve_U(wstrAbsolutePath, &wstrTempString, L'\\');
449
450 __free(wstrAbsolutePath.Buffer);
451
452 return (TRUE);
453 }
454
455 return (FALSE);
456
457 }
458
459 /* EOF */
460