dfs.c 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. /*
  2. * Copyright (c) 2006-2024 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_SMART
  17. #include <lwp.h>
  18. #endif
  19. #ifdef RT_USING_POSIX_STDIO
  20. #include <posix/stdio.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. static struct rt_mutex fdlock;
  28. #ifdef DFS_USING_WORKDIR
  29. char working_directory[DFS_PATH_MAX] = {"/"};
  30. #endif
  31. static struct dfs_fdtable _fdtab;
  32. static int fd_alloc(struct dfs_fdtable *fdt, int startfd);
  33. /**
  34. * @addtogroup group_device_virtual_file_system
  35. * @{
  36. */
  37. /**
  38. * this function will initialize device file system.
  39. */
  40. int dfs_init(void)
  41. {
  42. static rt_bool_t init_ok = RT_FALSE;
  43. if (init_ok)
  44. {
  45. rt_kprintf("dfs already init.\n");
  46. return 0;
  47. }
  48. /* init vnode hash table */
  49. dfs_vnode_mgr_init();
  50. /* clear filesystem operations table */
  51. rt_memset((void *)filesystem_operation_table, 0, sizeof(filesystem_operation_table));
  52. /* clear filesystem table */
  53. rt_memset(filesystem_table, 0, sizeof(filesystem_table));
  54. /* clean fd table */
  55. rt_memset(&_fdtab, 0, sizeof(_fdtab));
  56. /* create device filesystem lock */
  57. rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_PRIO);
  58. rt_mutex_init(&fdlock, "fdlock", RT_IPC_FLAG_PRIO);
  59. #ifdef DFS_USING_WORKDIR
  60. /* set current working directory */
  61. rt_memset(working_directory, 0, sizeof(working_directory));
  62. working_directory[0] = '/';
  63. #endif
  64. #ifdef RT_USING_DFS_TMPFS
  65. {
  66. extern int dfs_tmpfs_init(void);
  67. dfs_tmpfs_init();
  68. }
  69. #endif
  70. #ifdef RT_USING_DFS_DEVFS
  71. {
  72. extern int devfs_init(void);
  73. /* if enable devfs, initialize and mount it as soon as possible */
  74. devfs_init();
  75. dfs_mount(NULL, "/dev", "devfs", 0, 0);
  76. }
  77. #if defined(RT_USING_DEV_BUS) && defined(RT_USING_DFS_TMPFS)
  78. mkdir("/dev/shm", 0x777);
  79. if (dfs_mount(RT_NULL, "/dev/shm", "tmp", 0, 0) != 0)
  80. {
  81. rt_kprintf("Dir /dev/shm mount failed!\n");
  82. }
  83. #endif
  84. #endif
  85. init_ok = RT_TRUE;
  86. return 0;
  87. }
  88. INIT_PREV_EXPORT(dfs_init);
  89. /**
  90. * @brief this function will lock device file system.
  91. * this lock (fslock) is used for protecting filesystem_operation_table and filesystem_table.
  92. *
  93. * @note please don't invoke it on ISR.
  94. */
  95. void dfs_lock(void)
  96. {
  97. rt_err_t result = -RT_EBUSY;
  98. while (result == -RT_EBUSY)
  99. {
  100. result = rt_mutex_take(&fslock, RT_WAITING_FOREVER);
  101. }
  102. if (result != RT_EOK)
  103. {
  104. RT_ASSERT(0);
  105. }
  106. }
  107. /**
  108. * @brief this function will lock file descriptors.
  109. * this lock (fdlock) is used for protecting fd table (_fdtab).
  110. *
  111. * @note please don't invoke it on ISR.
  112. */
  113. void dfs_file_lock(void)
  114. {
  115. rt_err_t result = -RT_EBUSY;
  116. while (result == -RT_EBUSY)
  117. {
  118. result = rt_mutex_take(&fdlock, RT_WAITING_FOREVER);
  119. }
  120. if (result != RT_EOK)
  121. {
  122. RT_ASSERT(0);
  123. }
  124. }
  125. /**
  126. * @brief this function will unlock device file system.
  127. *
  128. * @note please don't invoke it on ISR.
  129. */
  130. void dfs_unlock(void)
  131. {
  132. rt_mutex_release(&fslock);
  133. }
  134. /**
  135. * @brief this function will unlock fd table.
  136. */
  137. void dfs_file_unlock(void)
  138. {
  139. rt_mutex_release(&fdlock);
  140. }
  141. #ifdef DFS_USING_POSIX
  142. /**
  143. * @brief Expand the file descriptor table to accommodate a specific file descriptor.
  144. *
  145. * This function ensures that the file descriptor table in the given `dfs_fdtable` structure
  146. * has sufficient capacity to include the specified file descriptor `fd`. If the table
  147. * needs to be expanded, it reallocates memory and initializes new slots to `NULL`.
  148. *
  149. * @param fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
  150. * @param fd The file descriptor that the table must accommodate.
  151. * @return int
  152. * - The input file descriptor `fd` if it is within the current or newly expanded table's capacity.
  153. * - `-1` if the requested file descriptor exceeds `DFS_FD_MAX` or memory allocation fails.
  154. */
  155. static int fd_slot_expand(struct dfs_fdtable *fdt, int fd)
  156. {
  157. int nr;
  158. int index;
  159. struct dfs_file **fds = NULL;
  160. /* If the file descriptor is already within the current capacity, no expansion is needed.*/
  161. if (fd < fdt->maxfd)
  162. {
  163. return fd;
  164. }
  165. /* If the file descriptor exceeds the maximum allowable limit, return an error.*/
  166. if (fd >= DFS_FD_MAX)
  167. {
  168. return -1;
  169. }
  170. /* Calculate the new capacity, rounding up to the nearest multiple of 4.*/
  171. nr = ((fd + 4) & ~3);
  172. /* Ensure the new capacity does not exceed the maximum limit.*/
  173. if (nr > DFS_FD_MAX)
  174. {
  175. nr = DFS_FD_MAX;
  176. }
  177. /* Attempt to reallocate the file descriptor table to the new capacity.*/
  178. fds = (struct dfs_file **)rt_realloc(fdt->fds, nr * sizeof(struct dfs_file *));
  179. if (!fds)
  180. {
  181. return -1;
  182. }
  183. /* clean the new allocated fds */
  184. for (index = fdt->maxfd; index < nr; index++)
  185. {
  186. fds[index] = NULL;
  187. }
  188. /* Update the file descriptor table and its capacity.*/
  189. fdt->fds = fds;
  190. fdt->maxfd = nr;
  191. return fd;
  192. }
  193. /**
  194. * @brief Allocate a file descriptor slot starting from a specified index.
  195. *
  196. * @param fdt fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
  197. * @param startfd The starting index for the search for an empty slot.
  198. * @return int
  199. * - The index of the first available slot if successful.
  200. * - `-1` if no slot is available or if table expansion fails
  201. */
  202. static int fd_slot_alloc(struct dfs_fdtable *fdt, int startfd)
  203. {
  204. int idx;
  205. /* find an empty fd slot */
  206. for (idx = startfd; idx < (int)fdt->maxfd; idx++)
  207. {
  208. if (fdt->fds[idx] == RT_NULL)
  209. {
  210. return idx;
  211. }
  212. }
  213. idx = fdt->maxfd;
  214. if (idx < startfd)
  215. {
  216. idx = startfd;
  217. }
  218. if (fd_slot_expand(fdt, idx) < 0)
  219. {
  220. return -1;
  221. }
  222. return idx;
  223. }
  224. /**
  225. * @brief Allocate a new file descriptor and associate it with a newly allocated `struct dfs_file`.
  226. *
  227. * @param fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
  228. * @param startfd The starting index for searching an available file descriptor slot.
  229. *
  230. * @return
  231. * - The index of the allocated file descriptor if successful.
  232. * - `-1` if no slot is available or memory allocation fails.
  233. */
  234. static int fd_alloc(struct dfs_fdtable *fdt, int startfd)
  235. {
  236. int idx;
  237. struct dfs_file *fd = NULL;
  238. idx = fd_slot_alloc(fdt, startfd);
  239. /* allocate 'struct dfs_file' */
  240. if (idx < 0)
  241. {
  242. return -1;
  243. }
  244. fd = (struct dfs_file *)rt_calloc(1, sizeof(struct dfs_file));
  245. if (!fd)
  246. {
  247. return -1;
  248. }
  249. fd->ref_count = 1;
  250. fd->magic = DFS_FD_MAGIC;
  251. fd->vnode = NULL;
  252. fdt->fds[idx] = fd;
  253. return idx;
  254. }
  255. /**
  256. * @ingroup group_fs_file_descriptor
  257. * This function will allocate a file descriptor.
  258. *
  259. * @return -1 on failed or the allocated file descriptor.
  260. */
  261. int fdt_fd_new(struct dfs_fdtable *fdt)
  262. {
  263. int idx;
  264. /* lock filesystem */
  265. dfs_file_lock();
  266. /* find an empty fd entry */
  267. idx = fd_alloc(fdt, DFS_STDIO_OFFSET);
  268. /* can't find an empty fd entry */
  269. if (idx < 0)
  270. {
  271. LOG_E("DFS fd new is failed! Could not found an empty fd entry.");
  272. }
  273. dfs_file_unlock();
  274. return idx;
  275. }
  276. int fd_new(void)
  277. {
  278. struct dfs_fdtable *fdt = NULL;
  279. fdt = dfs_fdtable_get();
  280. return fdt_fd_new(fdt);
  281. }
  282. /**
  283. * @ingroup group_fs_file_descriptor
  284. *
  285. * This function will return a file descriptor structure according to file
  286. * descriptor.
  287. *
  288. * @return NULL on on this file descriptor or the file descriptor structure
  289. * pointer.
  290. */
  291. struct dfs_file *fdt_fd_get(struct dfs_fdtable* fdt, int fd)
  292. {
  293. struct dfs_file *d;
  294. if (fd < 0 || fd >= (int)fdt->maxfd)
  295. {
  296. return NULL;
  297. }
  298. dfs_file_lock();
  299. d = fdt->fds[fd];
  300. /* check dfs_file valid or not */
  301. if ((d == NULL) || (d->magic != DFS_FD_MAGIC))
  302. {
  303. dfs_file_unlock();
  304. return NULL;
  305. }
  306. dfs_file_unlock();
  307. return d;
  308. }
  309. struct dfs_file *fd_get(int fd)
  310. {
  311. struct dfs_fdtable *fdt;
  312. fdt = dfs_fdtable_get();
  313. return fdt_fd_get(fdt, fd);
  314. }
  315. /**
  316. * @ingroup group_fs_file_descriptor
  317. *
  318. * @brief This function will release the file descriptor.
  319. *
  320. * This function releases a file descriptor slot in the file descriptor table, decrements reference
  321. * counts, and cleans up resources associated with the `dfs_file` and `dfs_vnode` structures when applicable.
  322. *
  323. */
  324. void fdt_fd_release(struct dfs_fdtable* fdt, int fd)
  325. {
  326. struct dfs_file *fd_slot = NULL;
  327. RT_ASSERT(fdt != NULL);
  328. dfs_file_lock();
  329. if ((fd < 0) || (fd >= fdt->maxfd))
  330. {
  331. dfs_file_unlock();
  332. return;
  333. }
  334. fd_slot = fdt->fds[fd];
  335. if (fd_slot == NULL)
  336. {
  337. dfs_file_unlock();
  338. return;
  339. }
  340. fdt->fds[fd] = NULL;
  341. /* check fd */
  342. RT_ASSERT(fd_slot->magic == DFS_FD_MAGIC);
  343. fd_slot->ref_count--;
  344. /* clear this fd entry */
  345. if (fd_slot->ref_count == 0)
  346. {
  347. struct dfs_vnode *vnode = fd_slot->vnode;
  348. if (vnode)
  349. {
  350. vnode->ref_count--;
  351. if(vnode->ref_count == 0)
  352. {
  353. rt_free(vnode);
  354. fd_slot->vnode = RT_NULL;
  355. }
  356. }
  357. rt_free(fd_slot);
  358. }
  359. dfs_file_unlock();
  360. }
  361. void fd_release(int fd)
  362. {
  363. struct dfs_fdtable *fdt;
  364. fdt = dfs_fdtable_get();
  365. fdt_fd_release(fdt, fd);
  366. }
  367. /**
  368. * @brief Duplicates a file descriptor.
  369. *
  370. * This function duplicates an existing file descriptor (`oldfd`) and returns
  371. * a new file descriptor that refers to the same underlying file object.
  372. *
  373. * @param oldfd The file descriptor to duplicate. It must be a valid file
  374. * descriptor within the range of allocated descriptors.
  375. *
  376. * @return The new file descriptor if successful, or a negative value
  377. * (e.g., -1) if an error occurs.
  378. *
  379. * @see sys_dup2()
  380. */
  381. rt_err_t sys_dup(int oldfd)
  382. {
  383. int newfd = -1;
  384. struct dfs_fdtable *fdt = NULL;
  385. dfs_file_lock();
  386. /* check old fd */
  387. fdt = dfs_fdtable_get();
  388. if ((oldfd < 0) || (oldfd >= fdt->maxfd))
  389. {
  390. goto exit;
  391. }
  392. if (!fdt->fds[oldfd])
  393. {
  394. goto exit;
  395. }
  396. /* get a new fd */
  397. newfd = fd_slot_alloc(fdt, DFS_STDIO_OFFSET);
  398. if (newfd >= 0)
  399. {
  400. fdt->fds[newfd] = fdt->fds[oldfd];
  401. /* inc ref_count */
  402. fdt->fds[newfd]->ref_count++;
  403. }
  404. exit:
  405. dfs_file_unlock();
  406. return newfd;
  407. }
  408. #endif /* DFS_USING_POSIX */
  409. /**
  410. * @ingroup group_fs_file_descriptor
  411. *
  412. * This function will return whether this file has been opend.
  413. *
  414. * @param pathname the file path name.
  415. *
  416. * @return 0 on file has been open successfully, -1 on open failed.
  417. */
  418. int fd_is_open(const char *pathname)
  419. {
  420. char *fullpath;
  421. unsigned int index;
  422. struct dfs_filesystem *fs;
  423. struct dfs_file *fd;
  424. struct dfs_fdtable *fdt;
  425. fdt = dfs_fdtable_get();
  426. fullpath = dfs_normalize_path(NULL, pathname);
  427. if (fullpath != NULL)
  428. {
  429. char *mountpath;
  430. fs = dfs_filesystem_lookup(fullpath);
  431. if (fs == NULL)
  432. {
  433. /* can't find mounted file system */
  434. rt_free(fullpath);
  435. return -1;
  436. }
  437. /* get file path name under mounted file system */
  438. if (fs->path[0] == '/' && fs->path[1] == '\0')
  439. mountpath = fullpath;
  440. else
  441. mountpath = fullpath + strlen(fs->path);
  442. dfs_lock();
  443. for (index = 0; index < fdt->maxfd; index++)
  444. {
  445. fd = fdt->fds[index];
  446. if (fd == NULL || fd->vnode->fops == NULL || fd->vnode->path == NULL) continue;
  447. if (fd->vnode->fs == fs && strcmp(fd->vnode->path, mountpath) == 0)
  448. {
  449. /* found file in file descriptor table */
  450. rt_free(fullpath);
  451. dfs_unlock();
  452. return 0;
  453. }
  454. }
  455. dfs_unlock();
  456. rt_free(fullpath);
  457. }
  458. return -1;
  459. }
  460. /**
  461. * @brief Duplicates a file descriptor to a specified file descriptor.
  462. *
  463. * This function duplicates an existing file descriptor (`oldfd`) and assigns it
  464. * to the specified file descriptor (`newfd`).
  465. *
  466. * @param oldfd The file descriptor to duplicate. It must be a valid and open file
  467. * descriptor within the range of allocated descriptors.
  468. * @param newfd The target file descriptor. If `newfd` is already in use, it will
  469. * be closed before duplication. If `newfd` exceeds the current file
  470. * descriptor table size, the table will be expanded to accommodate it.
  471. *
  472. * @return The value of `newfd` on success, or a negative value (e.g., -1) if an
  473. * error occurs.
  474. *
  475. * @see sys_dup()
  476. */
  477. rt_err_t sys_dup2(int oldfd, int newfd)
  478. {
  479. struct dfs_fdtable *fdt = NULL;
  480. int ret = 0;
  481. int retfd = -1;
  482. dfs_file_lock();
  483. /* check old fd */
  484. fdt = dfs_fdtable_get();
  485. if ((oldfd < 0) || (oldfd >= fdt->maxfd))
  486. {
  487. goto exit;
  488. }
  489. if (!fdt->fds[oldfd])
  490. {
  491. goto exit;
  492. }
  493. if (newfd < 0)
  494. {
  495. goto exit;
  496. }
  497. if (newfd >= fdt->maxfd)
  498. {
  499. newfd = fd_slot_expand(fdt, newfd);
  500. if (newfd < 0)
  501. {
  502. goto exit;
  503. }
  504. }
  505. if (fdt->fds[newfd] == fdt->fds[oldfd])
  506. {
  507. /* ok, return newfd */
  508. retfd = newfd;
  509. goto exit;
  510. }
  511. if (fdt->fds[newfd])
  512. {
  513. ret = dfs_file_close(fdt->fds[newfd]);
  514. if (ret < 0)
  515. {
  516. goto exit;
  517. }
  518. fd_release(newfd);
  519. }
  520. fdt->fds[newfd] = fdt->fds[oldfd];
  521. /* inc ref_count */
  522. fdt->fds[newfd]->ref_count++;
  523. retfd = newfd;
  524. exit:
  525. dfs_file_unlock();
  526. return retfd;
  527. }
  528. static int fd_get_fd_index_form_fdt(struct dfs_fdtable *fdt, struct dfs_file *file)
  529. {
  530. int fd = -1;
  531. if (file == RT_NULL)
  532. {
  533. return -1;
  534. }
  535. dfs_file_lock();
  536. for(int index = 0; index < (int)fdt->maxfd; index++)
  537. {
  538. if(fdt->fds[index] == file)
  539. {
  540. fd = index;
  541. break;
  542. }
  543. }
  544. dfs_file_unlock();
  545. return fd;
  546. }
  547. /**
  548. * @brief get fd (index) by dfs file object.
  549. *
  550. */
  551. int fd_get_fd_index(struct dfs_file *file)
  552. {
  553. struct dfs_fdtable *fdt;
  554. fdt = dfs_fdtable_get();
  555. return fd_get_fd_index_form_fdt(fdt, file);
  556. }
  557. /**
  558. * @brief Associates a file descriptor with a file object.
  559. *
  560. * This function associates a given file descriptor (`fd`) with a specified
  561. * file object (`file`) in the file descriptor table (`fdt`).
  562. *
  563. * @param fdt The file descriptor table to operate on. It must be a valid
  564. * and initialized `dfs_fdtable` structure.
  565. * @param fd The file descriptor to associate. It must be within the range
  566. * of allocated file descriptors and currently unoccupied.
  567. * @param file The file object to associate with the file descriptor. It must
  568. * be a valid and initialized `dfs_file` structure.
  569. *
  570. * @return The value of `fd` on success, or -1 if an error occurs.
  571. */
  572. int fd_associate(struct dfs_fdtable *fdt, int fd, struct dfs_file *file)
  573. {
  574. int retfd = -1;
  575. if (!file)
  576. {
  577. return retfd;
  578. }
  579. if (!fdt)
  580. {
  581. return retfd;
  582. }
  583. dfs_file_lock();
  584. /* check old fd */
  585. if ((fd < 0) || (fd >= fdt->maxfd))
  586. {
  587. goto exit;
  588. }
  589. if (fdt->fds[fd])
  590. {
  591. goto exit;
  592. }
  593. /* inc ref_count */
  594. file->ref_count++;
  595. fdt->fds[fd] = file;
  596. retfd = fd;
  597. exit:
  598. dfs_file_unlock();
  599. return retfd;
  600. }
  601. /**
  602. * @brief initialize a dfs file object.
  603. *
  604. */
  605. void fd_init(struct dfs_file *fd)
  606. {
  607. if (fd)
  608. {
  609. fd->magic = DFS_FD_MAGIC;
  610. fd->ref_count = 1;
  611. fd->pos = 0;
  612. fd->vnode = NULL;
  613. fd->data = NULL;
  614. }
  615. }
  616. /**
  617. * this function will return a sub-path name under directory.
  618. *
  619. * @param directory the parent directory.
  620. * @param filename the filename.
  621. *
  622. * @return the subdir pointer in filename
  623. */
  624. const char *dfs_subdir(const char *directory, const char *filename)
  625. {
  626. const char *dir;
  627. if (strlen(directory) == strlen(filename)) /* it's a same path */
  628. return NULL;
  629. dir = filename + strlen(directory);
  630. if ((*dir != '/') && (dir != filename))
  631. {
  632. dir --;
  633. }
  634. return dir;
  635. }
  636. RTM_EXPORT(dfs_subdir);
  637. /**
  638. * this function will normalize a path according to specified parent directory
  639. * and file name.
  640. *
  641. * @param directory the parent path
  642. * @param filename the file name
  643. *
  644. * @return the built full file path (absolute path)
  645. */
  646. char *dfs_normalize_path(const char *directory, const char *filename)
  647. {
  648. char *fullpath;
  649. char *dst0, *dst, *src;
  650. /* check parameters */
  651. RT_ASSERT(filename != NULL);
  652. #ifdef DFS_USING_WORKDIR
  653. if (directory == NULL) /* shall use working directory */
  654. {
  655. #ifdef RT_USING_SMART
  656. directory = lwp_getcwd();
  657. #else
  658. directory = &working_directory[0];
  659. #endif
  660. }
  661. #else
  662. if ((directory == NULL) && (filename[0] != '/'))
  663. {
  664. rt_kprintf(NO_WORKING_DIR);
  665. return NULL;
  666. }
  667. #endif
  668. if (filename[0] != '/') /* it's a absolute path, use it directly */
  669. {
  670. fullpath = (char *)rt_malloc(strlen(directory) + strlen(filename) + 2);
  671. if (fullpath == NULL)
  672. return NULL;
  673. /* join path and file name */
  674. rt_snprintf(fullpath, strlen(directory) + strlen(filename) + 2,
  675. "%s/%s", directory, filename);
  676. }
  677. else
  678. {
  679. fullpath = rt_strdup(filename); /* copy string */
  680. if (fullpath == NULL)
  681. return NULL;
  682. }
  683. src = fullpath;
  684. dst = fullpath;
  685. dst0 = dst;
  686. while (1)
  687. {
  688. char c = *src;
  689. if (c == '.')
  690. {
  691. if (!src[1]) src++; /* '.' and ends */
  692. else if (src[1] == '/')
  693. {
  694. /* './' case */
  695. src += 2;
  696. while ((*src == '/') && (*src != '\0'))
  697. src++;
  698. continue;
  699. }
  700. else if (src[1] == '.')
  701. {
  702. if (!src[2])
  703. {
  704. /* '..' and ends case */
  705. src += 2;
  706. goto up_one;
  707. }
  708. else if (src[2] == '/')
  709. {
  710. /* '../' case */
  711. src += 3;
  712. while ((*src == '/') && (*src != '\0'))
  713. src++;
  714. goto up_one;
  715. }
  716. }
  717. }
  718. /* copy up the next '/' and erase all '/' */
  719. while ((c = *src++) != '\0' && c != '/')
  720. *dst++ = c;
  721. if (c == '/')
  722. {
  723. *dst++ = '/';
  724. while (c == '/')
  725. c = *src++;
  726. src--;
  727. }
  728. else if (!c)
  729. break;
  730. continue;
  731. up_one:
  732. /* keep the topmost root directory */
  733. if (dst - dst0 != 1 || dst[-1] != '/')
  734. {
  735. dst--;
  736. if (dst < dst0)
  737. {
  738. rt_free(fullpath);
  739. return NULL;
  740. }
  741. }
  742. while (dst0 < dst && dst[-1] != '/')
  743. dst--;
  744. }
  745. *dst = '\0';
  746. /* remove '/' in the end of path if exist */
  747. dst--;
  748. if (dst > fullpath && (*dst == '/'))
  749. *dst = '\0';
  750. /* final check fullpath is not empty, for the special path of lwext "/.." */
  751. if ('\0' == fullpath[0])
  752. {
  753. fullpath[0] = '/';
  754. fullpath[1] = '\0';
  755. }
  756. return fullpath;
  757. }
  758. RTM_EXPORT(dfs_normalize_path);
  759. /**
  760. * This function will get the file descriptor table of current process.
  761. */
  762. struct dfs_fdtable *dfs_fdtable_get(void)
  763. {
  764. struct dfs_fdtable *fdt;
  765. #ifdef RT_USING_SMART
  766. struct rt_lwp *lwp;
  767. lwp = (struct rt_lwp *)rt_thread_self()->lwp;
  768. if (lwp)
  769. fdt = &lwp->fdt;
  770. else
  771. fdt = &_fdtab;
  772. #else
  773. fdt = &_fdtab;
  774. #endif
  775. return fdt;
  776. }
  777. #ifdef RT_USING_SMART
  778. struct dfs_fdtable *dfs_fdtable_get_pid(int pid)
  779. {
  780. struct rt_lwp *lwp = RT_NULL;
  781. struct dfs_fdtable *fdt = RT_NULL;
  782. lwp_pid_lock_take();
  783. lwp = lwp_from_pid_locked(pid);
  784. if (lwp)
  785. {
  786. fdt = &lwp->fdt;
  787. }
  788. lwp_pid_lock_release();
  789. return fdt;
  790. }
  791. #endif
  792. struct dfs_fdtable *dfs_fdtable_get_global(void)
  793. {
  794. return &_fdtab;
  795. }
  796. #ifdef RT_USING_FINSH
  797. int list_fd(void)
  798. {
  799. int index;
  800. struct dfs_fdtable *fd_table;
  801. fd_table = dfs_fdtable_get();
  802. if (!fd_table) return -1;
  803. dfs_lock();
  804. rt_kprintf("fd type ref magic path\n");
  805. rt_kprintf("-- ------ --- ----- ------\n");
  806. for (index = 0; index < (int)fd_table->maxfd; index++)
  807. {
  808. struct dfs_file *fd = fd_table->fds[index];
  809. if (fd && fd->vnode->fops)
  810. {
  811. rt_kprintf("%2d ", index);
  812. if (fd->vnode->type == FT_DIRECTORY) rt_kprintf("%-7.7s ", "dir");
  813. else if (fd->vnode->type == FT_REGULAR) rt_kprintf("%-7.7s ", "file");
  814. else if (fd->vnode->type == FT_SOCKET) rt_kprintf("%-7.7s ", "socket");
  815. else if (fd->vnode->type == FT_USER) rt_kprintf("%-7.7s ", "user");
  816. else if (fd->vnode->type == FT_DEVICE) rt_kprintf("%-7.7s ", "device");
  817. else rt_kprintf("%-8.8s ", "unknown");
  818. rt_kprintf("%3d ", fd->vnode->ref_count);
  819. rt_kprintf("%04x ", fd->magic);
  820. if (fd->vnode->path)
  821. {
  822. rt_kprintf("%s\n", fd->vnode->path);
  823. }
  824. else
  825. {
  826. rt_kprintf("\n");
  827. }
  828. }
  829. }
  830. dfs_unlock();
  831. return 0;
  832. }
  833. #ifdef RT_USING_SMART
  834. static int lsofp(int pid)
  835. {
  836. int index;
  837. struct dfs_fdtable *fd_table = RT_NULL;
  838. if (pid == (-1))
  839. {
  840. fd_table = dfs_fdtable_get();
  841. if (!fd_table) return -1;
  842. }
  843. else
  844. {
  845. fd_table = dfs_fdtable_get_pid(pid);
  846. if (!fd_table)
  847. {
  848. rt_kprintf("PID %s is not a applet(lwp)\n", pid);
  849. return -1;
  850. }
  851. }
  852. rt_kprintf("--- -- ------ ------ ----- ---------- ---------- ---------- ------\n");
  853. rt_enter_critical();
  854. for (index = 0; index < (int)fd_table->maxfd; index++)
  855. {
  856. struct dfs_file *fd = fd_table->fds[index];
  857. if (fd && fd->vnode->fops)
  858. {
  859. if(pid == (-1))
  860. {
  861. rt_kprintf(" K ");
  862. }
  863. else
  864. {
  865. rt_kprintf("%3d ", pid);
  866. }
  867. rt_kprintf("%2d ", index);
  868. if (fd->vnode->type == FT_DIRECTORY) rt_kprintf("%-7.7s ", "dir");
  869. else if (fd->vnode->type == FT_REGULAR) rt_kprintf("%-7.7s ", "file");
  870. else if (fd->vnode->type == FT_SOCKET) rt_kprintf("%-7.7s ", "socket");
  871. else if (fd->vnode->type == FT_USER) rt_kprintf("%-7.7s ", "user");
  872. else if (fd->vnode->type == FT_DEVICE) rt_kprintf("%-7.7s ", "device");
  873. else rt_kprintf("%-8.8s ", "unknown");
  874. rt_kprintf("%6d ", fd->vnode->ref_count);
  875. rt_kprintf("%04x 0x%.8x ", fd->magic, (int)(size_t)fd->vnode);
  876. if(fd->vnode == RT_NULL)
  877. {
  878. rt_kprintf("0x%.8x 0x%.8x ", (int)0x00000000, (int)(size_t)fd);
  879. }
  880. else
  881. {
  882. rt_kprintf("0x%.8x 0x%.8x ", (int)(size_t)(fd->vnode->data), (int)(size_t)fd);
  883. }
  884. if (fd->vnode->path)
  885. {
  886. rt_kprintf("%s \n", fd->vnode->path);
  887. }
  888. else
  889. {
  890. rt_kprintf("\n");
  891. }
  892. }
  893. }
  894. rt_exit_critical();
  895. return 0;
  896. }
  897. int lsof(int argc, char *argv[])
  898. {
  899. rt_kprintf("PID fd type fd-ref magic vnode vnode/data addr path \n");
  900. if (argc == 1)
  901. {
  902. struct rt_list_node *node, *list;
  903. struct lwp_avl_struct *pids = lwp_get_pid_ary();
  904. lsofp(-1);
  905. for (int index = 0; index < RT_LWP_MAX_NR; index++)
  906. {
  907. struct rt_lwp *lwp = (struct rt_lwp *)pids[index].data;
  908. if (lwp)
  909. {
  910. list = &lwp->t_grp;
  911. for (node = list->next; node != list; node = node->next)
  912. {
  913. lsofp(lwp_to_pid(lwp));
  914. }
  915. }
  916. }
  917. }
  918. else if (argc == 3)
  919. {
  920. if (argv[1][0] == '-' && argv[1][1] == 'p')
  921. {
  922. int pid = atoi(argv[2]);
  923. lsofp(pid);
  924. }
  925. }
  926. return 0;
  927. }
  928. MSH_CMD_EXPORT(lsof, list open files);
  929. #endif /* RT_USING_SMART */
  930. #endif
  931. /**@}*/