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