fs.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /*
  2. * Copyright (c) 2009 Travis Geiselbrecht
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining
  5. * a copy of this software and associated documentation files
  6. * (the "Software"), to deal in the Software without restriction,
  7. * including without limitation the rights to use, copy, modify, merge,
  8. * publish, distribute, sublicense, and/or sell copies of the Software,
  9. * and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  18. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  19. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  20. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  21. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. #include <debug.h>
  24. #include <list.h>
  25. #include <err.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <lib/fs.h>
  29. #include <lib/bio.h>
  30. #if WITH_LIB_FS_EXT2
  31. #include <lib/fs/ext2.h>
  32. #endif
  33. #if WITH_LIB_FS_FAT32
  34. #include <lib/fs/fat32.h>
  35. #endif
  36. #define LOCAL_TRACE 0
  37. struct fs_type {
  38. const char *name;
  39. int (*mount)(bdev_t *, fscookie *);
  40. int (*unmount)(fscookie);
  41. int (*open)(fscookie, const char *, filecookie *);
  42. int (*create)(fscookie, const char *, filecookie *);
  43. int (*mkdir)(fscookie, const char *);
  44. int (*stat)(filecookie, struct file_stat *);
  45. int (*read)(filecookie, void *, off_t, size_t);
  46. int (*write)(filecookie, const void *, off_t, size_t);
  47. int (*close)(filecookie);
  48. };
  49. struct fs_mount {
  50. struct list_node node;
  51. char *path;
  52. bdev_t *dev;
  53. fscookie cookie;
  54. int refs;
  55. struct fs_type *type;
  56. };
  57. struct fs_file {
  58. filecookie cookie;
  59. struct fs_mount *mount;
  60. };
  61. static struct list_node mounts;
  62. static struct fs_type types[] = {
  63. #if WITH_LIB_FS_EXT2
  64. {
  65. .name = "ext2",
  66. .mount = ext2_mount,
  67. .unmount = ext2_unmount,
  68. .open = ext2_open_file,
  69. .stat = ext2_stat_file,
  70. .read = ext2_read_file,
  71. .close = ext2_close_file,
  72. },
  73. #endif
  74. #if WITH_LIB_FS_FAT32
  75. {
  76. .name = "fat32",
  77. .mount = fat32_mount,
  78. .unmount = fat32_unmount,
  79. .open = fat32_open_file,
  80. .create = fat32_create_file,
  81. .mkdir = fat32_make_dir,
  82. .stat = fat32_stat_file,
  83. .read = fat32_read_file,
  84. .write = fat32_write_file,
  85. .close = fat32_close_file,
  86. },
  87. #endif
  88. };
  89. static void test_normalize(const char *in);
  90. static struct fs_mount *find_mount(const char *path, const char **trimmed_path);
  91. void fs_init(void)
  92. {
  93. list_initialize(&mounts);
  94. #if 0
  95. test_normalize("/");
  96. test_normalize("/test");
  97. test_normalize("/test/");
  98. test_normalize("test/");
  99. test_normalize("test");
  100. test_normalize("/test//");
  101. test_normalize("/test/foo");
  102. test_normalize("/test/foo/");
  103. test_normalize("/test/foo/bar");
  104. test_normalize("/test/foo/bar//");
  105. test_normalize("/test//foo/bar//");
  106. test_normalize("/test//./foo/bar//");
  107. test_normalize("/test//./.foo/bar//");
  108. test_normalize("/test//./..foo/bar//");
  109. test_normalize("/test//./../foo/bar//");
  110. test_normalize("/test/../foo");
  111. test_normalize("/test/bar/../foo");
  112. test_normalize("../foo");
  113. test_normalize("../foo/");
  114. test_normalize("/../foo");
  115. test_normalize("/../foo/");
  116. test_normalize("/../../foo");
  117. test_normalize("/bleh/../../foo");
  118. test_normalize("/bleh/bar/../../foo");
  119. test_normalize("/bleh/bar/../../foo/..");
  120. test_normalize("/bleh/bar/../../foo/../meh");
  121. #endif
  122. }
  123. static struct fs_mount *find_mount(const char *path, const char **trimmed_path)
  124. {
  125. struct fs_mount *mount;
  126. size_t pathlen = strlen(path);
  127. list_for_every_entry(&mounts, mount, struct fs_mount, node) {
  128. size_t mountpathlen = strlen(mount->path);
  129. if (pathlen < mountpathlen)
  130. continue;
  131. LTRACEF("comparing %s with %s\n", path, mount->path);
  132. if (memcmp(path, mount->path, mountpathlen) == 0) {
  133. if (trimmed_path)
  134. *trimmed_path = &path[mountpathlen];
  135. return mount;
  136. }
  137. }
  138. return NULL;
  139. }
  140. static int mount(const char *path, const char *device, struct fs_type *type)
  141. {
  142. char temppath[512];
  143. strlcpy(temppath, path, sizeof(temppath));
  144. fs_normalize_path(temppath);
  145. if(temppath[0] != '/')
  146. return ERR_BAD_PATH;
  147. if (find_mount(temppath, NULL))
  148. return ERR_ALREADY_MOUNTED;
  149. bdev_t *dev = bio_open(device);
  150. if (!dev)
  151. return ERR_NOT_FOUND;
  152. fscookie cookie;
  153. int err = type->mount(dev, &cookie);
  154. if (err < 0) {
  155. bio_close(dev);
  156. return err;
  157. }
  158. /* create the mount structure and add it to the list */
  159. struct fs_mount *mount = malloc(sizeof(struct fs_mount));
  160. mount->path = strdup(temppath);
  161. mount->dev = dev;
  162. mount->cookie = cookie;
  163. mount->refs = 1;
  164. mount->type = type;
  165. list_add_head(&mounts, &mount->node);
  166. return 0;
  167. }
  168. int fs_mount(const char *path, const char *device)
  169. {
  170. return mount(path, device, &types[0]);
  171. }
  172. int fs_mount_type(const char *path, const char *device, const char *name)
  173. {
  174. size_t i;
  175. for (i = 0; i < countof(types); i++) {
  176. if (!strcmp(name, types[i].name))
  177. return mount(path, device, &types[i]);
  178. }
  179. return ERR_NOT_FOUND;
  180. }
  181. static void put_mount(struct fs_mount *mount)
  182. {
  183. if (!(--mount->refs)) {
  184. list_delete(&mount->node);
  185. mount->type->unmount(mount->cookie);
  186. free(mount->path);
  187. bio_close(mount->dev);
  188. free(mount);
  189. }
  190. }
  191. int fs_unmount(const char *path)
  192. {
  193. char temppath[512];
  194. strlcpy(temppath, path, sizeof(temppath));
  195. fs_normalize_path(temppath);
  196. struct fs_mount *mount = find_mount(temppath, NULL);
  197. if (!mount)
  198. return ERR_NOT_FOUND;
  199. put_mount(mount);
  200. return 0;
  201. }
  202. int fs_open_file(const char *path, filecookie *fcookie)
  203. {
  204. int err;
  205. char temppath[512];
  206. filecookie cookie;
  207. strlcpy(temppath, path, sizeof(temppath));
  208. fs_normalize_path(temppath);
  209. LTRACEF("path %s temppath %s\n", path, temppath);
  210. const char *newpath;
  211. struct fs_mount *mount = find_mount(temppath, &newpath);
  212. if (!mount)
  213. return ERR_NOT_FOUND;
  214. LTRACEF("path %s temppath %s newpath %s\n", path, temppath, newpath);
  215. err = mount->type->open(mount->cookie, newpath, &cookie);
  216. if (err < 0)
  217. return err;
  218. struct fs_file *f = malloc(sizeof(*f));
  219. f->cookie = cookie;
  220. f->mount = mount;
  221. mount->refs++;
  222. *fcookie = f;
  223. return 0;
  224. }
  225. int fs_create_file(const char *path, filecookie *fcookie)
  226. {
  227. int err;
  228. char temppath[512];
  229. filecookie cookie;
  230. strlcpy(temppath, path, sizeof(temppath));
  231. fs_normalize_path(temppath);
  232. const char *newpath;
  233. struct fs_mount *mount = find_mount(temppath, &newpath);
  234. if (!mount)
  235. return ERR_NOT_FOUND;
  236. if (!mount->type->create)
  237. return ERR_NOT_SUPPORTED;
  238. err = mount->type->create(mount->cookie, newpath, &cookie);
  239. if (err < 0)
  240. return err;
  241. struct fs_file *f = malloc(sizeof(*f));
  242. f->cookie = cookie;
  243. f->mount = mount;
  244. mount->refs++;
  245. *fcookie = f;
  246. return 0;
  247. }
  248. int fs_make_dir(const char *path)
  249. {
  250. char temppath[512];
  251. strlcpy(temppath, path, sizeof(temppath));
  252. fs_normalize_path(temppath);
  253. const char *newpath;
  254. struct fs_mount *mount = find_mount(temppath, &newpath);
  255. if (!mount)
  256. return ERR_NOT_FOUND;
  257. if (!mount->type->mkdir)
  258. return ERR_NOT_SUPPORTED;
  259. return mount->type->mkdir(mount->cookie, newpath);
  260. }
  261. int fs_read_file(filecookie fcookie, void *buf, off_t offset, size_t len)
  262. {
  263. struct fs_file *f = fcookie;
  264. return f->mount->type->read(f->cookie, buf, offset, len);
  265. }
  266. int fs_write_file(filecookie fcookie, const void *buf, off_t offset, size_t len)
  267. {
  268. struct fs_file *f = fcookie;
  269. if (!f->mount->type->write)
  270. return ERR_NOT_SUPPORTED;
  271. return f->mount->type->write(f->cookie, buf, offset, len);
  272. }
  273. int fs_close_file(filecookie fcookie)
  274. {
  275. int err;
  276. struct fs_file *f = fcookie;
  277. err = f->mount->type->close(f->cookie);
  278. if (err < 0)
  279. return err;
  280. put_mount(f->mount);
  281. free(f);
  282. return 0;
  283. }
  284. int fs_stat_file(filecookie fcookie, struct file_stat *stat)
  285. {
  286. struct fs_file *f = fcookie;
  287. return f->mount->type->stat(f->cookie, stat);
  288. }
  289. ssize_t fs_load_file(const char *path, void *ptr, size_t maxlen)
  290. {
  291. int err;
  292. filecookie cookie;
  293. /* open the file */
  294. err = fs_open_file(path, &cookie);
  295. if (err < 0)
  296. return err;
  297. /* stat it for size, see how much we need to read */
  298. struct file_stat stat;
  299. fs_stat_file(cookie, &stat);
  300. err = fs_read_file(cookie, ptr, 0, MIN(maxlen, stat.size));
  301. fs_close_file(cookie);
  302. return err;
  303. }
  304. static void test_normalize(const char *in)
  305. {
  306. char path[1024];
  307. strlcpy(path, in, sizeof(path));
  308. fs_normalize_path(path);
  309. printf("'%s' -> '%s'\n", in, path);
  310. }
  311. void fs_normalize_path(char *path)
  312. {
  313. int outpos;
  314. int pos;
  315. char c;
  316. bool done;
  317. enum {
  318. INITIAL,
  319. FIELD_START,
  320. IN_FIELD,
  321. SEP,
  322. SEEN_SEP,
  323. DOT,
  324. SEEN_DOT,
  325. DOTDOT,
  326. SEEN_DOTDOT,
  327. } state;
  328. state = INITIAL;
  329. pos = 0;
  330. outpos = 0;
  331. done = false;
  332. /* remove duplicate path seperators, flatten empty fields (only composed of .), backtrack fields with .., remove trailing slashes */
  333. while (!done) {
  334. c = path[pos];
  335. switch (state) {
  336. case INITIAL:
  337. if (c == '/') {
  338. state = SEP;
  339. } else if (c == '.') {
  340. state = DOT;
  341. } else {
  342. state = FIELD_START;
  343. }
  344. break;
  345. case FIELD_START:
  346. if (c == '.') {
  347. state = DOT;
  348. } else if (c == 0) {
  349. done = true;
  350. } else {
  351. state = IN_FIELD;
  352. }
  353. break;
  354. case IN_FIELD:
  355. if (c == '/') {
  356. state = SEP;
  357. } else if (c == 0) {
  358. done = true;
  359. } else {
  360. path[outpos++] = c;
  361. pos++;
  362. }
  363. break;
  364. case SEP:
  365. pos++;
  366. path[outpos++] = '/';
  367. state = SEEN_SEP;
  368. break;
  369. case SEEN_SEP:
  370. if (c == '/') {
  371. // eat it
  372. pos++;
  373. } else if (c == 0) {
  374. done = true;
  375. } else {
  376. state = FIELD_START;
  377. }
  378. break;
  379. case DOT:
  380. pos++; // consume the dot
  381. state = SEEN_DOT;
  382. break;
  383. case SEEN_DOT:
  384. if (c == '.') {
  385. // dotdot now
  386. state = DOTDOT;
  387. } else if (c == '/') {
  388. // a field composed entirely of a .
  389. // consume the / and move directly to the SEEN_SEP state
  390. pos++;
  391. state = SEEN_SEP;
  392. } else if (c == 0) {
  393. done = true;
  394. } else {
  395. // a field prefixed with a .
  396. // emit a . and move directly into the IN_FIELD state
  397. path[outpos++] = '.';
  398. state = IN_FIELD;
  399. }
  400. break;
  401. case DOTDOT:
  402. pos++; // consume the dot
  403. state = SEEN_DOTDOT;
  404. break;
  405. case SEEN_DOTDOT:
  406. if (c == '/' || c == 0) {
  407. // a field composed entirely of '..'
  408. // search back and consume a field we've already emitted
  409. if (outpos > 0) {
  410. // we have already consumed at least one field
  411. outpos--;
  412. // walk backwards until we find the next field boundary
  413. while (outpos > 0) {
  414. if (path[outpos - 1] == '/') {
  415. break;
  416. }
  417. outpos--;
  418. }
  419. }
  420. pos++;
  421. state = SEEN_SEP;
  422. if (c == 0)
  423. done = true;
  424. } else {
  425. // a field prefixed with ..
  426. // emit the .. and move directly to the IN_FIELD state
  427. path[outpos++] = '.';
  428. path[outpos++] = '.';
  429. state = IN_FIELD;
  430. }
  431. break;
  432. }
  433. }
  434. /* dont end with trailing slashes */
  435. if (outpos > 0 && path[outpos - 1] == '/')
  436. outpos--;
  437. path[outpos++] = 0;
  438. }