xref: /illumos-gate/usr/src/lib/libshare/common/issubdir.c (revision 9d4bc241fda36c3d39d15e06ffb2eb780bd939dd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 /*
41  * Subdirectory detection: needed by exportfs and rpc.mountd.
42  * The above programs call issubdir() frequently, so we make
43  * it fast by caching the results of stat().
44  */
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/stat.h>
48 #include <string.h>
49 
50 #define	MAXSTATS MAXPATHLEN/2	/* maximum number of stat()'s to save */
51 
52 #define	inoeq(ino1, ino2)	((ino1) == (ino2))
53 #define	deveq(dev1, dev2)	((dev1) == (dev2))
54 
55 /*
56  * dir1 is a subdirectory of dir2 within the same filesystem if
57  *     (a) dir1 is identical to dir2
58  *     (b) dir1's parent is dir2
59  */
60 int
issubdir(char * dir1,char * dir2)61 issubdir(char *dir1, char *dir2)
62 {
63 	struct stat st;
64 	struct stat parent_st;
65 	char *p;
66 	int index;
67 
68 	static dev_t child_dev;
69 	static dev_t child_rdev;
70 	static ino_t child_ino[MAXSTATS];
71 	static int valid;
72 	static char childdir[MAXPATHLEN];
73 	static char child_fstype[_ST_FSTYPSZ];
74 
75 	/*
76 	 * Get parent directory info
77 	 */
78 	if (stat(dir2, &parent_st) < 0) {
79 		return (0);
80 	}
81 
82 	if (strcmp(childdir, dir1) != 0) {
83 		/*
84 		 * Not in cache: get child directory info
85 		 */
86 		p = strcpy(childdir, dir1) + strlen(dir1);
87 		index = 0;
88 		valid = 0;
89 		for (;;) {
90 			if (stat(childdir, &st) < 0) {
91 				childdir[0] = 0;	/* invalidate cache */
92 				return (0);
93 			}
94 			if (index == 0) {
95 				child_dev = st.st_dev;
96 				child_rdev = st.st_rdev;
97 				(void) strncpy(child_fstype, st.st_fstype,
98 				    sizeof (child_fstype));
99 			}
100 			if (index > 0 &&
101 			    (child_dev != st.st_dev ||
102 			    inoeq(child_ino[index - 1], st.st_ino))) {
103 				/*
104 				 * Hit root: done
105 				 */
106 				break;
107 			}
108 			child_ino[index++] = st.st_ino;
109 			if (S_ISDIR(st.st_mode)) {
110 				p = strcpy(p, "/..") + 3;
111 			} else {
112 				p = strrchr(childdir, '/');
113 				if (p == NULL) {
114 					p = strcpy(childdir, ".") + 1;
115 				} else {
116 					while (((p - 1) > childdir) &&
117 					    *(p - 1) == '/') {
118 						p--;
119 					}
120 					*p = '\0';
121 				}
122 			}
123 		}
124 		valid = index;
125 		(void) strlcpy(childdir, dir1, MAXPATHLEN);
126 	}
127 
128 	/*
129 	 * Perform the test
130 	 */
131 	if (!deveq(parent_st.st_dev, child_dev)) {
132 		return (0);
133 	}
134 
135 	/*
136 	 * Check rdev also in case of lofs
137 	 */
138 	if (((strcmp(parent_st.st_fstype, "lofs") == 0)) &&
139 	    (strcmp(child_fstype, "lofs") == 0)) {
140 		if (!deveq(parent_st.st_rdev, child_rdev)) {
141 			return (0);
142 		}
143 	}
144 
145 	for (index = 0; index < valid; index++) {
146 		if (inoeq(child_ino[index], parent_st.st_ino)) {
147 			return (1);
148 		}
149 	}
150 	return (0);
151 }
152