swissChili | 480f176 | 2021-07-26 22:17:34 -0700 | [diff] [blame] | 1 | #include <dri/fs/ext2/ext2.h> |
| 2 | #include <dri/fs/ext2/ext2_vfs.h> |
| 3 | #include <sync.h> |
| 4 | #include <alloc.h> |
| 5 | #include <log.h> |
| 6 | #include <io.h> |
| 7 | |
| 8 | struct ext2_fs_dirent |
| 9 | { |
| 10 | struct fs_node *node; |
| 11 | char name[256]; |
| 12 | uint name_len; |
| 13 | uint inode; |
| 14 | |
| 15 | struct ext2_fs_dirent *next; |
| 16 | }; |
| 17 | |
| 18 | struct ext2_fs_data |
| 19 | { |
| 20 | struct ext2_superblock *sb; |
| 21 | |
| 22 | /// Cached inode |
| 23 | struct ext2_inode *in; |
| 24 | |
| 25 | /// Reference count for the inode cache. Once this hits 0 we free |
| 26 | /// in. Only used for **files**, directories **always** cache |
| 27 | /// their inode. |
| 28 | uint rc; |
| 29 | |
| 30 | semaphore_t lock; |
| 31 | |
| 32 | /// Entries (if this is a directory) |
| 33 | struct ext2_fs_dirent *dirent; |
| 34 | }; |
| 35 | |
| 36 | uint ext2_file_read(struct fs_node *node, size_t ofs, size_t size, |
| 37 | uchar *buffer) |
| 38 | { |
| 39 | struct ext2_fs_data *d = node->dri_res_p; |
| 40 | const uint block_size = ext2_block_size(d->sb); |
| 41 | |
| 42 | // temporary buffer |
| 43 | uchar *tmp = malloc(block_size); |
| 44 | |
| 45 | uint num_read = 0; |
| 46 | |
| 47 | if (!buffer) |
| 48 | { |
| 49 | kprintf(WARN "ext2_file_read out of memory!\n"); |
| 50 | return 0; |
| 51 | } |
| 52 | |
| 53 | uint block_start = ofs / block_size; |
| 54 | uint block_offset = ofs % block_size; |
| 55 | int to_read; |
| 56 | |
| 57 | do |
| 58 | { |
| 59 | // How much from this block to read |
| 60 | to_read = MIN(block_size - block_offset, size); |
| 61 | ext2_read_inode_block(d->sb, d->in, tmp, block_start); |
| 62 | |
| 63 | // Copy that to the user buffer |
| 64 | memcpy(buffer, tmp + block_offset, to_read); |
| 65 | buffer += to_read; |
| 66 | size -= to_read; |
| 67 | num_read += to_read; |
| 68 | |
| 69 | // Move to the next block |
| 70 | block_start++; |
| 71 | block_offset = 0; |
| 72 | } |
| 73 | while (to_read > 0); |
| 74 | |
| 75 | free(tmp); |
| 76 | return num_read; |
| 77 | } |
| 78 | |
| 79 | void ext2_file_open(struct fs_node *node) |
| 80 | { |
| 81 | struct ext2_fs_data *d = node->dri_res_p; |
| 82 | |
| 83 | sm_wait(d->lock); |
| 84 | |
| 85 | if (d->rc++ == 0) |
| 86 | { |
| 87 | d->in = malloc(sizeof(struct ext2_inode)); |
| 88 | |
| 89 | if (d->in == NULL) |
| 90 | { |
| 91 | // lol |
| 92 | kpanic("ext2_file_open: ENOMEM"); |
| 93 | } |
| 94 | |
| 95 | if (!ext2_find_inode(d->sb, node->inode, d->in)) |
| 96 | { |
| 97 | kprintf(ERROR "ext2_file_open: can't find inode %d\n", |
| 98 | node->inode); |
| 99 | |
| 100 | free(d->in); |
| 101 | goto done; |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | done: |
| 106 | sm_signal(d->lock); |
| 107 | } |
| 108 | |
| 109 | void ext2_file_close(struct fs_node *node) |
| 110 | { |
| 111 | struct ext2_fs_data *d = node->dri_res_p; |
| 112 | |
| 113 | sm_wait(d->lock); |
| 114 | |
| 115 | if (--d->rc == 0) |
| 116 | { |
| 117 | free(d->in); |
| 118 | d->in = NULL; |
| 119 | } |
| 120 | |
| 121 | sm_signal(d->lock); |
| 122 | } |
| 123 | |
| 124 | struct fs_vtable ext2_file_vfs_vt = |
| 125 | { |
| 126 | .read = ext2_file_read, |
| 127 | .write = NULL, |
| 128 | .open = ext2_file_open, |
| 129 | .close = ext2_file_close, |
| 130 | .readdir = NULL, |
| 131 | .finddir = NULL, |
| 132 | }; |
| 133 | |
| 134 | bool ext2_dir_readdir(struct fs_node *node, uint index, struct fs_dirent *dirent) |
| 135 | { |
| 136 | struct ext2_fs_data *d = node->dri_res_p; |
| 137 | struct ext2_fs_dirent *dent = d->dirent; |
| 138 | |
| 139 | uint i; |
| 140 | |
| 141 | for (i = 0; i < index && dent; i++, dent = dent->next) |
| 142 | { |
| 143 | } |
| 144 | |
swissChili | 9d87678 | 2021-07-27 19:50:07 -0700 | [diff] [blame] | 145 | if (dent && i == index) |
swissChili | 480f176 | 2021-07-26 22:17:34 -0700 | [diff] [blame] | 146 | { |
swissChili | 9d87678 | 2021-07-27 19:50:07 -0700 | [diff] [blame] | 147 | memcpy(dirent->name, dent->name, MAX(dent->name_len, FS_MAX_NAME_LEN)); |
swissChili | 480f176 | 2021-07-26 22:17:34 -0700 | [diff] [blame] | 148 | dirent->name_len = dent->name_len; |
| 149 | dirent->inode = dent->inode; |
| 150 | |
| 151 | return true; |
| 152 | } |
| 153 | |
| 154 | return false; |
| 155 | } |
| 156 | |
| 157 | struct fs_node *ext2_dir_finddir(struct fs_node *node, char *name, uint name_len) |
| 158 | { |
| 159 | name_len = MIN(name_len, 256); |
| 160 | struct ext2_fs_data *d = node->dri_res_p; |
| 161 | struct ext2_fs_dirent *dent = d->dirent; |
| 162 | |
| 163 | for (; dent; dent = dent->next) |
| 164 | { |
| 165 | if (strncmp(dent->name, name, name_len) == 0) |
| 166 | { |
| 167 | return dent->node; |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | return NULL; |
| 172 | } |
| 173 | |
| 174 | struct fs_vtable ext2_dir_vfs_vt = |
| 175 | { |
| 176 | .read = NULL, |
| 177 | .write = NULL, |
| 178 | .open = NULL, |
| 179 | .close = NULL, |
| 180 | .readdir = ext2_dir_readdir, |
| 181 | .finddir = ext2_dir_finddir, |
| 182 | }; |
| 183 | |
| 184 | struct ext2_fs_dirent_to_fs_data |
| 185 | { |
| 186 | struct ext2_fs_data *d; |
| 187 | struct ext2_fs_dirent *last; |
| 188 | struct ext2_superblock *sb; |
| 189 | }; |
| 190 | |
| 191 | static bool ext2_dirent_to_fs_node_cb(uint inode, const char *name, |
| 192 | uint name_len, void *data) |
| 193 | { |
| 194 | struct ext2_fs_dirent_to_fs_data *d = data; |
| 195 | |
| 196 | struct ext2_fs_dirent *dent = |
| 197 | malloc(sizeof(struct ext2_fs_dirent)); |
| 198 | |
swissChili | 9d87678 | 2021-07-27 19:50:07 -0700 | [diff] [blame] | 199 | if (strncmp(".", (char *)name, name_len) == 0 || |
| 200 | strncmp("..", (char *)name, name_len) == 0) |
swissChili | a664e72 | 2021-07-27 17:47:55 -0700 | [diff] [blame] | 201 | { |
| 202 | return true; |
| 203 | } |
| 204 | |
swissChili | 480f176 | 2021-07-26 22:17:34 -0700 | [diff] [blame] | 205 | dent->node = ext2_inode2vfs(d->sb, inode, (char *)name, name_len); |
| 206 | dent->name_len = name_len; |
| 207 | memcpy(dent->name, name, MIN(name_len, 256)); |
| 208 | dent->inode = inode; |
| 209 | |
| 210 | if (d->last) |
| 211 | { |
| 212 | d->last->next = dent; |
| 213 | d->last = dent; |
| 214 | } |
| 215 | else |
| 216 | { |
| 217 | d->last = d->d->dirent = dent; |
| 218 | } |
| 219 | |
| 220 | return true; |
| 221 | } |
| 222 | |
| 223 | struct fs_node *ext2_inode2vfs(struct ext2_superblock *sb, uint inode, |
| 224 | char *name, uint name_len) |
| 225 | { |
| 226 | struct ext2_inode in; |
| 227 | |
| 228 | if (!ext2_find_inode(sb, inode, &in)) |
| 229 | { |
| 230 | // Something has gone terribly wrong! |
| 231 | return NULL; |
| 232 | } |
| 233 | |
| 234 | struct ext2_fs_data *d = malloc(sizeof(struct ext2_fs_data)); |
| 235 | |
| 236 | d->sb = sb; |
| 237 | d->rc = 0; |
| 238 | d->lock = sm_new(); |
| 239 | d->in = NULL; |
| 240 | d->dirent = NULL; |
| 241 | |
| 242 | struct fs_node *n = malloc(sizeof(struct fs_node)); |
| 243 | |
| 244 | n->name_len = MIN(name_len, FS_MAX_NAME_LEN); |
| 245 | memcpy(n->name, name, n->name_len); |
| 246 | n->inode = inode; |
| 247 | n->dri_res_p = d; |
| 248 | |
| 249 | n->mask = in.mode & 0xfff; |
| 250 | n->gid = in.gid; |
| 251 | n->uid = in.uid; |
| 252 | n->size = in.size; |
| 253 | |
| 254 | switch (in.mode & EXT2_F_TYPE) |
| 255 | { |
| 256 | case EXT2_S_IFREG: |
| 257 | { |
| 258 | n->flags = FS_FILE; |
| 259 | n->vtable = &ext2_file_vfs_vt; |
| 260 | |
| 261 | break; |
| 262 | } |
| 263 | |
| 264 | case EXT2_S_IFDIR: |
| 265 | { |
| 266 | n->flags = FS_DIRECTORY; |
| 267 | n->vtable = &ext2_dir_vfs_vt; |
| 268 | |
| 269 | struct ext2_fs_dirent_to_fs_data data; |
| 270 | data.d = d; |
| 271 | data.last = NULL; |
swissChili | a664e72 | 2021-07-27 17:47:55 -0700 | [diff] [blame] | 272 | data.sb = sb; |
swissChili | 480f176 | 2021-07-26 22:17:34 -0700 | [diff] [blame] | 273 | |
| 274 | ext2_dir_ls(sb, &in, ext2_dirent_to_fs_node_cb, &data); |
| 275 | |
| 276 | break; |
| 277 | } |
| 278 | |
| 279 | default: |
| 280 | { |
| 281 | kprintf(ERROR "ext2_inode2vfs: unimplemented for dir type%d\n", |
| 282 | EXT2_S_TO_FT(in.mode)); |
| 283 | kpanic("Unimplemented"); |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | return n; |
| 288 | } |