xref: /minix/minix/lib/libfsdriver/dentry.c (revision 83133719)
1 
2 #include "fsdriver.h"
3 #include <sys/dirent.h>
4 
5 /*
6  * Initialize a directory entry listing.
7  */
8 void
9 fsdriver_dentry_init(struct fsdriver_dentry * __restrict dentry,
10 	const struct fsdriver_data * __restrict data, size_t bytes,
11 	char * __restrict buf, size_t bufsize)
12 {
13 
14 	dentry->data = data;
15 	dentry->data_size = bytes;
16 	dentry->data_off = 0;
17 	dentry->buf = buf;
18 	dentry->buf_size = bufsize;
19 	dentry->buf_off = 0;
20 }
21 
22 /*
23  * Add an entry to a directory entry listing.  Return the entry size if it was
24  * added, zero if no more entries could be added and the listing should stop,
25  * or an error code in case of an error.
26  */
27 ssize_t
28 fsdriver_dentry_add(struct fsdriver_dentry * __restrict dentry, ino_t ino_nr,
29 	const char * __restrict name, size_t namelen, unsigned int type)
30 {
31 	struct dirent *dirent;
32 	size_t len, used;
33 	int r;
34 
35 	/* We could do several things here, but it should never happen.. */
36 	if (namelen > MAXNAMLEN)
37 		panic("fsdriver: directory entry name excessively long");
38 
39 	len = _DIRENT_RECLEN(dirent, namelen);
40 
41 	if (dentry->data_off + dentry->buf_off + len > dentry->data_size) {
42 		if (dentry->data_off == 0 && dentry->buf_off == 0)
43 			return EINVAL;
44 
45 		return 0;
46 	}
47 
48 	if (dentry->buf_off + len > dentry->buf_size) {
49 		if (dentry->buf_off == 0)
50 			panic("fsdriver: getdents buffer too small");
51 
52 		if ((r = fsdriver_copyout(dentry->data, dentry->data_off,
53 		    dentry->buf, dentry->buf_off)) != OK)
54 			return r;
55 
56 		dentry->data_off += dentry->buf_off;
57 		dentry->buf_off = 0;
58 	}
59 
60 	dirent = (struct dirent *)&dentry->buf[dentry->buf_off];
61 	dirent->d_fileno = ino_nr;
62 	dirent->d_reclen = len;
63 	dirent->d_namlen = namelen;
64 	dirent->d_type = type;
65 	memcpy(dirent->d_name, name, namelen);
66 
67 	/*
68 	 * Null-terminate the name, and zero out any alignment bytes after it,
69 	 * so as not to leak any data.
70 	 */
71 	used = _DIRENT_NAMEOFF(dirent) + namelen;
72 	if (used >= len)
73 		panic("fsdriver: inconsistency in dirent record");
74 	memset(&dirent->d_name[namelen], 0, len - used);
75 
76 	dentry->buf_off += len;
77 
78 	return len;
79 }
80 
81 /*
82  * Finish a directory entry listing operation.  Return the total number of
83  * bytes copied to the caller, or an error code in case of an error.
84  */
85 ssize_t
86 fsdriver_dentry_finish(struct fsdriver_dentry *dentry)
87 {
88 	int r;
89 
90 	if (dentry->buf_off > 0) {
91 		if ((r = fsdriver_copyout(dentry->data, dentry->data_off,
92 		    dentry->buf, dentry->buf_off)) != OK)
93 			return r;
94 
95 		dentry->data_off += dentry->buf_off;
96 	}
97 
98 	return dentry->data_off;
99 }
100