1 /* $NetBSD: paths.c,v 1.8 2008/08/12 19:44:39 pooka Exp $ */
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
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
28 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: paths.c,v 1.8 2008/08/12 19:44:39 pooka Exp $");
40 #include "puffs_priv.h"
43 * Generic routines for pathbuilding code
47 puffs_path_pcnbuild(struct puffs_usermount
*pu
, struct puffs_cn
*pcn
,
48 puffs_cookie_t parent
)
50 struct puffs_node
*pn_parent
= PU_CMAP(pu
, parent
);
51 struct puffs_cn pcn_orig
;
52 struct puffs_pathobj po
;
55 assert(pn_parent
->pn_po
.po_path
!= NULL
);
56 assert(pu
->pu_flags
& PUFFS_FLAG_BUILDPATH
);
58 if (pu
->pu_pathtransform
) {
59 rv
= pu
->pu_pathtransform(pu
, &pn_parent
->pn_po
, pcn
, &po
);
63 po
.po_path
= pcn
->pcn_name
;
64 po
.po_len
= pcn
->pcn_namelen
;
68 /* XXX: gcc complains if I do assignment */
69 memcpy(&pcn_orig
, pcn
, sizeof(pcn_orig
));
70 rv
= pu
->pu_namemod(pu
, &pn_parent
->pn_po
, pcn
);
75 rv
= pu
->pu_pathbuild(pu
, &pn_parent
->pn_po
, &po
, 0,
77 puffs_path_buildhash(pu
, &pcn
->pcn_po_full
);
79 if (pu
->pu_pathtransform
)
80 pu
->pu_pathfree(pu
, &po
);
82 if (pu
->pu_namemod
&& rv
)
89 * substitute all (child) patch prefixes. called from nodewalk, which
90 * in turn is called from rename
93 puffs_path_prefixadj(struct puffs_usermount
*pu
, struct puffs_node
*pn
,
96 struct puffs_pathinfo
*pi
= arg
;
97 struct puffs_pathobj localpo
;
98 struct puffs_pathobj oldpo
;
101 /* can't be a path prefix */
102 if (pn
->pn_po
.po_len
< pi
->pi_old
->po_len
)
105 if (pu
->pu_pathcmp(pu
, &pn
->pn_po
, pi
->pi_old
, pi
->pi_old
->po_len
, 1))
108 /* otherwise we'd have two nodes with an equal path */
109 assert(pn
->pn_po
.po_len
> pi
->pi_old
->po_len
);
111 /* found a matching prefix */
112 rv
= pu
->pu_pathbuild(pu
, pi
->pi_new
, &pn
->pn_po
,
113 pi
->pi_old
->po_len
, &localpo
);
115 * XXX: technically we shouldn't fail, but this is the only
116 * sensible thing to do here. If the buildpath routine fails,
117 * we will have paths in an inconsistent state. Should fix this,
118 * either by having two separate passes or by doing other tricks
119 * to make an invalid path with BUILDPATHS acceptable.
124 /* adjust hash sum */
125 puffs_path_buildhash(pu
, &localpo
);
127 /* out with the old and in with the new */
130 pu
->pu_pathfree(pu
, &oldpo
);
132 /* continue the walk */
137 * called from nodewalk, checks for exact match
140 puffs_path_walkcmp(struct puffs_usermount
*pu
, struct puffs_node
*pn
, void *arg
)
142 struct puffs_pathobj
*po
= arg
;
143 struct puffs_pathobj po2
;
145 if (po
->po_len
!= PNPLEN(pn
))
149 * If hashing and the hash doesn't match, we know this is
150 * definitely not a match. Otherwise check for collisions.
152 if (pu
->pu_flags
& PUFFS_FLAG_HASHPATH
)
153 if (pn
->pn_po
.po_hash
!= po
->po_hash
)
156 po2
.po_path
= PNPATH(pn
);
157 po2
.po_len
= PNPLEN(pn
);
159 if (pu
->pu_pathcmp(pu
, po
, &po2
, PNPLEN(pn
), 0) == 0)
165 * Hash sum building routine. Use string hash if the buildpath routine
166 * is the standard one, otherwise use binary hashes. A bit whimsical
167 * way to choose the routine, but the binary works for strings also,
171 puffs_path_buildhash(struct puffs_usermount
*pu
, struct puffs_pathobj
*po
)
174 if ((pu
->pu_flags
& PUFFS_FLAG_HASHPATH
) == 0)
177 if (pu
->pu_pathbuild
== puffs_stdpath_buildpath
)
178 po
->po_hash
= hash32_strn(po
->po_path
, po
->po_len
,
181 po
->po_hash
= hash32_buf(po
->po_path
, po
->po_len
,
186 * Routines provided to file systems which consider a path a tuple of
187 * strings and / the component separator.
192 puffs_stdpath_cmppath(struct puffs_usermount
*pu
, struct puffs_pathobj
*c1
,
193 struct puffs_pathobj
*c2
, size_t clen
, int checkprefix
)
198 rv
= strncmp(c1
->po_path
, c2
->po_path
, clen
);
202 if (checkprefix
== 0)
205 /* sanity for next step */
206 if (!(c1
->po_len
> c2
->po_len
))
209 /* check if it's really a complete path prefix */
211 if ((*(p
+ clen
)) != '/')
219 puffs_stdpath_buildpath(struct puffs_usermount
*pu
,
220 const struct puffs_pathobj
*po_pre
, const struct puffs_pathobj
*po_comp
,
221 size_t offset
, struct puffs_pathobj
*newpath
)
224 size_t plen
, complen
;
228 complen
= po_comp
->po_len
- offset
;
230 /* seek to correct place & remove all leading '/' from component */
231 pcomp
= po_comp
->po_path
;
233 while (*pcomp
== '/') {
238 /* todotdot or nottodotdot */
239 if (complen
== 2 && strcmp(pcomp
, "..") == 0)
245 * Strip trailing components from the preceending component.
246 * This is an issue only for the root node, which we might want
247 * to be at path "/" for some file systems.
249 prelen
= po_pre
->po_len
;
250 while (prelen
> 0 && *((char *)po_pre
->po_path
+ (prelen
-1)) == '/') {
251 assert(isdotdot
== 0);
256 char *slash
; /* sweet char of mine */
258 slash
= strrchr(po_pre
->po_path
, '/');
259 assert(slash
!= NULL
);
261 plen
= slash
- (char *)po_pre
->po_path
;
264 * As the converse to not stripping the initial "/" above,
265 * don't nuke it here either.
270 path
= malloc(plen
+ 1);
274 strlcpy(path
, po_pre
->po_path
, plen
+1);
277 plen
= prelen
+ 1 + complen
;
278 path
= malloc(plen
+ 1);
282 strlcpy(path
, po_pre
->po_path
, prelen
+1);
284 strncat(path
, pcomp
, complen
);
287 newpath
->po_path
= path
;
288 newpath
->po_len
= plen
;
295 puffs_stdpath_freepath(struct puffs_usermount
*pu
, struct puffs_pathobj
*po
)