dfs_fs.c 14 KB

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