2 * Copyright © 2007 Alistair Crooks. 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.
12 * 3. The name of the author may not be used to endorse or promote
13 * products derived from this software without specific prior written
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
31 #define FUSE_USE_VERSION 26
41 /* utility comparison routine for sorting and searching */
43 compare(const void *vp1
, const void *vp2
)
45 const virt_dirent_t
*tp1
= (const virt_dirent_t
*) vp1
;
46 const virt_dirent_t
*tp2
= (const virt_dirent_t
*) vp2
;
48 return strcmp(tp1
->name
, tp2
->name
);
51 /* save `n' chars of `s' in allocated storage */
53 strnsave(const char *s
, int n
)
60 NEWARRAY(char, cp
, n
+ 1, "strnsave", return NULL
);
61 (void) memcpy(cp
, s
, n
);
66 /* ensure intermediate directories exist */
68 mkdirs(virtdir_t
*tp
, const char *path
, size_t size
)
71 char name
[MAXPATHLEN
];
74 (void) strlcpy(name
, path
, sizeof(name
));
75 for (slash
= name
+ 1 ; (slash
= strchr(slash
+ 1, '/')) != NULL
; ) {
77 if ((ep
= virtdir_find(tp
, name
, strlen(name
))) == NULL
) {
78 virtdir_add(tp
, name
, strlen(name
), 'd', NULL
, 0);
84 /* get rid of multiple slashes in input */
86 normalise(const char *name
, size_t namelen
, char *path
, size_t pathsize
)
92 for (pp
= path
, np
= name
, done
= 0 ; !done
&& (int)(pp
- path
) < pathsize
- 1 && (int)(np
- name
) <= namelen
; ) {
95 if (pp
== path
|| *(pp
- 1) != '/') {
108 /* XXX - trailing slash? */
110 return (int)(pp
- path
);
113 /* initialise the tree */
115 virtdir_init(virtdir_t
*tp
, const char *rootdir
, struct stat
*d
, struct stat
*f
, struct stat
*l
)
117 (void) memcpy(&tp
->dir
, d
, sizeof(tp
->dir
));
118 tp
->dir
.st_mode
= S_IFDIR
| 0755;
119 tp
->dir
.st_nlink
= 2;
120 (void) memcpy(&tp
->file
, f
, sizeof(tp
->file
));
121 tp
->file
.st_mode
= S_IFREG
| 0644;
122 tp
->file
.st_nlink
= 1;
123 (void) memcpy(&tp
->lnk
, l
, sizeof(tp
->lnk
));
124 tp
->lnk
.st_mode
= S_IFLNK
| 0644;
125 tp
->lnk
.st_nlink
= 1;
126 if (rootdir
!= NULL
) {
127 tp
->rootdir
= strdup(rootdir
);
132 /* add an entry to the tree */
134 virtdir_add(virtdir_t
*tp
, const char *name
, size_t size
, uint8_t type
, const char *tgt
, size_t tgtlen
)
137 char path
[MAXPATHLEN
];
141 (void) stat(".", &st
);
142 virtdir_init(tp
, NULL
, &st
, &st
, &st
);
144 pathlen
= normalise(name
, size
, path
, sizeof(path
));
145 if (virtdir_find(tp
, path
, pathlen
) != NULL
) {
146 /* attempt to add a duplicate directory entry */
149 ALLOC(virt_dirent_t
, tp
->v
, tp
->size
, tp
->c
, 10, 10, "virtdir_add",
151 tp
->v
[tp
->c
].namelen
= pathlen
;
152 if ((tp
->v
[tp
->c
].name
= strnsave(path
, pathlen
)) == NULL
) {
155 tp
->v
[tp
->c
].d_name
= strrchr(tp
->v
[tp
->c
].name
, '/') + 1;
156 tp
->v
[tp
->c
].type
= type
;
157 tp
->v
[tp
->c
].ino
= (ino_t
) random() & 0xfffff;
159 tp
->v
[tp
->c
].tgtlen
= tgtlen
;
160 tp
->v
[tp
->c
].tgt
= strnsave(tgt
, tgtlen
);
163 qsort(tp
->v
, tp
->c
, sizeof(tp
->v
[0]), compare
);
164 mkdirs(tp
, path
, pathlen
);
168 /* delete an entry from the tree */
170 virtdir_del(virtdir_t
*tp
, const char *name
, size_t size
)
175 if ((ep
= virtdir_find(tp
, name
, size
)) == NULL
) {
178 i
= (int)(ep
- tp
->v
);
179 for (tp
->c
-= 1 ; i
< tp
->c
; i
++) {
180 tp
->v
[i
] = tp
->v
[i
+ 1];
185 /* find an entry in the tree */
187 virtdir_find(virtdir_t
*tp
, const char *name
, size_t namelen
)
190 char path
[MAXPATHLEN
];
192 (void) memset(&e
, 0x0, sizeof(e
));
193 e
.namelen
= normalise(name
, namelen
, path
, sizeof(path
));
195 return bsearch(&e
, tp
->v
, tp
->c
, sizeof(tp
->v
[0]), compare
);
198 /* return the virtual offset in the tree */
200 virtdir_offset(virtdir_t
*tp
, virt_dirent_t
*dp
)
202 return (int)(dp
- tp
->v
);
205 /* analogous to opendir(3) - open a directory, save information, and
206 * return a pointer to the dynamically allocated structure */
208 openvirtdir(virtdir_t
*tp
, const char *d
)
212 NEW(VIRTDIR
, dirp
, "openvirtdir", exit(EXIT_FAILURE
));
213 dirp
->dirname
= strdup(d
);
214 dirp
->dirnamelen
= strlen(d
);
220 /* analogous to readdir(3) - read the next entry in the directory that
221 * was opened, and return a pointer to it */
223 readvirtdir(VIRTDIR
*dirp
)
227 for ( ; dirp
->i
< dirp
->tp
->c
; dirp
->i
++) {
228 from
= (strcmp(dirp
->dirname
, "/") == 0) ?
229 &dirp
->tp
->v
[dirp
->i
].name
[1] :
230 &dirp
->tp
->v
[dirp
->i
].name
[dirp
->dirnamelen
+ 1];
231 if (strncmp(dirp
->tp
->v
[dirp
->i
].name
, dirp
->dirname
,
232 dirp
->dirnamelen
) == 0 &&
234 strchr(from
, '/') == NULL
) {
235 return &dirp
->tp
->v
[dirp
->i
++];
241 /* free the storage associated with the virtual directory structure */
243 closevirtdir(VIRTDIR
*dirp
)
249 /* find a target in the tree -- not quick! */
251 virtdir_find_tgt(virtdir_t
*tp
, const char *tgt
, size_t tgtlen
)
253 /* we don't need no stinking binary searches */
254 char path
[MAXPATHLEN
];
257 (void) normalise(tgt
, tgtlen
, path
, sizeof(path
));
258 for (i
= 0 ; i
< tp
->c
; i
++) {
259 if (tp
->v
[i
].tgt
&& strcmp(tp
->v
[i
].tgt
, path
) == 0) {
266 /* kill all of the space allocated to the tree */
268 virtdir_drop(virtdir_t
*tp
)
272 for (i
= 0 ; i
< tp
->c
; i
++) {
281 /* return the value of the root directory of the tree */
283 virtdir_rootdir(virtdir_t
*tp
)
290 ptree(virtdir_t
* tp
)
294 for (i
= 0 ; i
< tp
->c
; i
++) {
295 printf("%s, tgt %s\n", tp
->v
[i
].name
, tp
->v
[i
].tgt
);
302 main(int argc
, char **argv
)
308 (void) memset(&t
, 0x0, sizeof(t
));
310 virtdir_add(&t
, ".", 1, 'd', NULL
, 0);
312 virtdir_add(&t
, "..", 2, 'd', NULL
, 0);
313 st
.st_mode
= S_IFREG
| 0644;
314 virtdir_add(&t
, "file1", 5, 'f', NULL
, 0);
316 virtdir_add(&t
, "file2", 5, 'f', NULL
, 0);
317 virtdir_add(&t
, "file0", 5, 'f', NULL
, 0);
318 virtdir_add(&t
, "abcde", 5, 'f', NULL
, 0);
319 virtdir_add(&t
, "bcdef", 5, 'f', NULL
, 0);
320 virtdir_add(&t
, "a", 1, 'f', NULL
, 0);
322 if ((tp
= virtdir_find(&t
, "a", 1)) == NULL
) {