x86_64: Fix machdep.smp_active sysctl type.
[dragonfly.git] / lib / libpuffs / paths.c
blob18fc67ac3d0239415c570d823c59018dac304b09
1 /* $NetBSD: paths.c,v 1.8 2008/08/12 19:44:39 pooka Exp $ */
3 /*
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
28 #include <assert.h>
29 #include <errno.h>
30 #include <stdlib.h>
32 #include "puffs.h"
33 #include "puffs_priv.h"
34 #include "hash.h"
37 * Generic routines for pathbuilding code
40 int
41 puffs_path_pcnbuild(struct puffs_usermount *pu, struct puffs_cn *pcn,
42 puffs_cookie_t parent)
44 struct puffs_node *pn_parent = PU_CMAP(pu, parent);
45 struct puffs_cn pcn_orig;
46 struct puffs_pathobj po;
47 int rv;
49 assert(pn_parent->pn_po.po_path != NULL);
50 assert(pu->pu_flags & PUFFS_FLAG_BUILDPATH);
52 if (pu->pu_pathtransform) {
53 rv = pu->pu_pathtransform(pu, &pn_parent->pn_po, pcn, &po);
54 if (rv)
55 return rv;
56 } else {
57 po.po_path = pcn->pcn_name;
58 po.po_len = pcn->pcn_namelen;
61 if (pu->pu_namemod) {
62 /* XXX: gcc complains if I do assignment */
63 memcpy(&pcn_orig, pcn, sizeof(pcn_orig));
64 rv = pu->pu_namemod(pu, &pn_parent->pn_po, pcn);
65 if (rv)
66 return rv;
69 rv = pu->pu_pathbuild(pu, &pn_parent->pn_po, &po, 0,
70 &pcn->pcn_po_full);
71 puffs_path_buildhash(pu, &pcn->pcn_po_full);
73 if (pu->pu_pathtransform)
74 pu->pu_pathfree(pu, &po);
76 if (pu->pu_namemod && rv)
77 *pcn = pcn_orig;
79 return rv;
83 * substitute all (child) patch prefixes. called from nodewalk, which
84 * in turn is called from rename
86 void *
87 puffs_path_prefixadj(struct puffs_usermount *pu, struct puffs_node *pn,
88 void *arg)
90 struct puffs_pathinfo *pi = arg;
91 struct puffs_pathobj localpo;
92 struct puffs_pathobj oldpo;
93 int rv;
95 /* can't be a path prefix */
96 if (pn->pn_po.po_len < pi->pi_old->po_len)
97 return NULL;
99 if (pu->pu_pathcmp(pu, &pn->pn_po, pi->pi_old, pi->pi_old->po_len, 1))
100 return NULL;
102 /* otherwise we'd have two nodes with an equal path */
103 assert(pn->pn_po.po_len > pi->pi_old->po_len);
105 /* found a matching prefix */
106 rv = pu->pu_pathbuild(pu, pi->pi_new, &pn->pn_po,
107 pi->pi_old->po_len, &localpo);
109 * XXX: technically we shouldn't fail, but this is the only
110 * sensible thing to do here. If the buildpath routine fails,
111 * we will have paths in an inconsistent state. Should fix this,
112 * either by having two separate passes or by doing other tricks
113 * to make an invalid path with BUILDPATHS acceptable.
115 if (rv != 0)
116 abort();
118 /* adjust hash sum */
119 puffs_path_buildhash(pu, &localpo);
121 /* out with the old and in with the new */
122 oldpo = pn->pn_po;
123 pn->pn_po = localpo;
124 pu->pu_pathfree(pu, &oldpo);
126 /* continue the walk */
127 return NULL;
131 * called from nodewalk, checks for exact match
133 void *
134 puffs_path_walkcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
136 struct puffs_pathobj *po = arg;
137 struct puffs_pathobj po2;
139 if (po->po_len != PNPLEN(pn))
140 return NULL;
143 * If hashing and the hash doesn't match, we know this is
144 * definitely not a match. Otherwise check for collisions.
146 if (pu->pu_flags & PUFFS_FLAG_HASHPATH)
147 if (pn->pn_po.po_hash != po->po_hash)
148 return NULL;
150 po2.po_path = PNPATH(pn);
151 po2.po_len = PNPLEN(pn);
153 if (pu->pu_pathcmp(pu, po, &po2, PNPLEN(pn), 0) == 0)
154 return pn;
155 return NULL;
159 * Hash sum building routine. Use string hash if the buildpath routine
160 * is the standard one, otherwise use binary hashes. A bit whimsical
161 * way to choose the routine, but the binary works for strings also,
162 * so don't sweat it.
164 void
165 puffs_path_buildhash(struct puffs_usermount *pu, struct puffs_pathobj *po)
168 if ((pu->pu_flags & PUFFS_FLAG_HASHPATH) == 0)
169 return;
171 if (pu->pu_pathbuild == puffs_stdpath_buildpath)
172 po->po_hash = hash32_strn(po->po_path, po->po_len,
173 HASH32_STR_INIT);
174 else
175 po->po_hash = hash32_buf(po->po_path, po->po_len,
176 HASH32_BUF_INIT);
180 * Routines provided to file systems which consider a path a tuple of
181 * strings and / the component separator.
184 /*ARGSUSED*/
186 puffs_stdpath_cmppath(struct puffs_usermount *pu, struct puffs_pathobj *c1,
187 struct puffs_pathobj *c2, size_t clen, int checkprefix)
189 char *p;
190 int rv;
192 rv = strncmp(c1->po_path, c2->po_path, clen);
193 if (rv)
194 return 1;
196 if (checkprefix == 0)
197 return 0;
199 /* sanity for next step */
200 if (!(c1->po_len > c2->po_len))
201 return 1;
203 /* check if it's really a complete path prefix */
204 p = c1->po_path;
205 if ((*(p + clen)) != '/')
206 return 1;
208 return 0;
211 /*ARGSUSED*/
213 puffs_stdpath_buildpath(struct puffs_usermount *pu,
214 const struct puffs_pathobj *po_pre, const struct puffs_pathobj *po_comp,
215 size_t offset, struct puffs_pathobj *newpath)
217 char *path, *pcomp;
218 size_t plen, complen;
219 size_t prelen;
220 int isdotdot;
222 complen = po_comp->po_len - offset;
224 /* seek to correct place & remove all leading '/' from component */
225 pcomp = po_comp->po_path;
226 pcomp += offset;
227 while (*pcomp == '/') {
228 pcomp++;
229 complen--;
232 /* todotdot or nottodotdot */
233 if (complen == 2 && strcmp(pcomp, "..") == 0)
234 isdotdot = 1;
235 else
236 isdotdot = 0;
239 * Strip trailing components from the preceending component.
240 * This is an issue only for the root node, which we might want
241 * to be at path "/" for some file systems.
243 prelen = po_pre->po_len;
244 while (prelen > 0 && *((char *)po_pre->po_path + (prelen-1)) == '/') {
245 assert(isdotdot == 0);
246 prelen--;
249 if (isdotdot) {
250 char *slash; /* sweet char of mine */
252 slash = strrchr(po_pre->po_path, '/');
253 assert(slash != NULL);
255 plen = slash - (char *)po_pre->po_path;
258 * As the converse to not stripping the initial "/" above,
259 * don't nuke it here either.
261 if (plen == 0)
262 plen++;
264 path = malloc(plen + 1);
265 if (path == NULL)
266 return errno;
268 strlcpy(path, po_pre->po_path, plen+1);
269 } else {
270 /* + '/' + '\0' */
271 plen = prelen + 1 + complen;
272 path = malloc(plen + 1);
273 if (path == NULL)
274 return errno;
276 strlcpy(path, po_pre->po_path, prelen+1);
277 strcat(path, "/");
278 strncat(path, pcomp, complen);
281 newpath->po_path = path;
282 newpath->po_len = plen;
284 return 0;
287 /*ARGSUSED*/
288 void
289 puffs_stdpath_freepath(struct puffs_usermount *pu, struct puffs_pathobj *po)
292 free(po->po_path);