dfs_win32.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2012-11-27 prife the first version
  9. * 2013-03-03 aozima add dfs_win32_stat st_mtime support.
  10. * 2017-10-20 urey support rt-thread 3.0
  11. */
  12. #include <rtthread.h>
  13. #include <dfs_fs.h>
  14. #include <dfs_file.h>
  15. #include <rtdevice.h>
  16. #include <io.h>
  17. #include <fcntl.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <WinError.h>
  22. #include <windows.h>
  23. /*
  24. * RT-Thread DFS Interface for win-directory as an disk device
  25. */
  26. #define FILE_PATH_MAX 256 /* the longest file path */
  27. #define WIN32_DIRDISK_ROOT "./disk"
  28. typedef struct {
  29. HANDLE handle;
  30. char *start;
  31. char *end;
  32. char *curr;
  33. struct _finddata_t finddata;
  34. } WINDIR;
  35. /* There are so many error codes in windows, you'd better google for details.
  36. * google "System Error Codes (Windows)"
  37. * http://msdn.microsoft.com/ZH-CN/library/windows/desktop/ms681381(v=vs.85).aspx
  38. */
  39. struct _errcode_map
  40. {
  41. rt_uint16_t dfserr;
  42. rt_uint16_t win32err;
  43. };
  44. static const struct _errcode_map errcode_table[] =
  45. {
  46. {ENOENT, ERROR_FILE_NOT_FOUND },
  47. {ENOENT, ERROR_PATH_NOT_FOUND },
  48. {EEXIST, ERROR_FILE_EXISTS },
  49. {EEXIST, ERROR_ALREADY_EXISTS },
  50. {ENOTEMPTY, ERROR_DIR_NOT_EMPTY },
  51. {EBUSY, ERROR_PATH_BUSY },
  52. {EINVAL, ERROR_ACCESS_DENIED },
  53. #if 0 /* TODO: MORE NEED BE ADDED */
  54. {DFS_STATUS_EISDIR, ERROR_FILE_EXISTS },
  55. {DFS_STATUS_ENOTDIR, ERROR_FILE_EXISTS },
  56. {DFS_STATUS_EBADF, ERROR_FILE_EXISTS },
  57. {DFS_STATUS_EBUSY, ERROR_FILE_EXISTS },
  58. {DFS_STATUS_ENOMEM, ERROR_FILE_EXISTS },
  59. {DFS_STATUS_ENOSPC, ERROR_FILE_EXISTS },
  60. #endif
  61. };
  62. static int win32_result_to_dfs(DWORD res)
  63. {
  64. int i;
  65. int err = 0;
  66. for (i = 0; i < sizeof(errcode_table) / sizeof(struct _errcode_map); i++)
  67. {
  68. if (errcode_table[i].win32err == (res & 0xFFFF))
  69. {
  70. err = -errcode_table[i].dfserr;
  71. return err;
  72. }
  73. }
  74. /* unknown error */
  75. rt_kprintf("dfs win32 error not supported yet: %d\n", res);
  76. return -1;
  77. }
  78. static int dfs_win32_mount(
  79. struct dfs_filesystem *fs,
  80. unsigned long rwflag,
  81. const void *data)
  82. {
  83. return 0;
  84. }
  85. static int dfs_win32_unmount(struct dfs_filesystem *fs)
  86. {
  87. return 0;
  88. }
  89. static int dfs_win32_mkfs(rt_device_t devid)
  90. {
  91. return -ENOSYS;
  92. }
  93. static int dfs_win32_statfs(struct dfs_filesystem *fs,
  94. struct statfs *buf)
  95. {
  96. return -ENOSYS;
  97. }
  98. static char *winpath_dirdup(char *des, const char *src)
  99. {
  100. char *path;
  101. int i = 0;
  102. path = rt_malloc(FILE_PATH_MAX);
  103. if (path == RT_NULL)
  104. return RT_NULL;
  105. strcpy(path, des);
  106. strcat(path, src);
  107. while (1)
  108. {
  109. if (path[i] == 0)
  110. break;
  111. if (path[i] == '/')
  112. path[i] = '\\';
  113. i++;
  114. }
  115. return path;
  116. }
  117. /* This function can convert the path in rt-thread/dfs to the path in windows */
  118. char * dfs_win32_dirdup(char * path)
  119. {
  120. char * file_path;
  121. file_path = winpath_dirdup(WIN32_DIRDISK_ROOT, path);
  122. return file_path;
  123. }
  124. static int dfs_win32_open(struct dfs_fd *file)
  125. {
  126. int fd;
  127. uint32_t oflag, mode;
  128. char *file_path;
  129. int res;
  130. oflag = file->flags;
  131. if (oflag & O_DIRECTORY) /* operations about dir */
  132. {
  133. WINDIR *wdirp;
  134. HANDLE handle;
  135. int len;
  136. file_path = winpath_dirdup(WIN32_DIRDISK_ROOT, file->path);
  137. if (oflag & O_CREAT) /* create a dir*/
  138. {
  139. res = CreateDirectory(file_path, NULL);
  140. if (res == 0)
  141. {
  142. rt_free(file_path);
  143. return win32_result_to_dfs(GetLastError());
  144. }
  145. }
  146. len = strlen(file_path);
  147. if (file_path[len - 1] != '\\')
  148. {
  149. file_path[len] = '\\';
  150. file_path[len + 1] = 0;
  151. }
  152. strcat(file_path, "*.*");
  153. /* _findfirst will get '.' */
  154. /* save this pointer,will used by dfs_win32_getdents*/
  155. wdirp = rt_malloc(sizeof(WINDIR));
  156. RT_ASSERT(wdirp != NULL);
  157. if ((handle = _findfirst(file_path, &wdirp->finddata)) == -1)
  158. {
  159. rt_free(wdirp);
  160. rt_free(file_path);
  161. goto __err;
  162. }
  163. len = strlen(wdirp->finddata.name) + 1;
  164. wdirp->handle = handle;
  165. //wdirp->nfiles = 1;
  166. wdirp->start = malloc(len); //not rt_malloc!
  167. wdirp->end = wdirp->curr = wdirp->start;
  168. wdirp->end += len;
  169. rt_strncpy(wdirp->curr, wdirp->finddata.name, len);
  170. file->data = (void *)wdirp;
  171. rt_free(file_path);
  172. return 0;
  173. }
  174. /* regular file operations */
  175. mode = O_BINARY;
  176. if (oflag & O_RDONLY) mode |= O_RDONLY;
  177. if (oflag & O_WRONLY) mode |= O_WRONLY;
  178. if (oflag & O_RDWR) mode |= O_RDWR;
  179. /* Opens the file, if it is existing. If not, a new file is created. */
  180. if (oflag & O_CREAT) mode |= O_CREAT;
  181. /* Creates a new file. If the file is existing, it is truncated and overwritten. */
  182. if (oflag & O_TRUNC) mode |= O_TRUNC;
  183. /* Creates a new file. The function fails if the file is already existing. */
  184. if (oflag & O_EXCL) mode |= O_EXCL;
  185. file_path = winpath_dirdup(WIN32_DIRDISK_ROOT, file->path);
  186. fd = _open(file_path, mode, 0x0100 | 0x0080); /* _S_IREAD | _S_IWRITE */
  187. rt_free(file_path);
  188. if (fd < 0)
  189. goto __err;
  190. /* save this pointer, it will be used when calling read(), write(),
  191. * flush(), seek(), and will be free when calling close()*/
  192. file->data = (void *)fd;
  193. file->pos = 0;
  194. file->size = _lseek(fd, 0, SEEK_END);
  195. if (oflag & O_APPEND)
  196. {
  197. file->pos = file->size;
  198. }
  199. else
  200. _lseek(fd, 0, SEEK_SET);
  201. return 0;
  202. __err:
  203. res = GetLastError();
  204. return win32_result_to_dfs(res);
  205. }
  206. static int dfs_win32_close(struct dfs_fd *file)
  207. {
  208. if (file->flags & O_DIRECTORY)
  209. {
  210. WINDIR *wdirp = (WINDIR*)(file->data);
  211. RT_ASSERT(wdirp != RT_NULL);
  212. if (_findclose((intptr_t)wdirp->handle) == 0) {
  213. free(wdirp->start); /* NOTE: here we don't use rt_free! */
  214. rt_free(wdirp);
  215. return 0;
  216. }
  217. }
  218. else /* regular file operations */
  219. {
  220. if (_close((int)(file->data)) == 0)
  221. return 0;
  222. }
  223. return win32_result_to_dfs(GetLastError());
  224. }
  225. static int dfs_win32_ioctl(struct dfs_fd *file, int cmd, void *args)
  226. {
  227. return -ENOSYS;
  228. }
  229. static int dfs_win32_read(struct dfs_fd *file, void *buf, size_t len)
  230. {
  231. int fd;
  232. int char_read;
  233. fd = (int)(file->data);
  234. char_read = _read(fd, buf, len);
  235. if (char_read < 0)
  236. return win32_result_to_dfs(GetLastError());
  237. /* update position */
  238. file->pos = _lseek(fd, 0, SEEK_CUR);
  239. return char_read;
  240. }
  241. static int dfs_win32_write(struct dfs_fd *file, const void *buf, size_t len)
  242. {
  243. int fd;
  244. int char_write;
  245. fd = (int)(file->data);
  246. char_write = _write(fd, buf, len);
  247. if (char_write < 0)
  248. return win32_result_to_dfs(GetLastError());
  249. /* update position */
  250. file->pos = _lseek(fd, 0, SEEK_CUR);
  251. return char_write;
  252. }
  253. static int dfs_win32_flush(struct dfs_fd *file)
  254. {
  255. return 0;
  256. }
  257. static int dfs_win32_seek(struct dfs_fd *file,
  258. rt_off_t offset)
  259. {
  260. int result;
  261. /* set offset as current offset */
  262. if (file->type == FT_DIRECTORY)
  263. {
  264. WINDIR* wdirp = (WINDIR*)(file->data);
  265. RT_ASSERT(wdirp != RT_NULL);
  266. wdirp->curr = wdirp->start + offset;
  267. return offset;
  268. }
  269. else //file->type == FT_REGULAR)
  270. {
  271. result = _lseek((int)(file->data), offset, SEEK_SET);
  272. if (result >= 0)
  273. return offset;
  274. else
  275. return win32_result_to_dfs(GetLastError());
  276. }
  277. }
  278. /* return the size of struct dirent*/
  279. static int dfs_win32_getdents(struct dfs_fd *file, struct dirent *dirp, rt_uint32_t count)
  280. {
  281. WINDIR *wdirp;
  282. struct dirent *d = dirp;
  283. int result;
  284. /* make integer count */
  285. if (count / sizeof(struct dirent) != 1)
  286. return -EINVAL;
  287. wdirp = (WINDIR*)(file->data);
  288. RT_ASSERT(wdirp != RT_NULL);
  289. if (wdirp->curr == NULL) //no more entries in this directory
  290. return 0;
  291. /* get the current entry */
  292. if (wdirp->finddata.attrib & _A_SUBDIR)
  293. d->d_type = DT_DIR;
  294. else
  295. d->d_type = DT_REG;
  296. d->d_namlen = strlen(wdirp->curr);
  297. strncpy(d->d_name, wdirp->curr, DFS_PATH_MAX);
  298. d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
  299. wdirp->curr += (strlen(wdirp->curr) + 1);
  300. file->pos = wdirp->curr - wdirp->start + sizeof(struct dirent);//NOTE!
  301. /* now set up for the next call to readdir */
  302. if (wdirp->curr >= wdirp->end)
  303. {
  304. if (_findnext(wdirp->handle, &wdirp->finddata) == 0)
  305. {
  306. char* old_start = wdirp->start;
  307. long name_len = strlen(wdirp->finddata.name) + 1;
  308. wdirp->start = realloc(wdirp->start, wdirp->end - wdirp->start + name_len);
  309. wdirp->curr = wdirp->start + (wdirp->curr - old_start);
  310. wdirp->end = wdirp->curr + name_len;
  311. rt_strcpy(wdirp->curr, wdirp->finddata.name);
  312. }
  313. else
  314. {
  315. if ((result = GetLastError()) == ERROR_NO_MORE_FILES)
  316. wdirp->curr = NULL;
  317. else
  318. return win32_result_to_dfs(result);
  319. }
  320. }
  321. return sizeof(struct dirent);
  322. }
  323. static int dfs_win32_unlink(struct dfs_filesystem *fs, const char *path)
  324. {
  325. int result;
  326. char *fp;
  327. fp = winpath_dirdup(WIN32_DIRDISK_ROOT, path);
  328. if (fp == RT_NULL)
  329. {
  330. rt_kprintf("out of memory.\n");
  331. return -ENOMEM;
  332. }
  333. result = GetFileAttributes(fp);
  334. if (result == INVALID_FILE_ATTRIBUTES)
  335. goto __err;
  336. if (result & FILE_ATTRIBUTE_DIRECTORY)//winnt.h
  337. {
  338. if (RemoveDirectory(fp) == RT_FALSE)
  339. goto __err;
  340. }
  341. else //(result & FILE_ATTRIBUTE_NORMAL)
  342. {
  343. if (_unlink(fp) < 0)
  344. goto __err;
  345. }
  346. rt_free(fp);
  347. return 0;
  348. __err:
  349. rt_free(fp);
  350. return win32_result_to_dfs(GetLastError());
  351. }
  352. static int dfs_win32_rename(
  353. struct dfs_filesystem *fs,
  354. const char *oldpath,
  355. const char *newpath)
  356. {
  357. int result;
  358. char *op, *np;
  359. op = winpath_dirdup(WIN32_DIRDISK_ROOT, oldpath);
  360. np = winpath_dirdup(WIN32_DIRDISK_ROOT, newpath);
  361. if (op == RT_NULL || np == RT_NULL)
  362. {
  363. rt_kprintf("out of memory.\n");
  364. return -ENOMEM;
  365. }
  366. /* If the function fails, the return value is zero. */
  367. result = MoveFile(op, np);
  368. rt_free(op);
  369. rt_free(np);
  370. if (result == 0)
  371. return win32_result_to_dfs(GetLastError());
  372. return 0;
  373. }
  374. static int dfs_win32_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
  375. {
  376. WIN32_FIND_DATA fileInfo;
  377. HANDLE hFind;
  378. char *fp;
  379. fp = winpath_dirdup(WIN32_DIRDISK_ROOT, path);
  380. if (fp == RT_NULL)
  381. {
  382. rt_kprintf("out of memory.\n");
  383. return -ENOMEM;
  384. }
  385. hFind = FindFirstFile(fp, &fileInfo);
  386. rt_free(fp);
  387. if (hFind == INVALID_HANDLE_VALUE)
  388. goto __err;
  389. st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
  390. S_IWUSR | S_IWGRP | S_IWOTH;
  391. /* convert file info to dfs stat structure */
  392. if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  393. {
  394. st->st_mode &= ~S_IFREG;
  395. st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
  396. }
  397. st->st_dev = 0;
  398. st->st_size = fileInfo.nFileSizeLow;
  399. /* get st_mtime. */
  400. {
  401. LARGE_INTEGER time_tmp;
  402. time_tmp.LowPart = fileInfo.ftLastWriteTime.dwLowDateTime;
  403. time_tmp.HighPart = fileInfo.ftLastWriteTime.dwHighDateTime;
  404. /* removes the diff between 1970 and 1601. */
  405. time_tmp.QuadPart -= 11644473600000 * 10000;
  406. /* converts back from 100-nanoseconds to seconds. */
  407. time_tmp.QuadPart /= 10UL * 1000 * 1000;
  408. st->st_mtime = time_tmp.QuadPart;
  409. }
  410. FindClose(hFind);
  411. return 0;
  412. __err:
  413. return win32_result_to_dfs(GetLastError());
  414. }
  415. static const struct dfs_file_ops dfs_win32_file_ops =
  416. {
  417. dfs_win32_open,
  418. dfs_win32_close,
  419. dfs_win32_ioctl,
  420. dfs_win32_read,
  421. dfs_win32_write,
  422. dfs_win32_flush,
  423. dfs_win32_seek,
  424. dfs_win32_getdents,
  425. };
  426. static const struct dfs_filesystem_ops dfs_win32_ops =
  427. {
  428. "wdir", /* file system type: dir */
  429. DFS_FS_FLAG_DEFAULT,
  430. &dfs_win32_file_ops,
  431. dfs_win32_mount,
  432. dfs_win32_unmount,
  433. dfs_win32_mkfs,
  434. dfs_win32_statfs,
  435. dfs_win32_unlink,
  436. dfs_win32_stat,
  437. dfs_win32_rename,
  438. };
  439. int dfs_win32_init(void)
  440. {
  441. /* register uffs file system */
  442. dfs_register(&dfs_win32_ops);
  443. return 0;
  444. }
  445. static rt_err_t nop_init(rt_device_t dev)
  446. {
  447. return RT_EOK;
  448. }
  449. static rt_err_t nop_open(rt_device_t dev, rt_uint16_t oflag)
  450. {
  451. return RT_EOK;
  452. }
  453. static rt_err_t nop_close(rt_device_t dev)
  454. {
  455. return RT_EOK;
  456. }
  457. static rt_size_t nop_read(rt_device_t dev,
  458. rt_off_t pos,
  459. void *buffer,
  460. rt_size_t size)
  461. {
  462. return size;
  463. }
  464. static rt_size_t nop_write(rt_device_t dev,
  465. rt_off_t pos,
  466. const void *buffer,
  467. rt_size_t size)
  468. {
  469. return size;
  470. }
  471. static rt_err_t nop_control(rt_device_t dev, int cmd, void *args)
  472. {
  473. return RT_EOK;
  474. }
  475. static struct rt_device win_sharedir_dev;
  476. rt_err_t rt_win_sharedir_init(const char *name)
  477. {
  478. rt_device_t dev;
  479. dev = &win_sharedir_dev;
  480. RT_ASSERT(dev != RT_NULL);
  481. /* set device class and generic device interface */
  482. dev->type = RT_Device_Class_Block;
  483. dev->init = nop_init;
  484. dev->open = nop_open;
  485. dev->read = nop_read;
  486. dev->write = nop_write;
  487. dev->close = nop_close;
  488. dev->control = nop_control;
  489. dev->rx_indicate = RT_NULL;
  490. dev->tx_complete = RT_NULL;
  491. /* register to RT-Thread device system */
  492. return rt_device_register(dev, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
  493. }