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
33 #include "puffs_priv.h"
37 * Generic routines for pathbuilding code
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
;
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
);
57 po
.po_path
= pcn
->pcn_name
;
58 po
.po_len
= pcn
->pcn_namelen
;
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
);
69 rv
= pu
->pu_pathbuild(pu
, &pn_parent
->pn_po
, &po
, 0,
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
)
83 * substitute all (child) patch prefixes. called from nodewalk, which
84 * in turn is called from rename
87 puffs_path_prefixadj(struct puffs_usermount
*pu
, struct puffs_node
*pn
,
90 struct puffs_pathinfo
*pi
= arg
;
91 struct puffs_pathobj localpo
;
92 struct puffs_pathobj oldpo
;
95 /* can't be a path prefix */
96 if (pn
->pn_po
.po_len
< pi
->pi_old
->po_len
)
99 if (pu
->pu_pathcmp(pu
, &pn
->pn_po
, pi
->pi_old
, pi
->pi_old
->po_len
, 1))
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.
118 /* adjust hash sum */
119 puffs_path_buildhash(pu
, &localpo
);
121 /* out with the old and in with the new */
124 pu
->pu_pathfree(pu
, &oldpo
);
126 /* continue the walk */
131 * called from nodewalk, checks for exact match
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
))
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
)
150 po2
.po_path
= PNPATH(pn
);
151 po2
.po_len
= PNPLEN(pn
);
153 if (pu
->pu_pathcmp(pu
, po
, &po2
, PNPLEN(pn
), 0) == 0)
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,
165 puffs_path_buildhash(struct puffs_usermount
*pu
, struct puffs_pathobj
*po
)
168 if ((pu
->pu_flags
& PUFFS_FLAG_HASHPATH
) == 0)
171 if (pu
->pu_pathbuild
== puffs_stdpath_buildpath
)
172 po
->po_hash
= hash32_strn(po
->po_path
, po
->po_len
,
175 po
->po_hash
= hash32_buf(po
->po_path
, po
->po_len
,
180 * Routines provided to file systems which consider a path a tuple of
181 * strings and / the component separator.
186 puffs_stdpath_cmppath(struct puffs_usermount
*pu
, struct puffs_pathobj
*c1
,
187 struct puffs_pathobj
*c2
, size_t clen
, int checkprefix
)
192 rv
= strncmp(c1
->po_path
, c2
->po_path
, clen
);
196 if (checkprefix
== 0)
199 /* sanity for next step */
200 if (!(c1
->po_len
> c2
->po_len
))
203 /* check if it's really a complete path prefix */
205 if ((*(p
+ clen
)) != '/')
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
)
218 size_t plen
, complen
;
222 complen
= po_comp
->po_len
- offset
;
224 /* seek to correct place & remove all leading '/' from component */
225 pcomp
= po_comp
->po_path
;
227 while (*pcomp
== '/') {
232 /* todotdot or nottodotdot */
233 if (complen
== 2 && strcmp(pcomp
, "..") == 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);
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.
264 path
= malloc(plen
+ 1);
268 strlcpy(path
, po_pre
->po_path
, plen
+1);
271 plen
= prelen
+ 1 + complen
;
272 path
= malloc(plen
+ 1);
276 strlcpy(path
, po_pre
->po_path
, prelen
+1);
278 strncat(path
, pcomp
, complen
);
281 newpath
->po_path
= path
;
282 newpath
->po_len
= plen
;
289 puffs_stdpath_freepath(struct puffs_usermount
*pu
, struct puffs_pathobj
*po
)