1 /* @(#)lxchdir.c	1.1 11/10/21 Copyright 2004-2011 J. Schilling */
2 /*
3  *	Long path name aware chdir().
4  *
5  *	The code has been adopted from libfind.
6  *
7  *	Copyright (c) 2004-2011 J. Schilling
8  */
9 /*
10  * The contents of this file are subject to the terms of the
11  * Common Development and Distribution License, Version 1.0 only
12  * (the "License").  You may not use this file except in compliance
13  * with the License.
14  *
15  * See the file CDDL.Schily.txt in this distribution for details.
16  * A copy of the CDDL is also available via the Internet at
17  * http://www.opensource.org/licenses/cddl1.txt
18  *
19  * When distributing Covered Code, include this CDDL HEADER in each
20  * file and include the License file CDDL.Schily.txt from this distribution.
21  */
22 
23 #include <schily/unistd.h>
24 #include <schily/types.h>
25 #include <schily/fcntl.h>
26 #include <schily/maxpath.h>
27 #include <schily/string.h>
28 #include <schily/errno.h>
29 #include <schily/standard.h>
30 #include <schily/schily.h>
31 #include "at-defs.h"
32 
33 #ifndef	ENAMETOOLONG
34 #define	ENAMETOOLONG	EINVAL
35 #endif
36 
37 EXPORT	int	lxchdir	__PR((char *p));
38 LOCAL	int	xchdir	__PR((char *p));
39 
40 EXPORT int
lxchdir(p)41 lxchdir(p)
42 	char	*p;
43 {
44 	if (chdir(p) < 0) {
45 		if (geterrno() != ENAMETOOLONG)
46 			return (-1);
47 
48 		return (xchdir(p));
49 	}
50 	return (0);
51 }
52 
53 LOCAL int
xchdir(p)54 xchdir(p)
55 	char	*p;
56 {
57 	char	*p2;
58 	BOOL	first = TRUE;
59 
60 	while (*p) {
61 		if ((p2 = strchr(p, '/')) != NULL)
62 			*p2 = '\0';
63 
64 		if (first && p2 && p[0] == '\0') {
65 			if (chdir("/") < 0)
66 				return (-1);
67 		} else {
68 			/*
69 			 * If this is not the first chdir() and we are doing a
70 			 * multi hop chdir(), we may be on an undefined
71 			 * intermediate directory. Mark this case by returning
72 			 * -2 instead of -1.
73 			 */
74 			if (chdir(p) < 0)
75 				return (first?-1:-2);
76 		}
77 		if (p2 == NULL)
78 			break;
79 		*p2 = '/';
80 		p = &p2[1];
81 		first = FALSE;
82 	}
83 	return (0);
84 }
85