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