dfs.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /*
  2. * Copyright (c) 2006-2022, 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. * 2017-12-11 Bernard Use rt_free to instead of free in fd_is_open().
  10. * 2018-03-20 Heyuanjie dynamic allocation FD
  11. */
  12. #include <dfs.h>
  13. #include <dfs_fs.h>
  14. #include <dfs_file.h>
  15. #include "dfs_private.h"
  16. #ifdef RT_USING_LWP
  17. #include <lwp.h>
  18. #endif
  19. #ifdef RT_USING_POSIX_STDIO
  20. #include <libc.h>
  21. #endif /* RT_USING_POSIX_STDIO */
  22. /* Global variables */
  23. const struct dfs_filesystem_ops *filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX];
  24. struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX];
  25. /* device filesystem lock */
  26. static struct rt_mutex fslock;
  27. #ifdef DFS_USING_WORKDIR
  28. char working_directory[DFS_PATH_MAX] = {"/"};
  29. #endif
  30. static struct dfs_fdtable _fdtab;
  31. /**
  32. * @addtogroup DFS
  33. */
  34. /*@{*/
  35. /**
  36. * this function will initialize device file system.
  37. */
  38. int dfs_init(void)
  39. {
  40. static rt_bool_t init_ok = RT_FALSE;
  41. if (init_ok)
  42. {
  43. rt_kprintf("dfs already init.\n");
  44. return 0;
  45. }
  46. /* clear filesystem operations table */
  47. rt_memset((void *)filesystem_operation_table, 0, sizeof(filesystem_operation_table));
  48. /* clear filesystem table */
  49. rt_memset(filesystem_table, 0, sizeof(filesystem_table));
  50. /* clean fd table */
  51. rt_memset(&_fdtab, 0, sizeof(_fdtab));
  52. /* create device filesystem lock */
  53. rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_PRIO);
  54. #ifdef DFS_USING_WORKDIR
  55. /* set current working directory */
  56. rt_memset(working_directory, 0, sizeof(working_directory));
  57. working_directory[0] = '/';
  58. #endif
  59. #ifdef RT_USING_DFS_DEVFS
  60. {
  61. extern int devfs_init(void);
  62. /* if enable devfs, initialize and mount it as soon as possible */
  63. devfs_init();
  64. dfs_mount(NULL, "/dev", "devfs", 0, 0);
  65. }
  66. #endif
  67. init_ok = RT_TRUE;
  68. return 0;
  69. }
  70. INIT_PREV_EXPORT(dfs_init);
  71. /**
  72. * this function will lock device file system.
  73. *
  74. * @note please don't invoke it on ISR.
  75. */
  76. void dfs_lock(void)
  77. {
  78. rt_err_t result = -RT_EBUSY;
  79. while (result == -RT_EBUSY)
  80. {
  81. result = rt_mutex_take(&fslock, RT_WAITING_FOREVER);
  82. }
  83. if (result != RT_EOK)
  84. {
  85. RT_ASSERT(0);
  86. }
  87. }
  88. /**
  89. * this function will lock device file system.
  90. *
  91. * @note please don't invoke it on ISR.
  92. */
  93. void dfs_unlock(void)
  94. {
  95. rt_mutex_release(&fslock);
  96. }
  97. #ifdef DFS_USING_POSIX
  98. static int fd_alloc(struct dfs_fdtable *fdt, int startfd)
  99. {
  100. int idx;
  101. /* find an empty fd entry */
  102. for (idx = startfd; idx < (int)fdt->maxfd; idx++)
  103. {
  104. if (fdt->fds[idx] == RT_NULL)
  105. break;
  106. if (fdt->fds[idx]->ref_count == 0)
  107. break;
  108. }
  109. /* allocate a larger FD container */
  110. if (idx == (int)fdt->maxfd && fdt->maxfd < DFS_FD_MAX)
  111. {
  112. int cnt, index;
  113. struct dfs_fd **fds;
  114. /* increase the number of FD with 4 step length */
  115. cnt = fdt->maxfd + 4;
  116. cnt = cnt > DFS_FD_MAX ? DFS_FD_MAX : cnt;
  117. fds = (struct dfs_fd **)rt_realloc(fdt->fds, cnt * sizeof(struct dfs_fd *));
  118. if (fds == NULL) goto __exit; /* return fdt->maxfd */
  119. /* clean the new allocated fds */
  120. for (index = (int)fdt->maxfd; index < cnt; index ++)
  121. {
  122. fds[index] = NULL;
  123. }
  124. fdt->fds = fds;
  125. fdt->maxfd = cnt;
  126. }
  127. /* allocate 'struct dfs_fd' */
  128. if (idx < (int)fdt->maxfd && fdt->fds[idx] == RT_NULL)
  129. {
  130. fdt->fds[idx] = (struct dfs_fd *)rt_calloc(1, sizeof(struct dfs_fd));
  131. if (fdt->fds[idx] == RT_NULL)
  132. idx = fdt->maxfd;
  133. }
  134. __exit:
  135. return idx;
  136. }
  137. /**
  138. * @ingroup Fd
  139. * This function will allocate a file descriptor.
  140. *
  141. * @return -1 on failed or the allocated file descriptor.
  142. */
  143. int fd_new(void)
  144. {
  145. struct dfs_fd *d;
  146. int idx;
  147. struct dfs_fdtable *fdt;
  148. fdt = dfs_fdtable_get();
  149. /* lock filesystem */
  150. dfs_lock();
  151. /* find an empty fd entry */
  152. idx = fd_alloc(fdt, 0);
  153. /* can't find an empty fd entry */
  154. if (idx == (int)fdt->maxfd)
  155. {
  156. idx = -(1 + DFS_FD_OFFSET);
  157. LOG_E("DFS fd new is failed! Could not found an empty fd entry.");
  158. goto __result;
  159. }
  160. d = fdt->fds[idx];
  161. d->ref_count = 1;
  162. d->magic = DFS_FD_MAGIC;
  163. __result:
  164. dfs_unlock();
  165. return idx + DFS_FD_OFFSET;
  166. }
  167. /**
  168. * @ingroup Fd
  169. *
  170. * This function will return a file descriptor structure according to file
  171. * descriptor.
  172. *
  173. * @return NULL on on this file descriptor or the file descriptor structure
  174. * pointer.
  175. */
  176. struct dfs_fd *fd_get(int fd)
  177. {
  178. struct dfs_fd *d;
  179. struct dfs_fdtable *fdt;
  180. #ifdef RT_USING_POSIX_STDIO
  181. if ((0 <= fd) && (fd <= 2))
  182. fd = libc_stdio_get_console();
  183. #endif /* RT_USING_POSIX_STDIO */
  184. fdt = dfs_fdtable_get();
  185. fd = fd - DFS_FD_OFFSET;
  186. if (fd < 0 || fd >= (int)fdt->maxfd)
  187. return NULL;
  188. dfs_lock();
  189. d = fdt->fds[fd];
  190. /* check dfs_fd valid or not */
  191. if ((d == NULL) || (d->magic != DFS_FD_MAGIC))
  192. {
  193. dfs_unlock();
  194. return NULL;
  195. }
  196. /* increase the reference count */
  197. d->ref_count ++;
  198. dfs_unlock();
  199. return d;
  200. }
  201. /**
  202. * @ingroup Fd
  203. *
  204. * This function will put the file descriptor.
  205. */
  206. void fd_put(struct dfs_fd *fd)
  207. {
  208. RT_ASSERT(fd != NULL);
  209. dfs_lock();
  210. fd->ref_count --;
  211. /* clear this fd entry */
  212. if (fd->ref_count == 0)
  213. {
  214. int index;
  215. struct dfs_fdtable *fdt;
  216. fdt = dfs_fdtable_get();
  217. for (index = 0; index < (int)fdt->maxfd; index ++)
  218. {
  219. if (fdt->fds[index] == fd)
  220. {
  221. rt_free(fd);
  222. fdt->fds[index] = 0;
  223. break;
  224. }
  225. }
  226. }
  227. dfs_unlock();
  228. }
  229. #endif /* DFS_USING_POSIX */
  230. /**
  231. * @ingroup Fd
  232. *
  233. * This function will return whether this file has been opend.
  234. *
  235. * @param pathname the file path name.
  236. *
  237. * @return 0 on file has been open successfully, -1 on open failed.
  238. */
  239. int fd_is_open(const char *pathname)
  240. {
  241. char *fullpath;
  242. unsigned int index;
  243. struct dfs_filesystem *fs;
  244. struct dfs_fd *fd;
  245. struct dfs_fdtable *fdt;
  246. fdt = dfs_fdtable_get();
  247. fullpath = dfs_normalize_path(NULL, pathname);
  248. if (fullpath != NULL)
  249. {
  250. char *mountpath;
  251. fs = dfs_filesystem_lookup(fullpath);
  252. if (fs == NULL)
  253. {
  254. /* can't find mounted file system */
  255. rt_free(fullpath);
  256. return -1;
  257. }
  258. /* get file path name under mounted file system */
  259. if (fs->path[0] == '/' && fs->path[1] == '\0')
  260. mountpath = fullpath;
  261. else
  262. mountpath = fullpath + strlen(fs->path);
  263. dfs_lock();
  264. for (index = 0; index < fdt->maxfd; index++)
  265. {
  266. fd = fdt->fds[index];
  267. if (fd == NULL || fd->fops == NULL || fd->path == NULL) continue;
  268. if (fd->fs == fs && strcmp(fd->path, mountpath) == 0)
  269. {
  270. /* found file in file descriptor table */
  271. rt_free(fullpath);
  272. dfs_unlock();
  273. return 0;
  274. }
  275. }
  276. dfs_unlock();
  277. rt_free(fullpath);
  278. }
  279. return -1;
  280. }
  281. /**
  282. * this function will return a sub-path name under directory.
  283. *
  284. * @param directory the parent directory.
  285. * @param filename the filename.
  286. *
  287. * @return the subdir pointer in filename
  288. */
  289. const char *dfs_subdir(const char *directory, const char *filename)
  290. {
  291. const char *dir;
  292. if (strlen(directory) == strlen(filename)) /* it's a same path */
  293. return NULL;
  294. dir = filename + strlen(directory);
  295. if ((*dir != '/') && (dir != filename))
  296. {
  297. dir --;
  298. }
  299. return dir;
  300. }
  301. RTM_EXPORT(dfs_subdir);
  302. /**
  303. * this function will normalize a path according to specified parent directory
  304. * and file name.
  305. *
  306. * @param directory the parent path
  307. * @param filename the file name
  308. *
  309. * @return the built full file path (absolute path)
  310. */
  311. char *dfs_normalize_path(const char *directory, const char *filename)
  312. {
  313. char *fullpath;
  314. char *dst0, *dst, *src;
  315. /* check parameters */
  316. RT_ASSERT(filename != NULL);
  317. #ifdef DFS_USING_WORKDIR
  318. if (directory == NULL) /* shall use working directory */
  319. directory = &working_directory[0];
  320. #else
  321. if ((directory == NULL) && (filename[0] != '/'))
  322. {
  323. rt_kprintf(NO_WORKING_DIR);
  324. return NULL;
  325. }
  326. #endif
  327. if (filename[0] != '/') /* it's a absolute path, use it directly */
  328. {
  329. fullpath = (char *)rt_malloc(strlen(directory) + strlen(filename) + 2);
  330. if (fullpath == NULL)
  331. return NULL;
  332. /* join path and file name */
  333. rt_snprintf(fullpath, strlen(directory) + strlen(filename) + 2,
  334. "%s/%s", directory, filename);
  335. }
  336. else
  337. {
  338. fullpath = rt_strdup(filename); /* copy string */
  339. if (fullpath == NULL)
  340. return NULL;
  341. }
  342. src = fullpath;
  343. dst = fullpath;
  344. dst0 = dst;
  345. while (1)
  346. {
  347. char c = *src;
  348. if (c == '.')
  349. {
  350. if (!src[1]) src ++; /* '.' and ends */
  351. else if (src[1] == '/')
  352. {
  353. /* './' case */
  354. src += 2;
  355. while ((*src == '/') && (*src != '\0'))
  356. src ++;
  357. continue;
  358. }
  359. else if (src[1] == '.')
  360. {
  361. if (!src[2])
  362. {
  363. /* '..' and ends case */
  364. src += 2;
  365. goto up_one;
  366. }
  367. else if (src[2] == '/')
  368. {
  369. /* '../' case */
  370. src += 3;
  371. while ((*src == '/') && (*src != '\0'))
  372. src ++;
  373. goto up_one;
  374. }
  375. }
  376. }
  377. /* copy up the next '/' and erase all '/' */
  378. while ((c = *src++) != '\0' && c != '/')
  379. *dst ++ = c;
  380. if (c == '/')
  381. {
  382. *dst ++ = '/';
  383. while (c == '/')
  384. c = *src++;
  385. src --;
  386. }
  387. else if (!c)
  388. break;
  389. continue;
  390. up_one:
  391. dst --;
  392. if (dst < dst0)
  393. {
  394. rt_free(fullpath);
  395. return NULL;
  396. }
  397. while (dst0 < dst && dst[-1] != '/')
  398. dst --;
  399. }
  400. *dst = '\0';
  401. /* remove '/' in the end of path if exist */
  402. dst --;
  403. if ((dst != fullpath) && (*dst == '/'))
  404. *dst = '\0';
  405. /* final check fullpath is not empty, for the special path of lwext "/.." */
  406. if ('\0' == fullpath[0])
  407. {
  408. fullpath[0] = '/';
  409. fullpath[1] = '\0';
  410. }
  411. return fullpath;
  412. }
  413. RTM_EXPORT(dfs_normalize_path);
  414. /**
  415. * This function will get the file descriptor table of current process.
  416. */
  417. struct dfs_fdtable *dfs_fdtable_get(void)
  418. {
  419. struct dfs_fdtable *fdt;
  420. #ifdef RT_USING_LWP
  421. struct rt_lwp *lwp;
  422. lwp = (struct rt_lwp *)rt_thread_self()->lwp;
  423. if (lwp)
  424. fdt = &lwp->fdt;
  425. else
  426. fdt = &_fdtab;
  427. #else
  428. fdt = &_fdtab;
  429. #endif
  430. return fdt;
  431. }
  432. #ifdef RT_USING_FINSH
  433. #include <finsh.h>
  434. int list_fd(void)
  435. {
  436. int index;
  437. struct dfs_fdtable *fd_table;
  438. fd_table = dfs_fdtable_get();
  439. if (!fd_table) return -1;
  440. dfs_lock();
  441. rt_kprintf("fd type ref magic path\n");
  442. rt_kprintf("-- ------ --- ----- ------\n");
  443. for (index = 0; index < (int)fd_table->maxfd; index ++)
  444. {
  445. struct dfs_fd *fd = fd_table->fds[index];
  446. if (fd && fd->fops)
  447. {
  448. rt_kprintf("%2d ", index + DFS_FD_OFFSET);
  449. if (fd->type == FT_DIRECTORY) rt_kprintf("%-7.7s ", "dir");
  450. else if (fd->type == FT_REGULAR) rt_kprintf("%-7.7s ", "file");
  451. else if (fd->type == FT_SOCKET) rt_kprintf("%-7.7s ", "socket");
  452. else if (fd->type == FT_USER) rt_kprintf("%-7.7s ", "user");
  453. else if (fd->type == FT_DEVICE) rt_kprintf("%-7.7s ", "device");
  454. else rt_kprintf("%-8.8s ", "unknown");
  455. rt_kprintf("%3d ", fd->ref_count);
  456. rt_kprintf("%04x ", fd->magic);
  457. if (fd->fs && fd->fs->path && rt_strlen(fd->fs->path) > 1)
  458. {
  459. rt_kprintf("%s", fd->fs->path);
  460. }
  461. if (fd->path)
  462. {
  463. rt_kprintf("%s\n", fd->path);
  464. }
  465. else
  466. {
  467. rt_kprintf("\n");
  468. }
  469. }
  470. }
  471. dfs_unlock();
  472. return 0;
  473. }
  474. MSH_CMD_EXPORT(list_fd, list file descriptor);
  475. #endif
  476. /*@}*/