dfs_file.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  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. * 2011-12-08 Bernard Merges rename patch from iamcacy.
  10. * 2015-05-27 Bernard Fix the fd clear issue.
  11. */
  12. #include <dfs.h>
  13. #include <dfs_file.h>
  14. #include <dfs_private.h>
  15. /**
  16. * @addtogroup FileApi
  17. */
  18. /*@{*/
  19. /**
  20. * this function will open a file which specified by path with specified flags.
  21. *
  22. * @param fd the file descriptor pointer to return the corresponding result.
  23. * @param path the specified file path.
  24. * @param flags the flags for open operator.
  25. *
  26. * @return 0 on successful, -1 on failed.
  27. */
  28. int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
  29. {
  30. struct dfs_filesystem *fs;
  31. char *fullpath;
  32. int result;
  33. /* parameter check */
  34. if (fd == NULL)
  35. return -EINVAL;
  36. /* make sure we have an absolute path */
  37. fullpath = dfs_normalize_path(NULL, path);
  38. if (fullpath == NULL)
  39. {
  40. return -ENOMEM;
  41. }
  42. LOG_D("open file:%s", fullpath);
  43. /* Check whether file is already open */
  44. if (fd_is_open(fullpath) == 0)
  45. {
  46. rt_free(fullpath); /* release path */
  47. return -EBUSY;
  48. }
  49. /* find filesystem */
  50. fs = dfs_filesystem_lookup(fullpath);
  51. if (fs == NULL)
  52. {
  53. rt_free(fullpath); /* release path */
  54. return -ENOENT;
  55. }
  56. LOG_D("open in filesystem:%s", fs->ops->name);
  57. fd->fops = fs->ops->fops; /* set file ops */
  58. /* initialize the fd item */
  59. fd->type = FT_REGULAR;
  60. fd->flags = flags;
  61. fd->size = 0;
  62. fd->pos = 0;
  63. fd->data = fs;
  64. if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
  65. {
  66. if (dfs_subdir(fs->path, fullpath) == NULL)
  67. fd->path = rt_strdup("/");
  68. else
  69. fd->path = rt_strdup(dfs_subdir(fs->path, fullpath));
  70. rt_free(fullpath);
  71. LOG_D("Actual file path: %s", fd->path);
  72. }
  73. else
  74. {
  75. fd->path = fullpath;
  76. }
  77. /* specific file system open routine */
  78. if (fd->fops->open == NULL)
  79. {
  80. /* clear fd */
  81. rt_free(fd->path);
  82. fd->path = NULL;
  83. return -ENOSYS;
  84. }
  85. if ((result = fd->fops->open(fd)) < 0)
  86. {
  87. /* clear fd */
  88. rt_free(fd->path);
  89. fd->path = NULL;
  90. LOG_E("open failed");
  91. return result;
  92. }
  93. fd->flags |= DFS_F_OPEN;
  94. if (flags & O_DIRECTORY)
  95. {
  96. fd->type = FT_DIRECTORY;
  97. fd->flags |= DFS_F_DIRECTORY;
  98. }
  99. LOG_I("open successful");
  100. return 0;
  101. }
  102. /**
  103. * this function will close a file descriptor.
  104. *
  105. * @param fd the file descriptor to be closed.
  106. *
  107. * @return 0 on successful, -1 on failed.
  108. */
  109. int dfs_file_close(struct dfs_fd *fd)
  110. {
  111. int result = 0;
  112. if (fd == NULL)
  113. return -ENXIO;
  114. if (fd->fops->close != NULL)
  115. result = fd->fops->close(fd);
  116. /* close fd error, return */
  117. if (result < 0)
  118. return result;
  119. rt_free(fd->path);
  120. fd->path = NULL;
  121. return result;
  122. }
  123. /**
  124. * this function will perform a io control on a file descriptor.
  125. *
  126. * @param fd the file descriptor.
  127. * @param cmd the command to send to file descriptor.
  128. * @param args the argument to send to file descriptor.
  129. *
  130. * @return 0 on successful, -1 on failed.
  131. */
  132. int dfs_file_ioctl(struct dfs_fd *fd, int cmd, void *args)
  133. {
  134. if (fd == NULL)
  135. return -EINVAL;
  136. /* regular file system fd */
  137. if (fd->type == FT_REGULAR)
  138. {
  139. switch (cmd)
  140. {
  141. case F_GETFL:
  142. return fd->flags; /* return flags */
  143. case F_SETFL:
  144. {
  145. int flags = (int)args;
  146. int mask = O_NONBLOCK | O_APPEND;
  147. flags &= mask;
  148. fd->flags &= ~mask;
  149. fd->flags |= flags;
  150. }
  151. return 0;
  152. }
  153. }
  154. if (fd->fops->ioctl != NULL)
  155. return fd->fops->ioctl(fd, cmd, args);
  156. return -ENOSYS;
  157. }
  158. /**
  159. * this function will read specified length data from a file descriptor to a
  160. * buffer.
  161. *
  162. * @param fd the file descriptor.
  163. * @param buf the buffer to save the read data.
  164. * @param len the length of data buffer to be read.
  165. *
  166. * @return the actual read data bytes or 0 on end of file or failed.
  167. */
  168. int dfs_file_read(struct dfs_fd *fd, void *buf, size_t len)
  169. {
  170. int result = 0;
  171. if (fd == NULL)
  172. return -EINVAL;
  173. if (fd->fops->read == NULL)
  174. return -ENOSYS;
  175. if ((result = fd->fops->read(fd, buf, len)) < 0)
  176. fd->flags |= DFS_F_EOF;
  177. return result;
  178. }
  179. /**
  180. * this function will fetch directory entries from a directory descriptor.
  181. *
  182. * @param fd the directory descriptor.
  183. * @param dirp the dirent buffer to save result.
  184. * @param nbytes the available room in the buffer.
  185. *
  186. * @return the read dirent, others on failed.
  187. */
  188. int dfs_file_getdents(struct dfs_fd *fd, struct dirent *dirp, size_t nbytes)
  189. {
  190. /* parameter check */
  191. if (fd == NULL || fd->type != FT_DIRECTORY)
  192. return -EINVAL;
  193. if (fd->fops->getdents != NULL)
  194. return fd->fops->getdents(fd, dirp, nbytes);
  195. return -ENOSYS;
  196. }
  197. /**
  198. * this function will unlink (remove) a specified path file from file system.
  199. *
  200. * @param path the specified path file to be unlinked.
  201. *
  202. * @return 0 on successful, -1 on failed.
  203. */
  204. int dfs_file_unlink(const char *path)
  205. {
  206. int result;
  207. char *fullpath;
  208. struct dfs_filesystem *fs;
  209. /* Make sure we have an absolute path */
  210. fullpath = dfs_normalize_path(NULL, path);
  211. if (fullpath == NULL)
  212. {
  213. return -EINVAL;
  214. }
  215. /* get filesystem */
  216. if ((fs = dfs_filesystem_lookup(fullpath)) == NULL)
  217. {
  218. result = -ENOENT;
  219. goto __exit;
  220. }
  221. /* Check whether file is already open */
  222. if (fd_is_open(fullpath) == 0)
  223. {
  224. result = -EBUSY;
  225. goto __exit;
  226. }
  227. if (fs->ops->unlink != NULL)
  228. {
  229. if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
  230. {
  231. if (dfs_subdir(fs->path, fullpath) == NULL)
  232. result = fs->ops->unlink(fs, "/");
  233. else
  234. result = fs->ops->unlink(fs, dfs_subdir(fs->path, fullpath));
  235. }
  236. else
  237. result = fs->ops->unlink(fs, fullpath);
  238. }
  239. else result = -ENOSYS;
  240. __exit:
  241. rt_free(fullpath);
  242. return result;
  243. }
  244. /**
  245. * this function will write some specified length data to file system.
  246. *
  247. * @param fd the file descriptor.
  248. * @param buf the data buffer to be written.
  249. * @param len the data buffer length
  250. *
  251. * @return the actual written data length.
  252. */
  253. int dfs_file_write(struct dfs_fd *fd, const void *buf, size_t len)
  254. {
  255. if (fd == NULL)
  256. return -EINVAL;
  257. if (fd->fops->write == NULL)
  258. return -ENOSYS;
  259. return fd->fops->write(fd, buf, len);
  260. }
  261. /**
  262. * this function will flush buffer on a file descriptor.
  263. *
  264. * @param fd the file descriptor.
  265. *
  266. * @return 0 on successful, -1 on failed.
  267. */
  268. int dfs_file_flush(struct dfs_fd *fd)
  269. {
  270. if (fd == NULL)
  271. return -EINVAL;
  272. if (fd->fops->flush == NULL)
  273. return -ENOSYS;
  274. return fd->fops->flush(fd);
  275. }
  276. /**
  277. * this function will seek the offset for specified file descriptor.
  278. *
  279. * @param fd the file descriptor.
  280. * @param offset the offset to be sought.
  281. *
  282. * @return the current position after seek.
  283. */
  284. int dfs_file_lseek(struct dfs_fd *fd, off_t offset)
  285. {
  286. int result;
  287. if (fd == NULL)
  288. return -EINVAL;
  289. if (fd->fops->lseek == NULL)
  290. return -ENOSYS;
  291. result = fd->fops->lseek(fd, offset);
  292. /* update current position */
  293. if (result >= 0)
  294. fd->pos = result;
  295. return result;
  296. }
  297. /**
  298. * this function will get file information.
  299. *
  300. * @param path the file path.
  301. * @param buf the data buffer to save stat description.
  302. *
  303. * @return 0 on successful, -1 on failed.
  304. */
  305. int dfs_file_stat(const char *path, struct stat *buf)
  306. {
  307. int result;
  308. char *fullpath;
  309. struct dfs_filesystem *fs;
  310. fullpath = dfs_normalize_path(NULL, path);
  311. if (fullpath == NULL)
  312. {
  313. return -1;
  314. }
  315. if ((fs = dfs_filesystem_lookup(fullpath)) == NULL)
  316. {
  317. LOG_E(
  318. "can't find mounted filesystem on this path:%s", fullpath);
  319. rt_free(fullpath);
  320. return -ENOENT;
  321. }
  322. if ((fullpath[0] == '/' && fullpath[1] == '\0') ||
  323. (dfs_subdir(fs->path, fullpath) == NULL))
  324. {
  325. /* it's the root directory */
  326. buf->st_dev = 0;
  327. buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
  328. S_IWUSR | S_IWGRP | S_IWOTH;
  329. buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
  330. buf->st_size = 0;
  331. buf->st_mtime = 0;
  332. /* release full path */
  333. rt_free(fullpath);
  334. return RT_EOK;
  335. }
  336. else
  337. {
  338. if (fs->ops->stat == NULL)
  339. {
  340. rt_free(fullpath);
  341. LOG_E(
  342. "the filesystem didn't implement this function");
  343. return -ENOSYS;
  344. }
  345. /* get the real file path and get file stat */
  346. if (fs->ops->flags & DFS_FS_FLAG_FULLPATH)
  347. result = fs->ops->stat(fs, fullpath, buf);
  348. else
  349. result = fs->ops->stat(fs, dfs_subdir(fs->path, fullpath), buf);
  350. }
  351. rt_free(fullpath);
  352. return result;
  353. }
  354. /**
  355. * this function will rename an old path name to a new path name.
  356. *
  357. * @param oldpath the old path name.
  358. * @param newpath the new path name.
  359. *
  360. * @return 0 on successful, -1 on failed.
  361. */
  362. int dfs_file_rename(const char *oldpath, const char *newpath)
  363. {
  364. int result;
  365. struct dfs_filesystem *oldfs, *newfs;
  366. char *oldfullpath, *newfullpath;
  367. result = RT_EOK;
  368. newfullpath = NULL;
  369. oldfullpath = NULL;
  370. oldfullpath = dfs_normalize_path(NULL, oldpath);
  371. if (oldfullpath == NULL)
  372. {
  373. result = -ENOENT;
  374. goto __exit;
  375. }
  376. newfullpath = dfs_normalize_path(NULL, newpath);
  377. if (newfullpath == NULL)
  378. {
  379. result = -ENOENT;
  380. goto __exit;
  381. }
  382. oldfs = dfs_filesystem_lookup(oldfullpath);
  383. newfs = dfs_filesystem_lookup(newfullpath);
  384. if (oldfs == newfs)
  385. {
  386. if (oldfs->ops->rename == NULL)
  387. {
  388. result = -ENOSYS;
  389. }
  390. else
  391. {
  392. if (oldfs->ops->flags & DFS_FS_FLAG_FULLPATH)
  393. result = oldfs->ops->rename(oldfs, oldfullpath, newfullpath);
  394. else
  395. /* use sub directory to rename in file system */
  396. result = oldfs->ops->rename(oldfs,
  397. dfs_subdir(oldfs->path, oldfullpath),
  398. dfs_subdir(newfs->path, newfullpath));
  399. }
  400. }
  401. else
  402. {
  403. result = -EXDEV;
  404. }
  405. __exit:
  406. rt_free(oldfullpath);
  407. rt_free(newfullpath);
  408. /* not at same file system, return EXDEV */
  409. return result;
  410. }
  411. #ifdef RT_USING_FINSH
  412. #include <finsh.h>
  413. static struct dfs_fd fd;
  414. static struct dirent dirent;
  415. void ls(const char *pathname)
  416. {
  417. struct stat stat;
  418. int length;
  419. char *fullpath, *path;
  420. fullpath = NULL;
  421. if (pathname == NULL)
  422. {
  423. #ifdef DFS_USING_WORKDIR
  424. /* open current working directory */
  425. path = rt_strdup(working_directory);
  426. #else
  427. path = rt_strdup("/");
  428. #endif
  429. if (path == NULL)
  430. return ; /* out of memory */
  431. }
  432. else
  433. {
  434. path = (char *)pathname;
  435. }
  436. /* list directory */
  437. if (dfs_file_open(&fd, path, O_DIRECTORY) == 0)
  438. {
  439. rt_kprintf("Directory %s:\n", path);
  440. do
  441. {
  442. memset(&dirent, 0, sizeof(struct dirent));
  443. length = dfs_file_getdents(&fd, &dirent, sizeof(struct dirent));
  444. if (length > 0)
  445. {
  446. memset(&stat, 0, sizeof(struct stat));
  447. /* build full path for each file */
  448. fullpath = dfs_normalize_path(path, dirent.d_name);
  449. if (fullpath == NULL)
  450. break;
  451. if (dfs_file_stat(fullpath, &stat) == 0)
  452. {
  453. rt_kprintf("%-20s", dirent.d_name);
  454. if (S_ISDIR(stat.st_mode))
  455. {
  456. rt_kprintf("%-25s\n", "<DIR>");
  457. }
  458. else
  459. {
  460. rt_kprintf("%-25lu\n", stat.st_size);
  461. }
  462. }
  463. else
  464. rt_kprintf("BAD file: %s\n", dirent.d_name);
  465. rt_free(fullpath);
  466. }
  467. }while(length > 0);
  468. dfs_file_close(&fd);
  469. }
  470. else
  471. {
  472. rt_kprintf("No such directory\n");
  473. }
  474. if (pathname == NULL)
  475. rt_free(path);
  476. }
  477. FINSH_FUNCTION_EXPORT(ls, list directory contents);
  478. void rm(const char *filename)
  479. {
  480. if (dfs_file_unlink(filename) < 0)
  481. {
  482. rt_kprintf("Delete %s failed\n", filename);
  483. }
  484. }
  485. FINSH_FUNCTION_EXPORT(rm, remove files or directories);
  486. void cat(const char* filename)
  487. {
  488. uint32_t length;
  489. char buffer[81];
  490. if (dfs_file_open(&fd, filename, O_RDONLY) < 0)
  491. {
  492. rt_kprintf("Open %s failed\n", filename);
  493. return;
  494. }
  495. do
  496. {
  497. memset(buffer, 0, sizeof(buffer));
  498. length = dfs_file_read(&fd, buffer, sizeof(buffer)-1 );
  499. if (length > 0)
  500. {
  501. rt_kprintf("%s", buffer);
  502. }
  503. }while (length > 0);
  504. dfs_file_close(&fd);
  505. }
  506. FINSH_FUNCTION_EXPORT(cat, print file);
  507. #define BUF_SZ 4096
  508. static void copyfile(const char *src, const char *dst)
  509. {
  510. struct dfs_fd src_fd;
  511. rt_uint8_t *block_ptr;
  512. rt_int32_t read_bytes;
  513. block_ptr = rt_malloc(BUF_SZ);
  514. if (block_ptr == NULL)
  515. {
  516. rt_kprintf("out of memory\n");
  517. return;
  518. }
  519. if (dfs_file_open(&src_fd, src, O_RDONLY) < 0)
  520. {
  521. rt_free(block_ptr);
  522. rt_kprintf("Read %s failed\n", src);
  523. return;
  524. }
  525. if (dfs_file_open(&fd, dst, O_WRONLY | O_CREAT) < 0)
  526. {
  527. rt_free(block_ptr);
  528. dfs_file_close(&src_fd);
  529. rt_kprintf("Write %s failed\n", dst);
  530. return;
  531. }
  532. do
  533. {
  534. read_bytes = dfs_file_read(&src_fd, block_ptr, BUF_SZ);
  535. if (read_bytes > 0)
  536. {
  537. int length;
  538. length = dfs_file_write(&fd, block_ptr, read_bytes);
  539. if (length != read_bytes)
  540. {
  541. /* write failed. */
  542. rt_kprintf("Write file data failed, errno=%d\n", length);
  543. break;
  544. }
  545. }
  546. } while (read_bytes > 0);
  547. dfs_file_close(&src_fd);
  548. dfs_file_close(&fd);
  549. rt_free(block_ptr);
  550. }
  551. extern int mkdir(const char *path, mode_t mode);
  552. static void copydir(const char * src, const char * dst)
  553. {
  554. struct dirent dirent;
  555. struct stat stat;
  556. int length;
  557. struct dfs_fd cpfd;
  558. if (dfs_file_open(&cpfd, src, O_DIRECTORY) < 0)
  559. {
  560. rt_kprintf("open %s failed\n", src);
  561. return ;
  562. }
  563. do
  564. {
  565. memset(&dirent, 0, sizeof(struct dirent));
  566. length = dfs_file_getdents(&cpfd, &dirent, sizeof(struct dirent));
  567. if (length > 0)
  568. {
  569. char * src_entry_full = NULL;
  570. char * dst_entry_full = NULL;
  571. if (strcmp(dirent.d_name, "..") == 0 || strcmp(dirent.d_name, ".") == 0)
  572. continue;
  573. /* build full path for each file */
  574. if ((src_entry_full = dfs_normalize_path(src, dirent.d_name)) == NULL)
  575. {
  576. rt_kprintf("out of memory!\n");
  577. break;
  578. }
  579. if ((dst_entry_full = dfs_normalize_path(dst, dirent.d_name)) == NULL)
  580. {
  581. rt_kprintf("out of memory!\n");
  582. rt_free(src_entry_full);
  583. break;
  584. }
  585. memset(&stat, 0, sizeof(struct stat));
  586. if (dfs_file_stat(src_entry_full, &stat) != 0)
  587. {
  588. rt_kprintf("open file: %s failed\n", dirent.d_name);
  589. continue;
  590. }
  591. if (S_ISDIR(stat.st_mode))
  592. {
  593. mkdir(dst_entry_full, 0);
  594. copydir(src_entry_full, dst_entry_full);
  595. }
  596. else
  597. {
  598. copyfile(src_entry_full, dst_entry_full);
  599. }
  600. rt_free(src_entry_full);
  601. rt_free(dst_entry_full);
  602. }
  603. }while(length > 0);
  604. dfs_file_close(&cpfd);
  605. }
  606. static const char *_get_path_lastname(const char *path)
  607. {
  608. char * ptr;
  609. if ((ptr = strrchr(path, '/')) == NULL)
  610. return path;
  611. /* skip the '/' then return */
  612. return ++ptr;
  613. }
  614. void copy(const char *src, const char *dst)
  615. {
  616. #define FLAG_SRC_TYPE 0x03
  617. #define FLAG_SRC_IS_DIR 0x01
  618. #define FLAG_SRC_IS_FILE 0x02
  619. #define FLAG_SRC_NON_EXSIT 0x00
  620. #define FLAG_DST_TYPE 0x0C
  621. #define FLAG_DST_IS_DIR 0x04
  622. #define FLAG_DST_IS_FILE 0x08
  623. #define FLAG_DST_NON_EXSIT 0x00
  624. struct stat stat;
  625. uint32_t flag = 0;
  626. /* check the staus of src and dst */
  627. if (dfs_file_stat(src, &stat) < 0)
  628. {
  629. rt_kprintf("copy failed, bad %s\n", src);
  630. return;
  631. }
  632. if (S_ISDIR(stat.st_mode))
  633. flag |= FLAG_SRC_IS_DIR;
  634. else
  635. flag |= FLAG_SRC_IS_FILE;
  636. if (dfs_file_stat(dst, &stat) < 0)
  637. {
  638. flag |= FLAG_DST_NON_EXSIT;
  639. }
  640. else
  641. {
  642. if (S_ISDIR(stat.st_mode))
  643. flag |= FLAG_DST_IS_DIR;
  644. else
  645. flag |= FLAG_DST_IS_FILE;
  646. }
  647. //2. check status
  648. if ((flag & FLAG_SRC_IS_DIR) && (flag & FLAG_DST_IS_FILE))
  649. {
  650. rt_kprintf("cp faild, cp dir to file is not permitted!\n");
  651. return ;
  652. }
  653. //3. do copy
  654. if (flag & FLAG_SRC_IS_FILE)
  655. {
  656. if (flag & FLAG_DST_IS_DIR)
  657. {
  658. char * fdst;
  659. fdst = dfs_normalize_path(dst, _get_path_lastname(src));
  660. if (fdst == NULL)
  661. {
  662. rt_kprintf("out of memory\n");
  663. return;
  664. }
  665. copyfile(src, fdst);
  666. rt_free(fdst);
  667. }
  668. else
  669. {
  670. copyfile(src, dst);
  671. }
  672. }
  673. else //flag & FLAG_SRC_IS_DIR
  674. {
  675. if (flag & FLAG_DST_IS_DIR)
  676. {
  677. char * fdst;
  678. fdst = dfs_normalize_path(dst, _get_path_lastname(src));
  679. if (fdst == NULL)
  680. {
  681. rt_kprintf("out of memory\n");
  682. return;
  683. }
  684. mkdir(fdst, 0);
  685. copydir(src, fdst);
  686. rt_free(fdst);
  687. }
  688. else if ((flag & FLAG_DST_TYPE) == FLAG_DST_NON_EXSIT)
  689. {
  690. mkdir(dst, 0);
  691. copydir(src, dst);
  692. }
  693. else
  694. {
  695. copydir(src, dst);
  696. }
  697. }
  698. }
  699. FINSH_FUNCTION_EXPORT(copy, copy file or dir)
  700. #endif
  701. /* @} */