2 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
14 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
28 #include <sys/types.h>
39 #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
);
59 if (pu
->pu_pathtransform
) {
60 rv
= pu
->pu_pathtransform(pu
, &pn_parent
->pn_po
, pcn
, &po
);
64 po
.po_path
= pcn
->pcn_name
;
65 po
.po_len
= pcn
->pcn_namelen
;
69 rv
= pu
->pu_namemod(pu
, &pn_parent
->pn_po
, pcn
);
74 rv
= pu
->pu_pathbuild(pu
, &pn_parent
->pn_po
, &po
, 0,
76 puffs_path_buildhash(pu
, &pcn
->pcn_po_full
);
78 if (pu
->pu_pathtransform
)
79 pu
->pu_pathfree(pu
, &po
);
81 if (pu
->pu_namemod
&& rv
)
88 * substitute all (child) patch prefixes. called from nodewalk, which
89 * in turn is called from rename
92 puffs_path_prefixadj(struct puffs_usermount
*pu
, struct puffs_node
*pn
,
95 struct puffs_pathinfo
*pi
= arg
;
96 struct puffs_pathobj localpo
;
97 struct puffs_pathobj oldpo
;
100 /* can't be a path prefix */
101 if (pn
->pn_po
.po_len
< pi
->pi_old
->po_len
)
104 if (pu
->pu_pathcmp(pu
, &pn
->pn_po
, pi
->pi_old
, pi
->pi_old
->po_len
, 1))
107 /* otherwise we'd have two nodes with an equal path */
108 assert(pn
->pn_po
.po_len
> pi
->pi_old
->po_len
);
110 /* found a matching prefix */
111 rv
= pu
->pu_pathbuild(pu
, pi
->pi_new
, &pn
->pn_po
,
112 pi
->pi_old
->po_len
, &localpo
);
114 * XXX: technically we shouldn't fail, but this is the only
115 * sensible thing to do here. If the buildpath routine fails,
116 * we will have paths in an inconsistent state. Should fix this,
117 * either by having two separate passes or by doing other tricks
118 * to make an invalid path with BUILDPATHS acceptable.
123 /* adjust hash sum */
124 puffs_path_buildhash(pu
, &localpo
);
126 /* out with the old and in with the new */
129 pu
->pu_pathfree(pu
, &oldpo
);
131 /* continue the walk */
136 * called from nodewalk, checks for exact match
139 puffs_path_walkcmp(struct puffs_usermount
*pu
, struct puffs_node
*pn
, void *arg
)
141 struct puffs_pathobj
*po
= arg
;
142 struct puffs_pathobj po2
;
144 if (po
->po_len
!= PNPLEN(pn
))
148 * If hashing and the hash doesn't match, we know this is
149 * definitely not a match. Otherwise check for collisions.
151 if (pu
->pu_flags
& PUFFS_FLAG_HASHPATH
)
152 if (pn
->pn_po
.po_hash
!= po
->po_hash
)
155 po2
.po_path
= PNPATH(pn
);
156 po2
.po_len
= PNPLEN(pn
);
158 if (pu
->pu_pathcmp(pu
, po
, &po2
, PNPLEN(pn
), 0) == 0)
164 * Hash sum building routine. Use string hash if the buildpath routine
165 * is the standard one, otherwise use binary hashes. A bit whimsical
166 * way to choose the routine, but the binary works for strings also,
170 puffs_path_buildhash(struct puffs_usermount
*pu
, struct puffs_pathobj
*po
)
173 if ((pu
->pu_flags
& PUFFS_FLAG_HASHPATH
) == 0)
176 if (pu
->pu_pathbuild
== puffs_stdpath_buildpath
)
177 po
->po_hash
= hash32_strn(po
->po_path
, po
->po_len
,
180 po
->po_hash
= hash32_buf(po
->po_path
, po
->po_len
,
185 * Routines provided to file systems which consider a path a tuple of
186 * strings and / the component separator.
191 puffs_stdpath_cmppath(struct puffs_usermount
*pu
, struct puffs_pathobj
*c1
,
192 struct puffs_pathobj
*c2
, size_t clen
, int checkprefix
)
197 rv
= strncmp(c1
->po_path
, c2
->po_path
, clen
);
201 if (checkprefix
== 0)
204 /* sanity for next step */
205 if (!(c1
->po_len
> c2
->po_len
))
208 /* check if it's really a complete path prefix */
210 if ((*(p
+ clen
)) != '/')
218 puffs_stdpath_buildpath(struct puffs_usermount
*pu
,
219 const struct puffs_pathobj
*po_pre
, const struct puffs_pathobj
*po_comp
,
220 size_t offset
, struct puffs_pathobj
*newpath
)
223 size_t plen
, complen
;
227 complen
= po_comp
->po_len
- offset
;
229 /* seek to correct place & remove all leading '/' from component */
230 pcomp
= po_comp
->po_path
;
232 while (*pcomp
== '/') {
237 /* todotdot or nottodotdot */
238 if (complen
== 2 && strcmp(pcomp
, "..") == 0)
244 * Strip trailing components from the preceending component.
245 * This is an issue only for the root node, which we might want
246 * to be at path "/" for some file systems.
248 prelen
= po_pre
->po_len
;
249 while (prelen
> 0 && *((char *)po_pre
->po_path
+ (prelen
-1)) == '/') {
250 assert(isdotdot
== 0);
255 char *slash
; /* sweet char of mine */
257 slash
= strrchr(po_pre
->po_path
, '/');
258 assert(slash
!= NULL
);
260 plen
= slash
- (char *)po_pre
->po_path
;
263 * As the converse to not stripping the initial "/" above,
264 * don't nuke it here either.
269 path
= malloc(plen
+ 1);
273 strlcpy(path
, po_pre
->po_path
, plen
+1);
276 plen
= prelen
+ 1 + complen
;
277 path
= malloc(plen
+ 1);
281 strlcpy(path
, po_pre
->po_path
, prelen
+1);
283 strncat(path
, pcomp
, complen
);
286 newpath
->po_path
= path
;
287 newpath
->po_len
= plen
;
294 puffs_stdpath_freepath(struct puffs_usermount
*pu
, struct puffs_pathobj
*po
)