dfs_file.c 19 KB

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