1 /* $NetBSD: icfs.c,v 1.10 2008/08/12 15:14:00 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
29 * icfs: layer everything in lowercase
30 * (unfinished, as is probably fairly easy to tell)
32 * Now, this "layered" file system demostrates a nice gotcha with
33 * mangling readdir entries. In case we can't unmangle the name
34 * (cf. rot13fs), we need to map the mangled name back to the real
35 * name in lookup and store the actual lower layer name instead of
38 * This is mounted without namecache. Otherwise we might have
39 * two different nodes for e.g. FoO and foo. It might be possible
40 * support name cache by having all namespace-altering operations
41 * flush the directory namecache ...
44 #include <sys/types.h>
58 static void usage(void);
64 errx(1, "usage: %s [-sp] [-o mntopts] icfs mountpath",
69 dotolower(char *buf
, size_t buflen
)
73 *buf
= tolower((unsigned char)*buf
);
79 icpathcmp(struct puffs_usermount
*pu
, struct puffs_pathobj
*c1
,
80 struct puffs_pathobj
*c2
, size_t clen
, int checkprefix
)
82 struct puffs_pathobj
*po_root
;
86 po_root
= puffs_getrootpathobj(pu
);
87 rplen
= po_root
->po_len
;
89 assert(clen
>= rplen
);
94 if (strncasecmp(cp1
+ rplen
, cp2
+ rplen
, clen
- rplen
) != 0)
100 if (c1
->po_len
< c2
->po_len
)
103 if (*(cp1
+ clen
) != '/')
110 icpathxform(struct puffs_usermount
*pu
, const struct puffs_pathobj
*po_base
,
111 const struct puffs_cn
*pcn
, struct puffs_pathobj
*po_new
)
113 struct dirent entry
, *result
;
118 dp
= opendir(po_base
->po_path
);
123 srclen
= pcn
->pcn_namelen
;
125 if (readdir_r(dp
, &entry
, &result
) != 0)
129 if (strcasecmp(result
->d_name
, pcn
->pcn_name
) == 0) {
130 src
= result
->d_name
;
131 srclen
= strlen(result
->d_name
);
136 po_new
->po_path
= strdup(src
);
137 po_new
->po_len
= srclen
;
144 main(int argc
, char *argv
[])
146 struct puffs_usermount
*pu
;
147 struct puffs_ops
*pops
;
148 struct puffs_pathobj
*po_root
;
149 struct puffs_node
*pn_root
;
152 int mntflags
, pflags
;
156 setprogname(argv
[0]);
161 pflags
= mntflags
= dpres
= 0;
163 while ((ch
= getopt(argc
, argv
, "o:sp")) != -1) {
166 mp
= getmntopts(optarg
, puffsmopts
, &mntflags
, &pflags
);
168 err(1, "getmntopts");
179 pflags
|= PUFFS_FLAG_BUILDPATH
;
180 pflags
|= PUFFS_KFLAG_NOCACHE_NAME
;
184 if (pflags
& PUFFS_FLAG_OPDUMP
)
190 if (lstat(argv
[0], &sb
) == -1)
191 err(1, "stat %s", argv
[0]);
192 if ((sb
.st_mode
& S_IFDIR
) == 0)
193 errx(1, "%s is not a directory", argv
[0]);
196 puffs_null_setops(pops
);
199 PUFFSOP_SET(pops
, ic
, node
, readdir
);
201 if ((pu
= puffs_init(pops
, argv
[0], "ic", NULL
, pflags
)) == NULL
)
204 pn_root
= puffs_pn_new(pu
, NULL
);
206 err(1, "puffs_pn_new");
207 puffs_setroot(pu
, pn_root
);
209 po_root
= puffs_getrootpathobj(pu
);
211 err(1, "getrootpathobj");
212 po_root
->po_path
= argv
[0];
213 po_root
->po_len
= strlen(argv
[0]);
214 puffs_stat2vattr(&pn_root
->pn_va
, &sb
);
216 puffs_set_pathcmp(pu
, icpathcmp
);
217 puffs_set_pathtransform(pu
, icpathxform
);
220 if (puffs_daemon(pu
, 1, 1) == -1)
221 err(1, "puffs_daemon");
223 if (puffs_mount(pu
, argv
[1], mntflags
, pn_root
) == -1)
224 err(1, "puffs_mount");
225 if (puffs_mainloop(pu
) == -1)
232 ic_node_readdir(struct puffs_usermount
*pu
, void *opc
, struct dirent
*dent
,
233 off_t
*readoff
, size_t *reslen
, const struct puffs_cred
*pcr
,
234 int *eofflag
, off_t
*cookies
, size_t *ncookies
)
243 rv
= puffs_null_node_readdir(pu
, opc
, dent
, readoff
, reslen
, pcr
,
244 eofflag
, cookies
, ncookies
);
248 while (rl
> *reslen
) {
249 dotolower(dp
->d_name
, dp
->d_namlen
);
250 rl
-= _DIRENT_SIZE(dp
);
251 dp
= _DIRENT_NEXT(dp
);