dfs_fs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  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. * 2005-02-22 Bernard The first version.
  9. * 2010-06-30 Bernard Optimize for RT-Thread RTOS
  10. * 2011-03-12 Bernard fix the filesystem lookup issue.
  11. * 2017-11-30 Bernard fix the filesystem_operation_table issue.
  12. * 2017-12-05 Bernard fix the fs type search issue in mkfs.
  13. */
  14. #include <dfs_fs.h>
  15. #include <dfs_file.h>
  16. #include "dfs_private.h"
  17. /**
  18. * @addtogroup FsApi
  19. */
  20. /*@{*/
  21. /**
  22. * this function will register a file system instance to device file system.
  23. *
  24. * @param ops the file system instance to be registered.
  25. *
  26. * @return 0 on successful, -1 on failed.
  27. */
  28. int dfs_register(const struct dfs_filesystem_ops *ops)
  29. {
  30. int ret = RT_EOK;
  31. const struct dfs_filesystem_ops **empty = NULL;
  32. const struct dfs_filesystem_ops **iter;
  33. /* lock filesystem */
  34. dfs_lock();
  35. /* check if this filesystem was already registered */
  36. for (iter = &filesystem_operation_table[0];
  37. iter < &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; iter ++)
  38. {
  39. /* find out an empty filesystem type entry */
  40. if (*iter == NULL)
  41. (empty == NULL) ? (empty = iter) : 0;
  42. else if (strcmp((*iter)->name, ops->name) == 0)
  43. {
  44. rt_set_errno(-EEXIST);
  45. ret = -1;
  46. break;
  47. }
  48. }
  49. /* save the filesystem's operations */
  50. if (empty == NULL)
  51. {
  52. rt_set_errno(-ENOSPC);
  53. LOG_E("There is no space to register this file system (%s).", ops->name);
  54. ret = -1;
  55. }
  56. else if (ret == RT_EOK)
  57. {
  58. *empty = ops;
  59. }
  60. dfs_unlock();
  61. return ret;
  62. }
  63. /**
  64. * this function will return the file system mounted on specified path.
  65. *
  66. * @param path the specified path string.
  67. *
  68. * @return the found file system or NULL if no file system mounted on
  69. * specified path
  70. */
  71. struct dfs_filesystem *dfs_filesystem_lookup(const char *path)
  72. {
  73. struct dfs_filesystem *iter;
  74. struct dfs_filesystem *fs = NULL;
  75. uint32_t fspath, prefixlen;
  76. prefixlen = 0;
  77. RT_ASSERT(path);
  78. /* lock filesystem */
  79. dfs_lock();
  80. /* lookup it in the filesystem table */
  81. for (iter = &filesystem_table[0];
  82. iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
  83. {
  84. if ((iter->path == NULL) || (iter->ops == NULL))
  85. continue;
  86. fspath = strlen(iter->path);
  87. if ((fspath < prefixlen)
  88. || (strncmp(iter->path, path, fspath) != 0))
  89. continue;
  90. /* check next path separator */
  91. if (fspath > 1 && (strlen(path) > fspath) && (path[fspath] != '/'))
  92. continue;
  93. fs = iter;
  94. prefixlen = fspath;
  95. }
  96. dfs_unlock();
  97. return fs;
  98. }
  99. /**
  100. * this function will return the mounted path for specified device.
  101. *
  102. * @param device the device object which is mounted.
  103. *
  104. * @return the mounted path or NULL if none device mounted.
  105. */
  106. const char *dfs_filesystem_get_mounted_path(struct rt_device *device)
  107. {
  108. const char *path = NULL;
  109. struct dfs_filesystem *iter;
  110. dfs_lock();
  111. for (iter = &filesystem_table[0];
  112. iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
  113. {
  114. /* fint the mounted device */
  115. if (iter->ops == NULL) continue;
  116. else if (iter->dev_id == device)
  117. {
  118. path = iter->path;
  119. break;
  120. }
  121. }
  122. /* release filesystem_table lock */
  123. dfs_unlock();
  124. return path;
  125. }
  126. /**
  127. * this function will fetch the partition table on specified buffer.
  128. *
  129. * @param part the returned partition structure.
  130. * @param buf the buffer contains partition table.
  131. * @param pindex the index of partition table to fetch.
  132. *
  133. * @return RT_EOK on successful or -RT_ERROR on failed.
  134. */
  135. int dfs_filesystem_get_partition(struct dfs_partition *part,
  136. uint8_t *buf,
  137. uint32_t pindex)
  138. {
  139. #define DPT_ADDRESS 0x1be /* device partition offset in Boot Sector */
  140. #define DPT_ITEM_SIZE 16 /* partition item size */
  141. uint8_t *dpt;
  142. uint8_t type;
  143. RT_ASSERT(part != NULL);
  144. RT_ASSERT(buf != NULL);
  145. dpt = buf + DPT_ADDRESS + pindex * DPT_ITEM_SIZE;
  146. /* check if it is a valid partition table */
  147. if ((*dpt != 0x80) && (*dpt != 0x00))
  148. return -EIO;
  149. /* get partition type */
  150. type = *(dpt + 4);
  151. if (type == 0)
  152. return -EIO;
  153. /* set partition information
  154. * size is the number of 512-Byte */
  155. part->type = type;
  156. part->offset = *(dpt + 8) | *(dpt + 9) << 8 | *(dpt + 10) << 16 | *(dpt + 11) << 24;
  157. part->size = *(dpt + 12) | *(dpt + 13) << 8 | *(dpt + 14) << 16 | *(dpt + 15) << 24;
  158. rt_kprintf("found part[%d], begin: %d, size: ",
  159. pindex, part->offset * 512);
  160. if ((part->size >> 11) == 0)
  161. rt_kprintf("%d%s", part->size >> 1, "KB\n"); /* KB */
  162. else
  163. {
  164. unsigned int part_size;
  165. part_size = part->size >> 11; /* MB */
  166. if ((part_size >> 10) == 0)
  167. rt_kprintf("%d.%d%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
  168. else
  169. rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
  170. }
  171. return RT_EOK;
  172. }
  173. /**
  174. * this function will mount a file system on a specified path.
  175. *
  176. * @param device_name the name of device which includes a file system.
  177. * @param path the path to mount a file system
  178. * @param filesystemtype the file system type
  179. * @param rwflag the read/write etc. flag.
  180. * @param data the private data(parameter) for this file system.
  181. *
  182. * @return 0 on successful or -1 on failed.
  183. */
  184. int dfs_mount(const char *device_name,
  185. const char *path,
  186. const char *filesystemtype,
  187. unsigned long rwflag,
  188. const void *data)
  189. {
  190. const struct dfs_filesystem_ops **ops;
  191. struct dfs_filesystem *iter;
  192. struct dfs_filesystem *fs = NULL;
  193. char *fullpath = NULL;
  194. rt_device_t dev_id;
  195. /* open specific device */
  196. if (device_name == NULL)
  197. {
  198. /* which is a non-device filesystem mount */
  199. dev_id = NULL;
  200. }
  201. else if ((dev_id = rt_device_find(device_name)) == NULL)
  202. {
  203. /* no this device */
  204. rt_set_errno(-ENODEV);
  205. return -1;
  206. }
  207. /* find out the specific filesystem */
  208. dfs_lock();
  209. for (ops = &filesystem_operation_table[0];
  210. ops < &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; ops++)
  211. if ((*ops != NULL) && (strcmp((*ops)->name, filesystemtype) == 0))
  212. break;
  213. dfs_unlock();
  214. if (ops == &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX])
  215. {
  216. /* can't find filesystem */
  217. rt_set_errno(-ENODEV);
  218. return -1;
  219. }
  220. /* check if there is mount implementation */
  221. if ((*ops == NULL) || ((*ops)->mount == NULL))
  222. {
  223. rt_set_errno(-ENOSYS);
  224. return -1;
  225. }
  226. /* make full path for special file */
  227. fullpath = dfs_normalize_path(NULL, path);
  228. if (fullpath == NULL) /* not an abstract path */
  229. {
  230. rt_set_errno(-ENOTDIR);
  231. return -1;
  232. }
  233. /* Check if the path exists or not, raw APIs call, fixme */
  234. if ((strcmp(fullpath, "/") != 0) && (strcmp(fullpath, "/dev") != 0))
  235. {
  236. struct dfs_fd fd;
  237. if (dfs_file_open(&fd, fullpath, O_RDONLY | O_DIRECTORY) < 0)
  238. {
  239. rt_free(fullpath);
  240. rt_set_errno(-ENOTDIR);
  241. return -1;
  242. }
  243. dfs_file_close(&fd);
  244. }
  245. /* check whether the file system mounted or not in the filesystem table
  246. * if it is unmounted yet, find out an empty entry */
  247. dfs_lock();
  248. for (iter = &filesystem_table[0];
  249. iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
  250. {
  251. /* check if it is an empty filesystem table entry? if it is, save fs */
  252. if (iter->ops == NULL)
  253. (fs == NULL) ? (fs = iter) : 0;
  254. /* check if the PATH is mounted */
  255. else if (strcmp(iter->path, path) == 0)
  256. {
  257. rt_set_errno(-EINVAL);
  258. goto err1;
  259. }
  260. }
  261. if ((fs == NULL) && (iter == &filesystem_table[DFS_FILESYSTEMS_MAX]))
  262. {
  263. rt_set_errno(-ENOSPC);
  264. LOG_E("There is no space to mount this file system (%s).", filesystemtype);
  265. goto err1;
  266. }
  267. /* register file system */
  268. fs->path = fullpath;
  269. fs->ops = *ops;
  270. fs->dev_id = dev_id;
  271. /* release filesystem_table lock */
  272. dfs_unlock();
  273. /* open device, but do not check the status of device */
  274. if (dev_id != NULL)
  275. {
  276. if (rt_device_open(fs->dev_id,
  277. RT_DEVICE_OFLAG_RDWR) != RT_EOK)
  278. {
  279. /* The underlaying device has error, clear the entry. */
  280. dfs_lock();
  281. memset(fs, 0, sizeof(struct dfs_filesystem));
  282. goto err1;
  283. }
  284. }
  285. /* call mount of this filesystem */
  286. if ((*ops)->mount(fs, rwflag, data) < 0)
  287. {
  288. /* close device */
  289. if (dev_id != NULL)
  290. rt_device_close(fs->dev_id);
  291. /* mount failed */
  292. dfs_lock();
  293. /* clear filesystem table entry */
  294. memset(fs, 0, sizeof(struct dfs_filesystem));
  295. goto err1;
  296. }
  297. return 0;
  298. err1:
  299. dfs_unlock();
  300. rt_free(fullpath);
  301. return -1;
  302. }
  303. /**
  304. * this function will unmount a file system on specified path.
  305. *
  306. * @param specialfile the specified path which mounted a file system.
  307. *
  308. * @return 0 on successful or -1 on failed.
  309. */
  310. int dfs_unmount(const char *specialfile)
  311. {
  312. char *fullpath;
  313. struct dfs_filesystem *iter;
  314. struct dfs_filesystem *fs = NULL;
  315. fullpath = dfs_normalize_path(NULL, specialfile);
  316. if (fullpath == NULL)
  317. {
  318. rt_set_errno(-ENOTDIR);
  319. return -1;
  320. }
  321. /* lock filesystem */
  322. dfs_lock();
  323. for (iter = &filesystem_table[0];
  324. iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
  325. {
  326. /* check if the PATH is mounted */
  327. if ((iter->path != NULL) && (strcmp(iter->path, fullpath) == 0))
  328. {
  329. fs = iter;
  330. break;
  331. }
  332. }
  333. if (fs == NULL ||
  334. fs->ops->unmount == NULL ||
  335. fs->ops->unmount(fs) < 0)
  336. {
  337. goto err1;
  338. }
  339. /* close device, but do not check the status of device */
  340. if (fs->dev_id != NULL)
  341. rt_device_close(fs->dev_id);
  342. if (fs->path != NULL)
  343. rt_free(fs->path);
  344. /* clear this filesystem table entry */
  345. memset(fs, 0, sizeof(struct dfs_filesystem));
  346. dfs_unlock();
  347. rt_free(fullpath);
  348. return 0;
  349. err1:
  350. dfs_unlock();
  351. rt_free(fullpath);
  352. return -1;
  353. }
  354. /**
  355. * make a file system on the special device
  356. *
  357. * @param fs_name the file system name
  358. * @param device_name the special device name
  359. *
  360. * @return 0 on successful, otherwise failed.
  361. */
  362. int dfs_mkfs(const char *fs_name, const char *device_name)
  363. {
  364. int index;
  365. rt_device_t dev_id = NULL;
  366. /* check device name, and it should not be NULL */
  367. if (device_name != NULL)
  368. dev_id = rt_device_find(device_name);
  369. if (dev_id == NULL)
  370. {
  371. rt_set_errno(-ENODEV);
  372. LOG_E("Device (%s) was not found", device_name);
  373. return -1;
  374. }
  375. /* lock file system */
  376. dfs_lock();
  377. /* find the file system operations */
  378. for (index = 0; index < DFS_FILESYSTEM_TYPES_MAX; index ++)
  379. {
  380. if (filesystem_operation_table[index] != NULL &&
  381. strcmp(filesystem_operation_table[index]->name, fs_name) == 0)
  382. break;
  383. }
  384. dfs_unlock();
  385. if (index < DFS_FILESYSTEM_TYPES_MAX)
  386. {
  387. /* find file system operation */
  388. const struct dfs_filesystem_ops *ops = filesystem_operation_table[index];
  389. if (ops->mkfs == NULL)
  390. {
  391. LOG_E("The file system (%s) mkfs function was not implement", fs_name);
  392. rt_set_errno(-ENOSYS);
  393. return -1;
  394. }
  395. return ops->mkfs(dev_id);
  396. }
  397. LOG_E("File system (%s) was not found.", fs_name);
  398. return -1;
  399. }
  400. /**
  401. * this function will return the information about a mounted file system.
  402. *
  403. * @param path the path which mounted file system.
  404. * @param buffer the buffer to save the returned information.
  405. *
  406. * @return 0 on successful, others on failed.
  407. */
  408. int dfs_statfs(const char *path, struct statfs *buffer)
  409. {
  410. struct dfs_filesystem *fs;
  411. fs = dfs_filesystem_lookup(path);
  412. if (fs != NULL)
  413. {
  414. if (fs->ops->statfs != NULL)
  415. return fs->ops->statfs(fs, buffer);
  416. }
  417. return -1;
  418. }
  419. #ifdef RT_USING_DFS_MNTTABLE
  420. int dfs_mount_table(void)
  421. {
  422. int index = 0;
  423. while (1)
  424. {
  425. if (mount_table[index].path == NULL) break;
  426. if (dfs_mount(mount_table[index].device_name,
  427. mount_table[index].path,
  428. mount_table[index].filesystemtype,
  429. mount_table[index].rwflag,
  430. mount_table[index].data) != 0)
  431. {
  432. LOG_E("mount fs[%s] on %s failed.\n", mount_table[index].filesystemtype,
  433. mount_table[index].path);
  434. return -RT_ERROR;
  435. }
  436. index ++;
  437. }
  438. return 0;
  439. }
  440. INIT_ENV_EXPORT(dfs_mount_table);
  441. int dfs_mount_device(rt_device_t dev)
  442. {
  443. int index = 0;
  444. if(dev == RT_NULL) {
  445. rt_kprintf("the device is NULL to be mounted.\n");
  446. return -RT_ERROR;
  447. }
  448. while (1)
  449. {
  450. if (mount_table[index].path == NULL) break;
  451. if(strcmp(mount_table[index].device_name, dev->parent.name) == 0) {
  452. if (dfs_mount(mount_table[index].device_name,
  453. mount_table[index].path,
  454. mount_table[index].filesystemtype,
  455. mount_table[index].rwflag,
  456. mount_table[index].data) != 0)
  457. {
  458. LOG_E("mount fs[%s] device[%s] to %s failed.\n", mount_table[index].filesystemtype, dev->parent.name,
  459. mount_table[index].path);
  460. return -RT_ERROR;
  461. } else {
  462. LOG_D("mount fs[%s] device[%s] to %s ok.\n", mount_table[index].filesystemtype, dev->parent.name,
  463. mount_table[index].path);
  464. return RT_EOK;
  465. }
  466. }
  467. index ++;
  468. }
  469. rt_kprintf("can't find device:%s to be mounted.\n", dev->parent.name);
  470. return -RT_ERROR;
  471. }
  472. int dfs_unmount_device(rt_device_t dev)
  473. {
  474. struct dfs_filesystem *iter;
  475. struct dfs_filesystem *fs = NULL;
  476. /* lock filesystem */
  477. dfs_lock();
  478. for (iter = &filesystem_table[0];
  479. iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
  480. {
  481. /* check if the PATH is mounted */
  482. if ((iter->dev_id->parent.name != NULL)
  483. && (strcmp(iter->dev_id->parent.name, dev->parent.name) == 0))
  484. {
  485. fs = iter;
  486. break;
  487. }
  488. }
  489. if (fs == NULL ||
  490. fs->ops->unmount == NULL ||
  491. fs->ops->unmount(fs) < 0)
  492. {
  493. goto err1;
  494. }
  495. /* close device, but do not check the status of device */
  496. if (fs->dev_id != NULL)
  497. rt_device_close(fs->dev_id);
  498. if (fs->path != NULL)
  499. rt_free(fs->path);
  500. /* clear this filesystem table entry */
  501. memset(fs, 0, sizeof(struct dfs_filesystem));
  502. dfs_unlock();
  503. return 0;
  504. err1:
  505. dfs_unlock();
  506. return -1;
  507. }
  508. #endif
  509. #ifdef RT_USING_FINSH
  510. #include <finsh.h>
  511. void mkfs(const char *fs_name, const char *device_name)
  512. {
  513. dfs_mkfs(fs_name, device_name);
  514. }
  515. FINSH_FUNCTION_EXPORT(mkfs, make a file system);
  516. int df(const char *path)
  517. {
  518. int result;
  519. int minor = 0;
  520. long long cap;
  521. struct statfs buffer;
  522. int unit_index = 0;
  523. char *unit_str[] = {"KB", "MB", "GB"};
  524. result = dfs_statfs(path ? path : NULL, &buffer);
  525. if (result != 0)
  526. {
  527. rt_kprintf("dfs_statfs failed.\n");
  528. return -1;
  529. }
  530. cap = ((long long)buffer.f_bsize) * ((long long)buffer.f_bfree) / 1024LL;
  531. for (unit_index = 0; unit_index < 2; unit_index ++)
  532. {
  533. if (cap < 1024) break;
  534. minor = (cap % 1024) * 10 / 1024; /* only one decimal point */
  535. cap = cap / 1024;
  536. }
  537. rt_kprintf("disk free: %d.%d %s [ %d block, %d bytes per block ]\n",
  538. (unsigned long)cap, minor, unit_str[unit_index], buffer.f_bfree, buffer.f_bsize);
  539. return 0;
  540. }
  541. FINSH_FUNCTION_EXPORT(df, get disk free);
  542. #endif
  543. /* @} */