devtmpfs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-10-24 flybreak the first version
  9. * 2023-02-01 xqyjlj fix cannot open the same file repeatedly in 'w' mode
  10. * 2023-09-20 zmq810150896 adds truncate functionality and standardized unlink adaptations
  11. * 2023-12-02 Shell Support of dynamic device
  12. */
  13. #include <rthw.h>
  14. #include <rtthread.h>
  15. #include <dfs.h>
  16. #include <dfs_fs.h>
  17. #include <dfs_dentry.h>
  18. #include <dfs_file.h>
  19. #include <dfs_mnt.h>
  20. #include <dfs_vfs.h>
  21. #include <devfs.h>
  22. #include <unistd.h>
  23. #define TMPFS_MAGIC 0x0B0B0B0B
  24. #define TMPFS_TYPE_FILE 0x00
  25. #define TMPFS_TYPE_DIR 0x01
  26. #define TMPFS_TYPE_DYN_DEV 0x02 /* dynamic device */
  27. struct devtmpfs_sb;
  28. struct devtmpfs_file
  29. {
  30. char name[DIRENT_NAME_MAX]; /* file name */
  31. rt_uint32_t type; /* file type */
  32. struct dfs_vfs_node node; /* file node in the devtmpfs */
  33. struct devtmpfs_sb *sb; /* superblock ptr */
  34. rt_uint32_t mode;
  35. char *link;
  36. };
  37. struct devtmpfs_sb
  38. {
  39. rt_uint32_t magic; /* TMPFS_MAGIC */
  40. struct devtmpfs_file root; /* root dir */
  41. rt_size_t df_size; /* df size */
  42. struct rt_spinlock lock; /* tmpfs lock */
  43. };
  44. static struct dfs_file_ops _default_fops = { 0 };
  45. static int _path_separate(const char *path, char *parent_path, char *file_name)
  46. {
  47. const char *path_p, *path_q;
  48. RT_ASSERT(path[0] == '/');
  49. file_name[0] = '\0';
  50. path_p = path_q = &path[1];
  51. __next_dir:
  52. while (*path_q != '/' && *path_q != '\0')
  53. {
  54. path_q++;
  55. }
  56. if (path_q != path_p) /*sub dir*/
  57. {
  58. if (*path_q != '\0')
  59. {
  60. path_q++;
  61. path_p = path_q;
  62. goto __next_dir;
  63. }
  64. else /* Last level dir */
  65. {
  66. rt_memcpy(parent_path, path, path_p - path - 1);
  67. parent_path[path_p - path - 1] = '\0';
  68. rt_memcpy(file_name, path_p, path_q - path_p);
  69. file_name[path_q - path_p] = '\0';
  70. }
  71. }
  72. if (parent_path[0] == 0)
  73. {
  74. parent_path[0] = '/';
  75. parent_path[1] = '\0';
  76. }
  77. //LOG_D("parent_path: %s", parent_path);
  78. //LOG_D("file_name: %s", file_name);
  79. return 0;
  80. }
  81. static int _get_subdir(const char *path, char *name)
  82. {
  83. const char *subpath = path;
  84. while (*subpath == '/' && *subpath)
  85. subpath ++;
  86. while (*subpath != '/' && *subpath)
  87. {
  88. *name = *subpath;
  89. name ++;
  90. subpath ++;
  91. }
  92. return 0;
  93. }
  94. #if 0
  95. static int _free_subdir(struct devtmpfs_file *dfile)
  96. {
  97. struct devtmpfs_file *file, *tmp;
  98. struct devtmpfs_sb *superblock;
  99. RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
  100. dfs_vfs_for_each_subnode(file, tmp, dfile, node)
  101. {
  102. if (file->type == TMPFS_TYPE_DIR)
  103. {
  104. _free_subdir(file);
  105. }
  106. if (file->link)
  107. {
  108. rt_free(file->link);
  109. }
  110. superblock = file->sb;
  111. RT_ASSERT(superblock);
  112. rt_spin_lock(&superblock->lock);
  113. dfs_vfs_remove_node(&file->node);
  114. rt_spin_unlock(&superblock->lock);
  115. rt_free(file);
  116. }
  117. return 0;
  118. }
  119. #endif
  120. static int devtmpfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
  121. {
  122. struct devtmpfs_sb *superblock;
  123. superblock = rt_calloc(1, sizeof(struct devtmpfs_sb));
  124. if (superblock)
  125. {
  126. superblock->df_size = sizeof(struct devtmpfs_sb);
  127. superblock->magic = TMPFS_MAGIC;
  128. superblock->root.name[0] = '/';
  129. superblock->root.sb = superblock;
  130. superblock->root.type = TMPFS_TYPE_DIR;
  131. superblock->root.mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
  132. dfs_vfs_init_node(&superblock->root.node);
  133. rt_spin_lock_init(&superblock->lock);
  134. mnt->data = superblock;
  135. }
  136. else
  137. {
  138. return -RT_ERROR;
  139. }
  140. return RT_EOK;
  141. }
  142. static int devtmpfs_unmount(struct dfs_mnt *mnt)
  143. {
  144. #if 0
  145. struct devtmpfs_sb *superblock;
  146. /* FIXME: don't unmount on busy. */
  147. superblock = (struct devtmpfs_sb *)mnt->data;
  148. RT_ASSERT(superblock != NULL);
  149. mnt->data = NULL;
  150. _free_subdir(&(superblock->root));
  151. rt_free(superblock);
  152. #endif
  153. return -RT_ERROR;
  154. }
  155. static struct devtmpfs_file *devtmpfs_file_lookup(struct devtmpfs_sb *superblock, const char *path)
  156. {
  157. const char *subpath, *curpath, *filename = RT_NULL;
  158. char subdir_name[DIRENT_NAME_MAX];
  159. struct devtmpfs_file *file, *curfile, *tmp;
  160. subpath = path;
  161. while (*subpath == '/' && *subpath)
  162. subpath ++;
  163. if (! *subpath) /* is root directory */
  164. {
  165. return &(superblock->root);
  166. }
  167. curpath = subpath;
  168. curfile = &superblock->root;
  169. find_subpath:
  170. while (*subpath != '/' && *subpath)
  171. subpath ++;
  172. if (! *subpath) /* is last directory */
  173. filename = curpath;
  174. else
  175. subpath ++; /* skip '/' */
  176. memset(subdir_name, 0, DIRENT_NAME_MAX);
  177. _get_subdir(curpath, subdir_name);
  178. rt_spin_lock(&superblock->lock);
  179. dfs_vfs_for_each_subnode(file, tmp, curfile, node)
  180. {
  181. if (filename) /* find file */
  182. {
  183. if (rt_strcmp(file->name, filename) == 0)
  184. {
  185. rt_spin_unlock(&superblock->lock);
  186. return file;
  187. }
  188. }
  189. else if (rt_strcmp(file->name, subdir_name) == 0)
  190. {
  191. curpath = subpath;
  192. curfile = file;
  193. rt_spin_unlock(&superblock->lock);
  194. goto find_subpath;
  195. }
  196. }
  197. rt_spin_unlock(&superblock->lock);
  198. /* not found */
  199. return NULL;
  200. }
  201. static int devtmpfs_statfs(struct dfs_mnt *mnt, struct statfs *buf)
  202. {
  203. struct devtmpfs_sb *superblock;
  204. RT_ASSERT(mnt != NULL);
  205. RT_ASSERT(buf != NULL);
  206. superblock = (struct devtmpfs_sb *)mnt->data;
  207. RT_ASSERT(superblock != NULL);
  208. buf->f_bsize = 512;
  209. buf->f_blocks = (superblock->df_size + 511) / 512;
  210. buf->f_bfree = 1;
  211. buf->f_bavail = buf->f_bfree;
  212. return RT_EOK;
  213. }
  214. static int devtmpfs_stat(struct dfs_dentry *dentry, struct stat *st)
  215. {
  216. struct dfs_vnode *vnode;
  217. if (dentry && dentry->vnode)
  218. {
  219. vnode = dentry->vnode;
  220. st->st_dev = (dev_t)(long)(dentry->mnt->dev_id);
  221. st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
  222. st->st_gid = vnode->gid;
  223. st->st_uid = vnode->uid;
  224. st->st_mode = vnode->mode;
  225. st->st_nlink = vnode->nlink;
  226. st->st_size = vnode->size;
  227. st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
  228. st->st_mtim.tv_sec = vnode->mtime.tv_sec;
  229. st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
  230. st->st_ctim.tv_sec = vnode->ctime.tv_sec;
  231. st->st_atim.tv_nsec = vnode->atime.tv_nsec;
  232. st->st_atim.tv_sec = vnode->atime.tv_sec;
  233. }
  234. return RT_EOK;
  235. }
  236. static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
  237. {
  238. rt_size_t index, end;
  239. struct dirent *d;
  240. struct devtmpfs_file *d_file, *n_file = RT_NULL, *tmp;
  241. struct devtmpfs_sb *superblock;
  242. RT_ASSERT(file);
  243. RT_ASSERT(file->dentry);
  244. RT_ASSERT(file->dentry->mnt);
  245. superblock = (struct devtmpfs_sb *)file->dentry->mnt->data;
  246. RT_ASSERT(superblock);
  247. d_file = devtmpfs_file_lookup(superblock, file->dentry->pathname);
  248. if (d_file)
  249. {
  250. /* make integer count */
  251. count = (count / sizeof(struct dirent));
  252. if (count == 0)
  253. {
  254. return -EINVAL;
  255. }
  256. end = file->fpos + count;
  257. index = 0;
  258. count = 0;
  259. dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
  260. {
  261. if (index >= (rt_size_t)file->fpos)
  262. {
  263. d = dirp + count;
  264. if (n_file->type == TMPFS_TYPE_FILE)
  265. {
  266. d->d_type = DT_REG;
  267. }
  268. if (n_file->type == TMPFS_TYPE_DIR)
  269. {
  270. d->d_type = DT_DIR;
  271. }
  272. d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
  273. rt_strncpy(d->d_name, n_file->name, DIRENT_NAME_MAX);
  274. d->d_namlen = rt_strlen(d->d_name);
  275. count += 1;
  276. file->fpos += 1;
  277. }
  278. index += 1;
  279. if (index >= end)
  280. {
  281. break;
  282. }
  283. }
  284. }
  285. return count * sizeof(struct dirent);
  286. }
  287. static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target, const char *linkpath)
  288. {
  289. int ret = RT_EOK;
  290. struct devtmpfs_file *p_file, *l_file;
  291. struct devtmpfs_sb *superblock;
  292. RT_ASSERT(parent_dentry);
  293. RT_ASSERT(parent_dentry->mnt);
  294. superblock = (struct devtmpfs_sb *)parent_dentry->mnt->data;
  295. RT_ASSERT(superblock);
  296. p_file = devtmpfs_file_lookup(superblock, parent_dentry->pathname);
  297. if (p_file)
  298. {
  299. l_file = (struct devtmpfs_file *)rt_calloc(1, sizeof(struct devtmpfs_file));
  300. if (l_file)
  301. {
  302. superblock->df_size += sizeof(struct devtmpfs_file);
  303. strncpy(l_file->name, linkpath, DIRENT_NAME_MAX - 1);
  304. dfs_vfs_init_node(&l_file->node);
  305. l_file->sb = superblock;
  306. l_file->type = TMPFS_TYPE_FILE;
  307. l_file->mode = p_file->mode;
  308. l_file->mode &= ~S_IFMT;
  309. l_file->mode |= S_IFLNK;
  310. l_file->link = rt_strdup(target);
  311. rt_spin_lock(&superblock->lock);
  312. dfs_vfs_append_node(&p_file->node, &l_file->node);
  313. rt_spin_unlock(&superblock->lock);
  314. }
  315. }
  316. return ret;
  317. }
  318. static int devtmpfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
  319. {
  320. int ret = 0;
  321. struct devtmpfs_file *d_file;
  322. struct devtmpfs_sb *superblock;
  323. RT_ASSERT(dentry);
  324. RT_ASSERT(dentry->mnt);
  325. superblock = (struct devtmpfs_sb *)dentry->mnt->data;
  326. RT_ASSERT(superblock);
  327. d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
  328. if (d_file)
  329. {
  330. if (d_file->link)
  331. {
  332. if (d_file->type == TMPFS_TYPE_DYN_DEV)
  333. {
  334. rt_device_t device = (void *)d_file->link;
  335. buf[0] = '\0';
  336. ret = device->readlink(device, buf, len);
  337. if (ret == 0)
  338. {
  339. buf[len - 1] = '\0';
  340. ret = rt_strlen(buf);
  341. }
  342. else
  343. {
  344. ret = 0;
  345. }
  346. }
  347. else
  348. {
  349. rt_strncpy(buf, (const char *)d_file->link, len);
  350. buf[len - 1] = '\0';
  351. ret = rt_strlen(buf);
  352. }
  353. }
  354. }
  355. return ret;
  356. }
  357. static int devtmpfs_unlink(struct dfs_dentry *dentry)
  358. {
  359. struct devtmpfs_file *d_file;
  360. struct devtmpfs_sb *superblock;
  361. RT_ASSERT(dentry);
  362. RT_ASSERT(dentry->mnt);
  363. superblock = (struct devtmpfs_sb *)dentry->mnt->data;
  364. RT_ASSERT(superblock);
  365. d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
  366. if (d_file)
  367. {
  368. if (d_file->link && d_file->type != TMPFS_TYPE_DYN_DEV)
  369. {
  370. rt_free(d_file->link);
  371. }
  372. rt_spin_lock(&superblock->lock);
  373. dfs_vfs_remove_node(&d_file->node);
  374. rt_spin_unlock(&superblock->lock);
  375. rt_free(d_file);
  376. }
  377. return RT_EOK;
  378. }
  379. static int devtmpfs_setattr(struct dfs_dentry *dentry, struct dfs_attr *attr)
  380. {
  381. struct devtmpfs_file *d_file;
  382. struct devtmpfs_sb *superblock;
  383. RT_ASSERT(dentry);
  384. RT_ASSERT(dentry->mnt);
  385. superblock = (struct devtmpfs_sb *)dentry->mnt->data;
  386. RT_ASSERT(superblock);
  387. d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
  388. if (d_file)
  389. {
  390. d_file->mode &= ~0xFFF;
  391. d_file->mode |= attr->st_mode & 0xFFF;
  392. return RT_EOK;
  393. }
  394. return -RT_ERROR;
  395. }
  396. static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
  397. {
  398. struct dfs_vnode *vnode = RT_NULL;
  399. struct devtmpfs_sb *superblock;
  400. struct devtmpfs_file *d_file, *p_file;
  401. char parent_path[DFS_PATH_MAX], file_name[DIRENT_NAME_MAX];
  402. if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
  403. {
  404. return NULL;
  405. }
  406. superblock = (struct devtmpfs_sb *)dentry->mnt->data;
  407. RT_ASSERT(superblock != NULL);
  408. vnode = dfs_vnode_create();
  409. if (vnode)
  410. {
  411. /* find parent file */
  412. _path_separate(dentry->pathname, parent_path, file_name);
  413. if (file_name[0] == '\0') /* it's root dir */
  414. {
  415. dfs_vnode_destroy(vnode);
  416. return NULL;
  417. }
  418. /* open parent directory */
  419. p_file = devtmpfs_file_lookup(superblock, parent_path);
  420. if (p_file == NULL)
  421. {
  422. dfs_vnode_destroy(vnode);
  423. return NULL;
  424. }
  425. /* create a file entry */
  426. d_file = (struct devtmpfs_file *)rt_calloc(1, sizeof(struct devtmpfs_file));
  427. if (d_file == NULL)
  428. {
  429. dfs_vnode_destroy(vnode);
  430. return NULL;
  431. }
  432. superblock->df_size += sizeof(struct devtmpfs_file);
  433. strncpy(d_file->name, file_name, DIRENT_NAME_MAX);
  434. dfs_vfs_init_node(&d_file->node);
  435. d_file->sb = superblock;
  436. vnode->nlink = 1;
  437. vnode->size = 0;
  438. vnode->mode = mode;
  439. vnode->mnt = dentry->mnt;
  440. vnode->fops = &_default_fops;
  441. if (type == FT_DIRECTORY)
  442. {
  443. d_file->type = TMPFS_TYPE_DIR;
  444. vnode->type = FT_DIRECTORY;
  445. vnode->mode &= ~S_IFMT;
  446. vnode->mode |= S_IFDIR;
  447. }
  448. else
  449. {
  450. d_file->type = TMPFS_TYPE_FILE;
  451. vnode->type = FT_DEVICE;
  452. }
  453. d_file->mode = vnode->mode;
  454. rt_spin_lock(&superblock->lock);
  455. dfs_vfs_append_node(&p_file->node, &d_file->node);
  456. rt_spin_unlock(&superblock->lock);
  457. }
  458. return vnode;
  459. }
  460. static struct dfs_vnode *devtmpfs_lookup(struct dfs_dentry *dentry)
  461. {
  462. struct dfs_vnode *vnode = RT_NULL;
  463. struct devtmpfs_sb *superblock;
  464. struct devtmpfs_file *d_file;
  465. if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
  466. {
  467. return NULL;
  468. }
  469. superblock = (struct devtmpfs_sb *)dentry->mnt->data;
  470. d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
  471. if (d_file)
  472. {
  473. vnode = dfs_vnode_create();
  474. if (vnode)
  475. {
  476. vnode->nlink = 1;
  477. vnode->size = 0;
  478. vnode->mnt = dentry->mnt;
  479. vnode->fops = &_default_fops;
  480. vnode->mode = d_file->mode;
  481. if (d_file->type == TMPFS_TYPE_DIR)
  482. {
  483. vnode->type = FT_DIRECTORY;
  484. }
  485. else if (d_file->link)
  486. {
  487. vnode->type = FT_SYMLINK;
  488. }
  489. else
  490. {
  491. vnode->type = FT_DEVICE;
  492. }
  493. }
  494. }
  495. else
  496. {
  497. rt_device_t device = RT_NULL;
  498. device = rt_device_find(&dentry->pathname[1]);
  499. if (device)
  500. {
  501. vnode = devtmpfs_create_vnode(dentry, FT_REGULAR, dfs_devfs_device_to_mode(device));
  502. if (device->flag & RT_DEVICE_FLAG_DYNAMIC)
  503. {
  504. d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
  505. d_file->type = TMPFS_TYPE_DYN_DEV;
  506. d_file->link = (char *)device;
  507. }
  508. }
  509. }
  510. return vnode;
  511. }
  512. static int devtmpfs_free_vnode(struct dfs_vnode *vnode)
  513. {
  514. return RT_EOK;
  515. }
  516. static const struct dfs_filesystem_ops _devtmpfs_ops =
  517. {
  518. .name = "devtmpfs",
  519. .flags = DFS_FS_FLAG_DEFAULT,
  520. .default_fops = &_default_fops,
  521. .mount = devtmpfs_mount,
  522. .umount = devtmpfs_unmount,
  523. .symlink = devtmpfs_symlink,
  524. .readlink = devtmpfs_readlink,
  525. .unlink = devtmpfs_unlink,
  526. .setattr = devtmpfs_setattr,
  527. .statfs = devtmpfs_statfs,
  528. .stat = devtmpfs_stat,
  529. .lookup = devtmpfs_lookup,
  530. .create_vnode = devtmpfs_create_vnode,
  531. .free_vnode = devtmpfs_free_vnode
  532. };
  533. static struct dfs_filesystem_type _devtmpfs =
  534. {
  535. .fs_ops = &_devtmpfs_ops,
  536. };
  537. int dfs_devtmpfs_init(void)
  538. {
  539. _default_fops = *dfs_devfs_fops();
  540. _default_fops.getdents = devtmpfs_getdents;
  541. /* register file system */
  542. dfs_register(&_devtmpfs);
  543. dfs_mount(RT_NULL, "/dev", "devtmpfs", 0, RT_NULL);
  544. dfs_devfs_update();
  545. return 0;
  546. }
  547. INIT_COMPONENT_EXPORT(dfs_devtmpfs_init);