dfs_ext.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2017-11-11 parai@foxmail.com base porting
  9. * 2018-06-02 parai@foxmail.com fix mkfs issues
  10. * 2020-08-19 lizhirui porting to ls2k
  11. * 2021-07-09 linzhenxing modify for art pi smart
  12. * 2023-01-15 bernard add RT-Thread 5.0.x support
  13. */
  14. #include <string.h>
  15. #include <rtthread.h>
  16. #include <dfs.h>
  17. #include <dfs_fs.h>
  18. #include <dfs_file.h>
  19. #include <dfs_mnt.h>
  20. #include <dfs_dentry.h>
  21. #include "ext4.h"
  22. #include "ext4_mkfs.h"
  23. #include "ext4_config.h"
  24. #include "ext4_blockdev.h"
  25. #include "ext4_errno.h"
  26. #include "ext4_mbr.h"
  27. #include "ext4_super.h"
  28. #include "ext4_fs.h"
  29. #include <ext4_mp.h>
  30. #include "dfs_ext.h"
  31. #include "dfs_ext_blockdev.h"
  32. #ifdef RT_USING_PAGECACHE
  33. #include "dfs_pcache.h"
  34. #endif
  35. #ifdef PKG_USING_DLOG
  36. #include <dlog.h>
  37. #else
  38. #define DLOG(...)
  39. #endif
  40. struct dfs_ext4_vnode
  41. {
  42. struct ext4_mountpoint *mp;
  43. struct ext4_inode_ref inode_ref;
  44. };
  45. struct dfs_ext4_file
  46. {
  47. uint32_t type; /* EXT4_DE_DIR or EXT4_DE_REG_FILE */
  48. union
  49. {
  50. ext4_file file;
  51. ext4_dir dir;
  52. } entry;
  53. struct dfs_ext4_vnode vnode;
  54. };
  55. static rt_mutex_t ext4_mutex = RT_NULL;
  56. static void ext4_lock(void);
  57. static void ext4_unlock(void);
  58. static struct ext4_lock ext4_lock_ops =
  59. {
  60. ext4_lock,
  61. ext4_unlock
  62. };
  63. static void ext4_lock(void)
  64. {
  65. rt_err_t result = -RT_EBUSY;
  66. while (result == -RT_EBUSY)
  67. {
  68. result = rt_mutex_take(ext4_mutex, RT_WAITING_FOREVER);
  69. }
  70. if (result != RT_EOK)
  71. {
  72. RT_ASSERT(0);
  73. }
  74. return;
  75. }
  76. static void ext4_unlock(void)
  77. {
  78. rt_mutex_release(ext4_mutex);
  79. return;
  80. }
  81. static off_t dfs_ext_lseek(struct dfs_file *file, off_t offset, int whence);
  82. #ifdef RT_USING_PAGECACHE
  83. static ssize_t dfs_ext_page_read(struct dfs_file *file, struct dfs_page *page);
  84. static ssize_t dfs_ext_page_write(struct dfs_page *page);
  85. static struct dfs_aspace_ops dfs_ext_aspace_ops =
  86. {
  87. .read = dfs_ext_page_read,
  88. .write = dfs_ext_page_write,
  89. };
  90. #endif
  91. /* update vnode information */
  92. rt_inline int ext4_vnode_update_info(struct dfs_vnode *vnode)
  93. {
  94. if (vnode && vnode->data)
  95. {
  96. struct dfs_ext4_file *ext_file = (struct dfs_ext4_file *)vnode->data;
  97. vnode->mode = ext4_inode_get_mode(&ext_file->vnode.mp->fs.sb, ext_file->vnode.inode_ref.inode);
  98. vnode->uid = ext4_inode_get_uid(ext_file->vnode.inode_ref.inode);
  99. vnode->gid = ext4_inode_get_gid(ext_file->vnode.inode_ref.inode);
  100. vnode->atime.tv_sec = ext4_inode_get_access_time(ext_file->vnode.inode_ref.inode);
  101. vnode->mtime.tv_sec = ext4_inode_get_modif_time(ext_file->vnode.inode_ref.inode);
  102. vnode->ctime.tv_sec = ext4_inode_get_change_inode_time(ext_file->vnode.inode_ref.inode);
  103. }
  104. return 0;
  105. }
  106. /* file system ops */
  107. static struct dfs_vnode *dfs_ext_lookup(struct dfs_dentry *dentry)
  108. {
  109. char *fn = RT_NULL;
  110. struct dfs_vnode *vnode = RT_NULL;
  111. struct dfs_ext4_file *ext_file = RT_NULL;
  112. ext_file = (struct dfs_ext4_file *)rt_calloc(1, sizeof(struct dfs_ext4_file));
  113. if (ext_file)
  114. {
  115. fn = dfs_dentry_full_path(dentry);
  116. if (fn)
  117. {
  118. DLOG(msg, "ext", "vnode", DLOG_MSG, "dfs_vnode_create()");
  119. vnode = dfs_vnode_create();
  120. if (vnode)
  121. {
  122. ext_file->vnode.mp = ext4_get_inode_ref(fn, &(ext_file->vnode.inode_ref));
  123. if (ext_file->vnode.mp)
  124. {
  125. /* found entry */
  126. int type = ext4_inode_type(&(ext_file->vnode.mp->fs.sb), ext_file->vnode.inode_ref.inode);
  127. switch (type)
  128. {
  129. case EXT4_INODE_MODE_FILE:
  130. vnode->type = FT_REGULAR;
  131. vnode->size = ext4_inode_get_size(&(ext_file->vnode.mp->fs.sb), ext_file->vnode.inode_ref.inode);
  132. #ifdef RT_USING_PAGECACHE
  133. vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_ext_aspace_ops);
  134. #endif
  135. break;
  136. case EXT4_INODE_MODE_DIRECTORY:
  137. vnode->type = FT_DIRECTORY;
  138. vnode->size = 0;
  139. break;
  140. case EXT4_INODE_MODE_SOFTLINK:
  141. vnode->type = FT_SYMLINK;
  142. vnode->size = 0;
  143. break;
  144. }
  145. vnode->nlink = 1;
  146. DLOG(msg, "ext", "mnt", DLOG_MSG, "dfs_mnt_ref(dentry->mnt, name=%s)", dentry->mnt->fs_ops->name);
  147. vnode->mnt = dentry->mnt;
  148. vnode->data = (void *)ext_file;
  149. ext_file->type = EXT4_DE_UNKNOWN;
  150. rt_mutex_init(&vnode->lock, dentry->pathname, RT_IPC_FLAG_PRIO);
  151. ext4_vnode_update_info(vnode);
  152. }
  153. else
  154. {
  155. /* free vnode */
  156. DLOG(msg, "ext", "vnode", DLOG_MSG, "dfs_vnode_destroy(no entry)");
  157. dfs_vnode_destroy(vnode);
  158. vnode = RT_NULL;
  159. }
  160. }
  161. rt_free(fn);
  162. }
  163. if (vnode == RT_NULL)
  164. {
  165. rt_free(ext_file);
  166. }
  167. }
  168. return vnode;
  169. }
  170. static struct dfs_vnode *dfs_ext_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
  171. {
  172. int ret = 0;
  173. char *fn = NULL;
  174. struct dfs_vnode *vnode = RT_NULL;
  175. struct dfs_ext4_file *ext_file = RT_NULL;
  176. int filetype = EXT4_DE_UNKNOWN;
  177. vnode = dfs_vnode_create();
  178. if (vnode)
  179. {
  180. fn = dfs_dentry_full_path(dentry);
  181. if (fn)
  182. {
  183. ext_file = (struct dfs_ext4_file *)rt_calloc(1, sizeof(struct dfs_ext4_file));
  184. if (ext_file)
  185. {
  186. if (type == FT_DIRECTORY)
  187. {
  188. /* create dir */
  189. ret = ext4_dir_mk(fn);
  190. if (ret == EOK)
  191. {
  192. ext4_mode_set(fn, mode);
  193. ext_file->vnode.mp = ext4_get_inode_ref(fn, &(ext_file->vnode.inode_ref));
  194. if (ext_file->vnode.mp)
  195. {
  196. vnode->type = FT_DIRECTORY;
  197. vnode->size = 0;
  198. }
  199. else
  200. {
  201. rt_kprintf("get inode ref failed: %s\n", fn);
  202. }
  203. }
  204. }
  205. else if (type == FT_REGULAR)
  206. {
  207. ext4_file file;
  208. /* create file */
  209. if (!(mode & S_IFMT) || S_ISREG(mode))
  210. {
  211. ret = ext4_fopen2(&file, fn, O_CREAT);
  212. if (ret == EOK)
  213. {
  214. ext4_fclose(&file);
  215. ext4_mode_set(fn, mode);
  216. ext_file->vnode.mp = ext4_get_inode_ref(fn, &(ext_file->vnode.inode_ref));
  217. if (ext_file->vnode.mp)
  218. {
  219. vnode->type = FT_REGULAR;
  220. vnode->size = ext4_inode_get_size(&(ext_file->vnode.mp->fs.sb), ext_file->vnode.inode_ref.inode);
  221. }
  222. #ifdef RT_USING_PAGECACHE
  223. vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_ext_aspace_ops);
  224. #endif
  225. }
  226. }
  227. else
  228. {
  229. if (S_ISLNK(mode))
  230. {
  231. filetype = EXT4_DE_SYMLINK;
  232. }
  233. else if (S_ISDIR(mode))
  234. {
  235. filetype = EXT4_DE_DIR;
  236. }
  237. else if (S_ISCHR(mode))
  238. {
  239. filetype = EXT4_DE_CHRDEV;
  240. }
  241. else if (S_ISBLK(mode))
  242. {
  243. filetype = EXT4_DE_BLKDEV;
  244. }
  245. else if (S_ISFIFO(mode))
  246. {
  247. filetype = EXT4_DE_FIFO;
  248. }
  249. else if (S_ISSOCK(mode))
  250. {
  251. filetype = EXT4_DE_SOCK;
  252. }
  253. ret = ext4_mknod(fn, filetype, 0);
  254. }
  255. }
  256. if (ret != EOK)
  257. {
  258. rt_free(ext_file);
  259. ext_file = NULL;
  260. dfs_vnode_destroy(vnode);
  261. vnode = NULL;
  262. }
  263. else
  264. {
  265. DLOG(msg, "ext", "mnt", DLOG_MSG, "dfs_mnt_ref(dentry->mnt, name=%s)", dentry->mnt->fs_ops->name);
  266. vnode->mnt = dentry->mnt;
  267. vnode->data = (void *)ext_file;
  268. vnode->mode = mode;
  269. ext_file->type = filetype;
  270. rt_mutex_init(&vnode->lock, dentry->pathname, RT_IPC_FLAG_PRIO);
  271. }
  272. }
  273. rt_free(fn);
  274. fn = NULL;
  275. }
  276. else
  277. {
  278. dfs_vnode_destroy(vnode);
  279. vnode = NULL;
  280. }
  281. }
  282. return vnode;
  283. }
  284. static int dfs_ext_free_vnode(struct dfs_vnode *vnode)
  285. {
  286. if (vnode)
  287. {
  288. struct dfs_ext4_file *ext_file = (struct dfs_ext4_file *)vnode->data;
  289. if (ext_file)
  290. {
  291. if (ext_file->vnode.mp)
  292. {
  293. ext4_put_inode_ref(ext_file->vnode.mp, &(ext_file->vnode.inode_ref));
  294. }
  295. rt_mutex_detach(&vnode->lock);
  296. rt_free(ext_file);
  297. vnode->data = RT_NULL;
  298. }
  299. }
  300. return RT_EOK;
  301. }
  302. static int dfs_ext_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
  303. {
  304. int rc = 0;
  305. struct ext4_blockdev *bd = NULL;
  306. struct dfs_ext4_blockdev *dbd = NULL;
  307. /* create dfs ext4 block device */
  308. dbd = dfs_ext4_blockdev_create(mnt->dev_id);
  309. if (!dbd) return RT_NULL;
  310. bd = &dbd->bd;
  311. rc = ext4_mount(bd, mnt->fullpath, false);
  312. if (rc != EOK)
  313. {
  314. dfs_ext4_blockdev_destroy(dbd);
  315. rc = -rc;
  316. }
  317. else
  318. {
  319. ext4_mount_setup_locks(mnt->fullpath, &ext4_lock_ops);
  320. /* set file system data to dbd */
  321. dbd->data = bd->journal;
  322. bd->journal = 0;
  323. mnt->data = (void *)dbd;
  324. }
  325. return rc;
  326. }
  327. static int dfs_ext_unmount(struct dfs_mnt *mnt)
  328. {
  329. int rc = EPERM;
  330. struct dfs_ext4_blockdev *dbd = NULL;
  331. dbd = (struct dfs_ext4_blockdev *)mnt->data;
  332. if (dbd)
  333. {
  334. rc = ext4_umount_mp(dbd->data);
  335. if (rc == 0)
  336. {
  337. dfs_ext4_blockdev_destroy(dbd);
  338. mnt->data = NULL;
  339. }
  340. }
  341. return rc;
  342. }
  343. static int dfs_ext_mkfs(rt_device_t devid, const char *fs_name)
  344. {
  345. int rc;
  346. static struct ext4_fs fs;
  347. static struct ext4_mkfs_info info =
  348. {
  349. .block_size = 4096,
  350. .journal = true,
  351. };
  352. struct ext4_blockdev *bd = NULL;
  353. struct dfs_ext4_blockdev *dbd = NULL;
  354. if (devid == RT_NULL)
  355. {
  356. return -RT_EINVAL;
  357. }
  358. /* create dfs ext4 block device */
  359. dbd = dfs_ext4_blockdev_create(devid);
  360. if (!dbd) return -RT_ERROR;
  361. /* get ext4 block device */
  362. bd = &dbd->bd;
  363. /* try to open device */
  364. rt_device_open(devid, RT_DEVICE_OFLAG_RDWR);
  365. rc = ext4_mkfs(&fs, bd, &info, F_SET_EXT4);
  366. /* no matter what, unregister */
  367. dfs_ext4_blockdev_destroy(dbd);
  368. /* close device */
  369. rt_device_close(devid);
  370. rc = -rc;
  371. return rc;
  372. }
  373. static int dfs_ext_statfs(struct dfs_mnt *mnt, struct statfs *buf)
  374. {
  375. struct ext4_sblock *sb = NULL;
  376. int error = RT_EOK;
  377. if (mnt)
  378. {
  379. error = ext4_get_sblock(mnt->fullpath, &sb);
  380. if (error != RT_EOK)
  381. {
  382. return -error;
  383. }
  384. buf->f_bsize = ext4_sb_get_block_size(sb);
  385. buf->f_blocks = ext4_sb_get_blocks_cnt(sb);
  386. buf->f_bfree = ext4_sb_get_free_blocks_cnt(sb);
  387. //TODO this is not accurate, because it is free blocks available to unprivileged user, but ...
  388. buf->f_bavail = buf->f_bfree;
  389. }
  390. return error;
  391. }
  392. /* file ops */
  393. static ssize_t dfs_ext_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
  394. {
  395. int r;
  396. size_t bytesread = 0;
  397. struct dfs_ext4_file *ext_file;
  398. if (file && file->data && file->vnode->size > *pos)
  399. {
  400. ext_file = (struct dfs_ext4_file *)file->data;
  401. if (ext_file->vnode.mp)
  402. {
  403. rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
  404. dfs_ext_lseek(file, *pos, SEEK_SET);
  405. r = ext4_fread(&ext_file->entry.file, buf, count, &bytesread);
  406. if (r != 0)
  407. {
  408. bytesread = 0;
  409. }
  410. *pos = ext_file->entry.file.fpos;
  411. rt_mutex_release(&file->vnode->lock);
  412. }
  413. }
  414. return bytesread;
  415. }
  416. static ssize_t dfs_ext_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
  417. {
  418. int r;
  419. size_t byteswritten = 0;
  420. struct dfs_ext4_file *ext_file;
  421. if (file && file->data)
  422. {
  423. ext_file = (struct dfs_ext4_file *)file->data;
  424. if (ext_file->vnode.mp)
  425. {
  426. rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
  427. dfs_ext_lseek(file, *pos, SEEK_SET);
  428. r = ext4_fwrite(&(ext_file->entry.file), buf, count, &byteswritten);
  429. if (r != 0)
  430. {
  431. byteswritten = 0;
  432. }
  433. file->vnode->size = ext4_fsize(&(ext_file->entry.file));
  434. *pos = ext_file->entry.file.fpos;
  435. rt_mutex_release(&file->vnode->lock);
  436. }
  437. }
  438. return byteswritten;
  439. }
  440. static int dfs_ext_flush(struct dfs_file *file)
  441. {
  442. char *fn = RT_NULL;
  443. int error = RT_EOK;
  444. if (file && file->dentry)
  445. {
  446. fn = dfs_dentry_full_path(file->dentry);
  447. if (fn)
  448. {
  449. error = ext4_cache_flush(fn);
  450. rt_free(fn);
  451. }
  452. }
  453. if (error != RT_EOK)
  454. {
  455. error = -error;
  456. }
  457. return error;
  458. }
  459. static off_t dfs_ext_lseek(struct dfs_file *file, off_t offset, int whence)
  460. {
  461. off_t ret = -EPERM;
  462. struct dfs_ext4_file *ext_file;
  463. if (file && file->data)
  464. {
  465. ext_file = (struct dfs_ext4_file *)file->data;
  466. rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
  467. if (ext_file->type == EXT4_DE_DIR)
  468. {
  469. if (offset == 0)
  470. {
  471. ext4_dir_entry_rewind(&(ext_file->entry.dir));
  472. ret = 0;
  473. }
  474. }
  475. else if (ext_file->type == EXT4_DE_REG_FILE)
  476. {
  477. ret = generic_dfs_lseek(file, offset, whence);
  478. if (ret >= 0)
  479. {
  480. ext_file->entry.file.fpos = ret;
  481. }
  482. }
  483. rt_mutex_release(&file->vnode->lock);
  484. }
  485. return ret;
  486. }
  487. static int dfs_ext_close(struct dfs_file *file)
  488. {
  489. int ret = 0;
  490. struct dfs_ext4_file *ext_file = RT_NULL;
  491. if (file)
  492. {
  493. RT_ASSERT(file->vnode->ref_count > 0);
  494. if (file->vnode->ref_count > 1)
  495. {
  496. return ret;
  497. }
  498. ext_file = (struct dfs_ext4_file *)file->data;
  499. if (ext_file)
  500. {
  501. if (ext_file->type == EXT4_DE_DIR)
  502. {
  503. ret = ext4_dir_close(&ext_file->entry.dir);
  504. }
  505. else if (ext_file->type == EXT4_DE_REG_FILE)
  506. {
  507. ret = ext4_fclose(&ext_file->entry.file);
  508. }
  509. if (ret == EOK)
  510. {
  511. ext_file->type = EXT4_DE_UNKNOWN;
  512. file->data = NULL;
  513. }
  514. }
  515. }
  516. return -ret;
  517. }
  518. static int dfs_ext_open(struct dfs_file *file)
  519. {
  520. int ret = EOK;
  521. struct dfs_ext4_file *ext_file = RT_NULL;
  522. if (file && file->vnode)
  523. {
  524. ext_file = (struct dfs_ext4_file *)file->vnode->data;
  525. RT_ASSERT(file->vnode->ref_count > 0);
  526. if (ext_file && ext_file->type != EXT4_DE_UNKNOWN)
  527. {
  528. if (file->vnode->type == FT_DIRECTORY
  529. && !(file->flags & O_DIRECTORY))
  530. {
  531. return -ENOENT;
  532. }
  533. if (file->vnode->type == FT_DIRECTORY)
  534. {
  535. file->data = rt_calloc(1, sizeof(struct dfs_ext4_file));
  536. rt_memcpy(file->data, ext_file, sizeof(struct dfs_ext4_file));
  537. ext_file = (struct dfs_ext4_file *)file->data;
  538. ext_file->entry.dir.next_off = 0;
  539. }
  540. else
  541. {
  542. file->data = ext_file;
  543. }
  544. file->fpos = 0;
  545. return ret;
  546. }
  547. if (ext_file)
  548. {
  549. char *fn = NULL;
  550. fn = dfs_dentry_full_path(file->dentry);
  551. if (fn)
  552. {
  553. if (file->vnode->type == FT_DIRECTORY)
  554. {
  555. /* open dir */
  556. ret = ext4_dir_open(&ext_file->entry.dir, fn);
  557. if (ret == EOK)
  558. {
  559. ext_file->type = EXT4_DE_DIR;
  560. file->fpos = 0;
  561. }
  562. }
  563. else
  564. {
  565. /* open regular file */
  566. ret = ext4_fopen2(&ext_file->entry.file, fn, file->flags);
  567. if (ret == EOK)
  568. {
  569. ext_file->type = EXT4_DE_REG_FILE;
  570. if (file->flags & O_TRUNC)
  571. {
  572. file->vnode->size = 0;
  573. }
  574. file->fpos = ext_file->entry.file.fpos;
  575. }
  576. }
  577. if (ret == EOK)
  578. {
  579. file->data = ext_file;
  580. }
  581. rt_free(fn);
  582. }
  583. }
  584. }
  585. else
  586. {
  587. ret = ENOENT;
  588. }
  589. return -ret;
  590. }
  591. static int dfs_ext_readlink(struct dfs_dentry *dentry, char *buf, int len)
  592. {
  593. int ret = EOK;
  594. char *fn = NULL;
  595. if (dentry && buf)
  596. {
  597. fn = dfs_dentry_full_path(dentry);
  598. if (fn)
  599. {
  600. size_t size;
  601. ret = ext4_readlink(fn, buf, len, &size);
  602. rt_free(fn);
  603. if (ret == EOK)
  604. {
  605. buf[size] = '\0';
  606. return size;
  607. }
  608. }
  609. else
  610. {
  611. ret = ENOMEM;
  612. }
  613. }
  614. else
  615. {
  616. ret = EBADF;
  617. }
  618. return -ret;
  619. }
  620. static int dfs_ext_link(struct dfs_dentry *src_dentry, struct dfs_dentry *dst_dentry)
  621. {
  622. char *src_path = NULL, *dst_path = NULL;
  623. src_path = dfs_dentry_full_path(src_dentry);
  624. dst_path = dfs_dentry_full_path(dst_dentry);
  625. if (src_path && dst_path)
  626. {
  627. ext4_flink(src_path, dst_path);
  628. rt_free(src_path);
  629. rt_free(dst_path);
  630. }
  631. return EOK;
  632. }
  633. static int dfs_ext_symlink(struct dfs_dentry *parent_dentry, const char *target, const char *linkpath)
  634. {
  635. int ret = EOK;
  636. char *fn = NULL;
  637. if (parent_dentry && linkpath[0] != '/')
  638. {
  639. char *full = dfs_dentry_full_path(parent_dentry);
  640. if (full)
  641. {
  642. fn = dfs_normalize_path(full, linkpath);
  643. rt_free(full);
  644. }
  645. }
  646. else
  647. {
  648. fn = (char *)linkpath;
  649. }
  650. if (fn)
  651. {
  652. ret = ext4_fsymlink(target, fn);
  653. if (fn != linkpath)
  654. rt_free(fn);
  655. }
  656. else
  657. {
  658. ret = ENOMEM;
  659. }
  660. return -ret;
  661. }
  662. static int dfs_ext_unlink(struct dfs_dentry *dentry)
  663. {
  664. int ret = EPERM;
  665. char *fn = NULL;
  666. struct dfs_ext4_file file;
  667. fn = dfs_dentry_full_path(dentry);
  668. if (fn)
  669. {
  670. ret = ext4_dir_open(&(file.entry.dir), fn);
  671. if (ret == 0)
  672. {
  673. ext4_dir_close(&(file.entry.dir));
  674. ret = ext4_dir_rm(fn);
  675. }
  676. else
  677. {
  678. ret = ext4_fremove(fn);
  679. }
  680. rt_free(fn);
  681. }
  682. return -ret;
  683. }
  684. static int dfs_ext_stat(struct dfs_dentry *dentry, struct stat *st)
  685. {
  686. int ret = 0;
  687. char *stat_path;
  688. stat_path = dfs_dentry_full_path(dentry);
  689. if (stat_path)
  690. {
  691. struct ext4_inode_ref inode_ref;
  692. struct ext4_mountpoint *mp = ext4_get_inode_ref(stat_path, &inode_ref);
  693. if (mp)
  694. {
  695. st->st_mode = ext4_inode_get_mode(&mp->fs.sb, inode_ref.inode);
  696. st->st_uid = ext4_inode_get_uid(inode_ref.inode);
  697. st->st_gid = ext4_inode_get_gid(inode_ref.inode);
  698. if (S_ISDIR(st->st_mode))
  699. {
  700. st->st_size = ext4_inode_get_size(&mp->fs.sb, inode_ref.inode);
  701. }
  702. else
  703. {
  704. #ifdef RT_USING_PAGECACHE
  705. st->st_size = (dentry->vnode && dentry->vnode->aspace) ? dentry->vnode->size : ext4_inode_get_size(&mp->fs.sb, inode_ref.inode);
  706. #else
  707. st->st_size = ext4_inode_get_size(&mp->fs.sb, inode_ref.inode);
  708. #endif
  709. }
  710. st->st_atime = ext4_inode_get_access_time(inode_ref.inode);
  711. st->st_mtime = ext4_inode_get_modif_time(inode_ref.inode);
  712. st->st_ctime = ext4_inode_get_change_inode_time(inode_ref.inode);
  713. st->st_dev = (dev_t)(dentry->mnt->dev_id);
  714. st->st_ino = inode_ref.index;
  715. st->st_blksize = ext4_sb_get_block_size(&mp->fs.sb);
  716. // man say st_blocks is number of 512B blocks allocated
  717. st->st_blocks = RT_ALIGN(st->st_size, st->st_blksize) / 512;
  718. ext4_put_inode_ref(mp, &inode_ref);
  719. }
  720. else
  721. {
  722. ret = ENOENT;
  723. }
  724. rt_free(stat_path);
  725. }
  726. return -ret;
  727. }
  728. int dfs_ext_setattr(struct dfs_dentry *dentry, struct dfs_attr *attr)
  729. {
  730. int ret = 0;
  731. char *fn = NULL;
  732. fn = dfs_dentry_full_path(dentry);
  733. if (fn)
  734. {
  735. if (attr->ia_valid & ATTR_MODE_SET)
  736. {
  737. ret = ext4_mode_set(fn, attr->st_mode);
  738. }
  739. if (attr->ia_valid & ATTR_ATIME_SET)
  740. {
  741. ret = ext4_atime_set(fn, attr->ia_atime.tv_sec);
  742. }
  743. if (attr->ia_valid & ATTR_MTIME_SET)
  744. {
  745. ret = ext4_mtime_set(fn, attr->ia_mtime.tv_sec);
  746. }
  747. if (attr->ia_valid & ATTR_UID_SET)
  748. {
  749. uint32_t unuse = 0, gid = 0;
  750. ext4_owner_get(fn, &unuse, &gid);
  751. ret = ext4_owner_set(fn, attr->st_uid, gid);
  752. }
  753. if (attr->ia_valid & ATTR_GID_SET)
  754. {
  755. uint32_t unuse = 0, uid = 0;
  756. ext4_owner_get(fn, &uid, &unuse);
  757. ret = ext4_owner_set(fn, uid, attr->st_gid);
  758. }
  759. ext4_vnode_update_info(dentry->vnode);
  760. rt_free(fn);
  761. }
  762. else
  763. {
  764. ret = ENOENT;
  765. }
  766. return ret;
  767. }
  768. static int dfs_ext_getdents(struct dfs_file *file, struct dirent *dirp, rt_uint32_t count)
  769. {
  770. int index;
  771. struct dirent *d;
  772. struct dfs_ext4_file *ext_file;
  773. const ext4_direntry *rentry;
  774. /* make integer count */
  775. count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
  776. if (count == 0 || file->data == RT_NULL)
  777. {
  778. return -RT_EINVAL;
  779. }
  780. index = 0;
  781. ext_file = (struct dfs_ext4_file *)file->data;
  782. while (1)
  783. {
  784. d = dirp + index;
  785. rentry = ext4_dir_entry_next(&(ext_file->entry.dir));
  786. if (rentry != NULL)
  787. {
  788. strncpy(d->d_name, (char *)rentry->name, DIRENT_NAME_MAX);
  789. if (rentry->inode_type == EXT4_DE_DIR)
  790. {
  791. d->d_type = DT_DIR;
  792. }
  793. else if (rentry->inode_type == EXT4_DE_SYMLINK)
  794. {
  795. d->d_type = DT_SYMLINK;
  796. }
  797. else
  798. {
  799. d->d_type = DT_REG;
  800. }
  801. d->d_namlen = (rt_uint8_t)rentry->name_length;
  802. d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
  803. index ++;
  804. if (index * sizeof(struct dirent) >= count)
  805. break;
  806. }
  807. else
  808. {
  809. break;
  810. }
  811. }
  812. file->fpos += index * sizeof(struct dirent);
  813. return index * sizeof(struct dirent);
  814. }
  815. static int dfs_ext_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *new_dentry)
  816. {
  817. int r = EPERM;
  818. char *oldpath, *newpath;
  819. oldpath = dfs_dentry_full_path(old_dentry);
  820. newpath = dfs_dentry_full_path(new_dentry);
  821. if (oldpath && newpath)
  822. {
  823. r = ext4_frename(oldpath, newpath);
  824. }
  825. rt_free(oldpath);
  826. rt_free(newpath);
  827. return -r;
  828. }
  829. static int dfs_ext_truncate(struct dfs_file *file, off_t offset)
  830. {
  831. struct dfs_ext4_file *ext_file = (struct dfs_ext4_file *)file->data;
  832. if (ext_file)
  833. {
  834. ext4_ftruncate(&(ext_file->entry.file), offset);
  835. }
  836. if (file->vnode->size < offset)
  837. {
  838. file->vnode->size = offset;
  839. }
  840. return 0;
  841. }
  842. static int dfs_ext_ioctl(struct dfs_file *file, int cmd, void *args)
  843. {
  844. int ret = RT_EOK;
  845. switch (cmd)
  846. {
  847. case RT_FIOFTRUNCATE:
  848. {
  849. off_t offset = (off_t)(size_t)(args);
  850. ret = dfs_ext_truncate(file, offset);
  851. }
  852. break;
  853. case F_GETLK:
  854. case F_SETLK:
  855. ret = RT_EOK;
  856. break;
  857. default:
  858. ret = -RT_EIO;
  859. break;
  860. }
  861. return ret;
  862. }
  863. #ifdef RT_USING_PAGECACHE
  864. static ssize_t dfs_ext_page_read(struct dfs_file *file, struct dfs_page *page)
  865. {
  866. ssize_t ret = -EINVAL;
  867. if (page->page)
  868. {
  869. uint32_t flags;
  870. off_t fpos = page->fpos;
  871. if (file && file->data)
  872. {
  873. struct dfs_ext4_file *ext_file = (struct dfs_ext4_file *)file->data;
  874. rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
  875. flags = ext_file->entry.file.flags;
  876. ext_file->entry.file.flags = O_RDWR;
  877. ret = dfs_ext_read(file, page->page, page->size, &fpos);
  878. ext_file->entry.file.flags = flags;
  879. rt_mutex_release(&file->vnode->lock);
  880. }
  881. }
  882. return ret;
  883. }
  884. static ssize_t dfs_ext_page_write(struct dfs_page *page)
  885. {
  886. int r;
  887. size_t byteswritten = 0;
  888. struct dfs_ext4_file *ext_file;
  889. if (page && page->aspace->vnode && page->aspace->vnode->data)
  890. {
  891. ext_file = (struct dfs_ext4_file *)page->aspace->vnode->data;
  892. rt_mutex_take(&page->aspace->vnode->lock, RT_WAITING_FOREVER);
  893. ext4_fseek(&(ext_file->entry.file), (int64_t)page->fpos, SEEK_SET);
  894. r = ext4_fwrite(&(ext_file->entry.file), page->page, page->len, &byteswritten);
  895. if (r != 0)
  896. {
  897. byteswritten = 0;
  898. }
  899. rt_mutex_release(&page->aspace->vnode->lock);
  900. }
  901. return byteswritten;
  902. }
  903. #endif
  904. static const struct dfs_file_ops _extfs_fops =
  905. {
  906. .open = dfs_ext_open,
  907. .close = dfs_ext_close,
  908. .ioctl = dfs_ext_ioctl,
  909. .read = dfs_ext_read,
  910. .write = dfs_ext_write,
  911. .flush = dfs_ext_flush,
  912. .lseek = dfs_ext_lseek,
  913. .truncate = dfs_ext_truncate,
  914. .getdents = dfs_ext_getdents,
  915. };
  916. static const struct dfs_filesystem_ops _extfs_ops =
  917. {
  918. .name = "ext",
  919. .flags = FS_NEED_DEVICE,
  920. .default_fops = &_extfs_fops,
  921. .mount = dfs_ext_mount,
  922. .umount = dfs_ext_unmount,
  923. .mkfs = dfs_ext_mkfs,
  924. .statfs = dfs_ext_statfs, /* statfs */
  925. .readlink = dfs_ext_readlink,
  926. .link = dfs_ext_link,
  927. .unlink = dfs_ext_unlink,
  928. .symlink = dfs_ext_symlink,
  929. .stat = dfs_ext_stat,
  930. .setattr = dfs_ext_setattr,
  931. .rename = dfs_ext_rename,
  932. .lookup = dfs_ext_lookup,
  933. .create_vnode = dfs_ext_create_vnode,
  934. .free_vnode = dfs_ext_free_vnode,
  935. };
  936. static struct dfs_filesystem_type _extfs =
  937. {
  938. .fs_ops = &_extfs_ops,
  939. };
  940. int dfs_ext_init(void)
  941. {
  942. if (ext4_mutex == RT_NULL)
  943. {
  944. ext4_mutex = rt_mutex_create("lwext4", RT_IPC_FLAG_FIFO);
  945. if (ext4_mutex == RT_NULL)
  946. {
  947. ext4_dbg(DEBUG_DFS_EXT, "create lwext mutex failed.\n");
  948. return -1;
  949. }
  950. }
  951. /* register rom file system */
  952. dfs_register(&_extfs);
  953. return 0;
  954. }
  955. INIT_COMPONENT_EXPORT(dfs_ext_init);