1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 */ 9 10 #include <rtthread.h> 11 #include <dfs.h> 12 #include <dfs_fs.h> 13 #include <dfs_file.h> 14 15 #include "dfs_romfs.h" 16 17 int dfs_romfs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data) 18 { 19 struct romfs_dirent *root_dirent; 20 21 if (data == NULL) 22 return -EIO; 23 24 root_dirent = (struct romfs_dirent *)data; 25 fs->data = root_dirent; 26 27 return RT_EOK; 28 } 29 30 int dfs_romfs_unmount(struct dfs_filesystem *fs) 31 { 32 return RT_EOK; 33 } 34 35 int dfs_romfs_ioctl(struct dfs_fd *file, int cmd, void *args) 36 { 37 return -EIO; 38 } 39 40 rt_inline int check_dirent(struct romfs_dirent *dirent) 41 { 42 if ((dirent->type != ROMFS_DIRENT_FILE && dirent->type != ROMFS_DIRENT_DIR) 43 || dirent->size == ~0) 44 return -1; 45 return 0; 46 } 47 48 struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const char *path, rt_size_t *size) 49 { 50 rt_size_t index, found; 51 const char *subpath, *subpath_end; 52 struct romfs_dirent *dirent; 53 rt_size_t dirent_size; 54 55 /* Check the root_dirent. */ 56 if (check_dirent(root_dirent) != 0) 57 return NULL; 58 59 if (path[0] == '/' && path[1] == '\0') 60 { 61 *size = root_dirent->size; 62 return root_dirent; 63 } 64 65 /* goto root directy entries */ 66 dirent = (struct romfs_dirent *)root_dirent->data; 67 dirent_size = root_dirent->size; 68 69 /* get the end position of this subpath */ 70 subpath_end = path; 71 /* skip /// */ 72 while (*subpath_end && *subpath_end == '/') 73 subpath_end ++; 74 subpath = subpath_end; 75 while ((*subpath_end != '/') && *subpath_end) 76 subpath_end ++; 77 78 while (dirent != NULL) 79 { 80 found = 0; 81 82 /* search in folder */ 83 for (index = 0; index < dirent_size; index ++) 84 { 85 if (check_dirent(&dirent[index]) != 0) 86 return NULL; 87 if (rt_strlen(dirent[index].name) == (subpath_end - subpath) && 88 rt_strncmp(dirent[index].name, subpath, (subpath_end - subpath)) == 0) 89 { 90 dirent_size = dirent[index].size; 91 92 /* skip /// */ 93 while (*subpath_end && *subpath_end == '/') 94 subpath_end ++; 95 subpath = subpath_end; 96 while ((*subpath_end != '/') && *subpath_end) 97 subpath_end ++; 98 99 if (!(*subpath)) 100 { 101 *size = dirent_size; 102 return &dirent[index]; 103 } 104 105 if (dirent[index].type == ROMFS_DIRENT_DIR) 106 { 107 /* enter directory */ 108 dirent = (struct romfs_dirent*)dirent[index].data; 109 found = 1; 110 break; 111 } 112 else 113 { 114 /* return file dirent */ 115 if (subpath != NULL) 116 break; /* not the end of path */ 117 118 return &dirent[index]; 119 } 120 } 121 } 122 123 if (!found) 124 break; /* not found */ 125 } 126 127 /* not found */ 128 return NULL; 129 } 130 131 int dfs_romfs_read(struct dfs_fd *file, void *buf, size_t count) 132 { 133 rt_size_t length; 134 struct romfs_dirent *dirent; 135 136 dirent = (struct romfs_dirent *)file->data; 137 RT_ASSERT(dirent != NULL); 138 139 if (check_dirent(dirent) != 0) 140 { 141 return -EIO; 142 } 143 144 if (count < file->size - file->pos) 145 length = count; 146 else 147 length = file->size - file->pos; 148 149 if (length > 0) 150 memcpy(buf, &(dirent->data[file->pos]), length); 151 152 /* update file current position */ 153 file->pos += length; 154 155 return length; 156 } 157 158 int dfs_romfs_lseek(struct dfs_fd *file, off_t offset) 159 { 160 if (offset <= file->size) 161 { 162 file->pos = offset; 163 return file->pos; 164 } 165 166 return -EIO; 167 } 168 169 int dfs_romfs_close(struct dfs_fd *file) 170 { 171 file->data = NULL; 172 return RT_EOK; 173 } 174 175 int dfs_romfs_open(struct dfs_fd *file) 176 { 177 rt_size_t size; 178 struct romfs_dirent *dirent; 179 struct romfs_dirent *root_dirent; 180 struct dfs_filesystem *fs; 181 182 fs = (struct dfs_filesystem *)file->data; 183 root_dirent = (struct romfs_dirent *)fs->data; 184 185 if (check_dirent(root_dirent) != 0) 186 return -EIO; 187 188 if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR)) 189 return -EINVAL; 190 191 dirent = dfs_romfs_lookup(root_dirent, file->path, &size); 192 if (dirent == NULL) 193 return -ENOENT; 194 195 /* entry is a directory file type */ 196 if (dirent->type == ROMFS_DIRENT_DIR) 197 { 198 if (!(file->flags & O_DIRECTORY)) 199 return -ENOENT; 200 } 201 else 202 { 203 /* entry is a file, but open it as a directory */ 204 if (file->flags & O_DIRECTORY) 205 return -ENOENT; 206 } 207 208 file->data = dirent; 209 file->size = size; 210 file->pos = 0; 211 212 return RT_EOK; 213 } 214 215 int dfs_romfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st) 216 { 217 rt_size_t size; 218 struct romfs_dirent *dirent; 219 struct romfs_dirent *root_dirent; 220 221 root_dirent = (struct romfs_dirent *)fs->data; 222 dirent = dfs_romfs_lookup(root_dirent, path, &size); 223 224 if (dirent == NULL) 225 return -ENOENT; 226 227 st->st_dev = 0; 228 st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | 229 S_IWUSR | S_IWGRP | S_IWOTH; 230 231 if (dirent->type == ROMFS_DIRENT_DIR) 232 { 233 st->st_mode &= ~S_IFREG; 234 st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; 235 } 236 237 st->st_size = dirent->size; 238 st->st_mtime = 0; 239 240 return RT_EOK; 241 } 242 243 int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count) 244 { 245 rt_size_t index; 246 const char *name; 247 struct dirent *d; 248 struct romfs_dirent *dirent, *sub_dirent; 249 250 dirent = (struct romfs_dirent *)file->data; 251 if (check_dirent(dirent) != 0) 252 return -EIO; 253 RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR); 254 255 /* enter directory */ 256 dirent = (struct romfs_dirent *)dirent->data; 257 258 /* make integer count */ 259 count = (count / sizeof(struct dirent)); 260 if (count == 0) 261 return -EINVAL; 262 263 index = 0; 264 for (index = 0; index < count && file->pos < file->size; index ++) 265 { 266 d = dirp + index; 267 268 sub_dirent = &dirent[file->pos]; 269 name = sub_dirent->name; 270 271 /* fill dirent */ 272 if (sub_dirent->type == ROMFS_DIRENT_DIR) 273 d->d_type = DT_DIR; 274 else 275 d->d_type = DT_REG; 276 277 d->d_namlen = rt_strlen(name); 278 d->d_reclen = (rt_uint16_t)sizeof(struct dirent); 279 rt_strncpy(d->d_name, name, rt_strlen(name) + 1); 280 281 /* move to next position */ 282 ++ file->pos; 283 } 284 285 return index * sizeof(struct dirent); 286 } 287 288 static const struct dfs_file_ops _rom_fops = 289 { 290 dfs_romfs_open, 291 dfs_romfs_close, 292 dfs_romfs_ioctl, 293 dfs_romfs_read, 294 NULL, 295 NULL, 296 dfs_romfs_lseek, 297 dfs_romfs_getdents, 298 }; 299 static const struct dfs_filesystem_ops _romfs = 300 { 301 "rom", 302 DFS_FS_FLAG_DEFAULT, 303 &_rom_fops, 304 305 dfs_romfs_mount, 306 dfs_romfs_unmount, 307 NULL, 308 NULL, 309 310 NULL, 311 dfs_romfs_stat, 312 NULL, 313 }; 314 315 int dfs_romfs_init(void) 316 { 317 /* register rom file system */ 318 dfs_register(&_romfs); 319 return 0; 320 } 321 INIT_COMPONENT_EXPORT(dfs_romfs_init); 322 323