vfs.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2011-2014 Kevin Lange
  5. * Copyright (C) 2014 Lioncash
  6. * Copyright (C) 2012 Tianyi Wang
  7. *
  8. * Virtual File System
  9. *
  10. */
  11. #include <kernel/system.h>
  12. #include <kernel/fs.h>
  13. #include <kernel/printf.h>
  14. #include <kernel/list.h>
  15. #include <kernel/process.h>
  16. #include <kernel/logging.h>
  17. #include <kernel/hashmap.h>
  18. #define MAX_SYMLINK_DEPTH 8
  19. #define MAX_SYMLINK_SIZE 4096
  20. tree_t * fs_tree = NULL; /* File system mountpoint tree */
  21. fs_node_t * fs_root = NULL; /* Pointer to the root mount fs_node (must be some form of filesystem, even ramdisk) */
  22. hashmap_t * fs_types = NULL;
  23. int has_permission(fs_node_t * node, int permission_bit) {
  24. if (!node) return 0;
  25. if (current_process->user == 0) {
  26. return 1;
  27. }
  28. uint32_t permissions = node->mask;
  29. uint8_t user_perm = (permissions >> 6) & 07;
  30. //uint8_t group_perm = (permissions >> 3) & 07;
  31. uint8_t other_perm = (permissions) & 07;
  32. if (current_process->user == node->uid) {
  33. return (permission_bit & user_perm);
  34. /* TODO group permissions? */
  35. } else {
  36. return (permission_bit & other_perm);
  37. }
  38. }
  39. static struct dirent * readdir_mapper(fs_node_t *node, uint32_t index) {
  40. tree_node_t * d = (tree_node_t *)node->device;
  41. if (!d) return NULL;
  42. if (index == 0) {
  43. struct dirent * dir = malloc(sizeof(struct dirent));
  44. strcpy(dir->name, ".");
  45. dir->ino = 0;
  46. return dir;
  47. } else if (index == 1) {
  48. struct dirent * dir = malloc(sizeof(struct dirent));
  49. strcpy(dir->name, "..");
  50. dir->ino = 1;
  51. return dir;
  52. }
  53. index -= 2;
  54. unsigned int i = 0;
  55. foreach(child, d->children) {
  56. if (i == index) {
  57. /* Recursively print the children */
  58. tree_node_t * tchild = (tree_node_t *)child->value;
  59. struct vfs_entry * n = (struct vfs_entry *)tchild->value;
  60. struct dirent * dir = malloc(sizeof(struct dirent));
  61. size_t len = strlen(n->name) + 1;
  62. memcpy(&dir->name, n->name, MIN(256, len));
  63. dir->ino = i;
  64. return dir;
  65. }
  66. ++i;
  67. }
  68. return NULL;
  69. }
  70. static fs_node_t * vfs_mapper(void) {
  71. fs_node_t * fnode = malloc(sizeof(fs_node_t));
  72. memset(fnode, 0x00, sizeof(fs_node_t));
  73. fnode->mask = 0666;
  74. fnode->flags = FS_DIRECTORY;
  75. fnode->readdir = readdir_mapper;
  76. return fnode;
  77. }
  78. /**
  79. * selectcheck_fs: Check if a read from this file would block.
  80. */
  81. int selectcheck_fs(fs_node_t * node) {
  82. if (!node) return -1;
  83. if (node->selectcheck) {
  84. return node->selectcheck(node);
  85. }
  86. return -1;
  87. }
  88. /**
  89. * selectwait_fs: Inform a node that it should alert the current_process.
  90. */
  91. int selectwait_fs(fs_node_t * node, void * process) {
  92. if (!node) return -1;
  93. if (node->selectwait) {
  94. return node->selectwait(node, process);
  95. }
  96. return -1;
  97. }
  98. /**
  99. * read_fs: Read a file system node based on its underlying type.
  100. *
  101. * @param node Node to read
  102. * @param offset Offset into the node data to read from
  103. * @param size How much data to read (in bytes)
  104. * @param buffer A buffer to copy of the read data into
  105. * @returns Bytes read
  106. */
  107. uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  108. if (!node) return -1;
  109. if (node->read) {
  110. uint32_t ret = node->read(node, offset, size, buffer);
  111. return ret;
  112. } else {
  113. return -1;
  114. }
  115. }
  116. /**
  117. * write_fs: Write a file system node based on its underlying type.
  118. *
  119. * @param node Node to write to
  120. * @param offset Offset into the node data to write to
  121. * @param size How much data to write (in bytes)
  122. * @param buffer A buffer to copy from
  123. * @returns Bytes written
  124. */
  125. uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  126. if (!node) return -1;
  127. if (node->write) {
  128. uint32_t ret = node->write(node, offset, size, buffer);
  129. return ret;
  130. } else {
  131. return -1;
  132. }
  133. }
  134. //volatile uint8_t tmp_refcount_lock = 0;
  135. static spin_lock_t tmp_refcount_lock = { 0 };
  136. void vfs_lock(fs_node_t * node) {
  137. spin_lock(tmp_refcount_lock);
  138. node->refcount = -1;
  139. spin_unlock(tmp_refcount_lock);
  140. }
  141. /**
  142. * open_fs: Open a file system node.
  143. *
  144. * @param node Node to open
  145. * @param flags Same as open, specifies read/write/append/truncate
  146. */
  147. void open_fs(fs_node_t *node, unsigned int flags) {
  148. if (!node) return;
  149. if (node->refcount >= 0) {
  150. spin_lock(tmp_refcount_lock);
  151. node->refcount++;
  152. spin_unlock(tmp_refcount_lock);
  153. }
  154. if (node->open) {
  155. node->open(node, flags);
  156. }
  157. }
  158. /**
  159. * close_fs: Close a file system node
  160. *
  161. * @param node Node to close
  162. */
  163. void close_fs(fs_node_t *node) {
  164. assert(node != fs_root && "Attempted to close the filesystem root. kablooey");
  165. if (!node) {
  166. debug_print(WARNING, "Double close? This isn't an fs_node.");
  167. return;
  168. }
  169. if (node->refcount == -1) return;
  170. spin_lock(tmp_refcount_lock);
  171. node->refcount--;
  172. if (node->refcount == 0) {
  173. debug_print(NOTICE, "Node refcount [%s] is now 0: %d", node->name, node->refcount);
  174. if (node->close) {
  175. node->close(node);
  176. }
  177. free(node);
  178. }
  179. spin_unlock(tmp_refcount_lock);
  180. }
  181. /**
  182. * chmod_fs
  183. */
  184. int chmod_fs(fs_node_t *node, int mode) {
  185. if (node->chmod) {
  186. return node->chmod(node, mode);
  187. }
  188. return 0;
  189. }
  190. /**
  191. * chown_fs
  192. */
  193. int chown_fs(fs_node_t *node, int uid, int gid) {
  194. if (node->chown) {
  195. return node->chown(node, uid, gid);
  196. }
  197. return 0;
  198. }
  199. /**
  200. * readdir_fs: Read a directory for the requested index
  201. *
  202. * @param node Directory to read
  203. * @param index Offset to look for
  204. * @returns A dirent object.
  205. */
  206. struct dirent *readdir_fs(fs_node_t *node, uint32_t index) {
  207. if (!node) return NULL;
  208. if ((node->flags & FS_DIRECTORY) && node->readdir) {
  209. struct dirent *ret = node->readdir(node, index);
  210. return ret;
  211. } else {
  212. return (struct dirent *)NULL;
  213. }
  214. }
  215. /**
  216. * finddir_fs: Find the requested file in the directory and return an fs_node for it
  217. *
  218. * @param node Directory to search
  219. * @param name File to look for
  220. * @returns An fs_node that the caller can free
  221. */
  222. fs_node_t *finddir_fs(fs_node_t *node, char *name) {
  223. if (!node) return NULL;
  224. if ((node->flags & FS_DIRECTORY) && node->finddir) {
  225. fs_node_t *ret = node->finddir(node, name);
  226. return ret;
  227. } else {
  228. debug_print(WARNING, "Node passed to finddir_fs isn't a directory!");
  229. debug_print(WARNING, "node = 0x%x, name = %s", node, name);
  230. return (fs_node_t *)NULL;
  231. }
  232. }
  233. /**
  234. * ioctl_fs: Control Device
  235. *
  236. * @param node Device node to control
  237. * @param request Device-specific request code
  238. * @param argp Depends on `request`
  239. * @returns Depends on `request`
  240. */
  241. int ioctl_fs(fs_node_t *node, int request, void * argp) {
  242. if (!node) return -1;
  243. if (node->ioctl) {
  244. return node->ioctl(node, request, argp);
  245. } else {
  246. return -1; /* TODO Should actually be ENOTTY, but we're bad at error numbers */
  247. }
  248. }
  249. /*
  250. * XXX: The following two function should be replaced with
  251. * one function to create children of directory nodes.
  252. * There is no fundamental difference between a directory
  253. * and a file, thus, the use of flag sets should suffice
  254. */
  255. int create_file_fs(char *name, uint16_t permission) {
  256. fs_node_t * parent;
  257. char *cwd = (char *)(current_process->wd_name);
  258. char *path = canonicalize_path(cwd, name);
  259. char * parent_path = malloc(strlen(path) + 4);
  260. sprintf(parent_path, "%s/..", path);
  261. char * f_path = path + strlen(path) - 1;
  262. while (f_path > path) {
  263. if (*f_path == '/') {
  264. f_path += 1;
  265. break;
  266. }
  267. f_path--;
  268. }
  269. while (*f_path == '/') {
  270. f_path++;
  271. }
  272. debug_print(WARNING, "creating file %s within %s (hope these strings are good)", f_path, parent_path);
  273. parent = kopen(parent_path, 0);
  274. free(parent_path);
  275. if (!parent) {
  276. debug_print(WARNING, "failed to open parent");
  277. free(path);
  278. return -1;
  279. }
  280. if (!has_permission(parent, 02)) {
  281. debug_print(WARNING, "bad permissions");
  282. return -EACCES;
  283. }
  284. if (parent->create) {
  285. parent->create(parent, f_path, permission);
  286. }
  287. free(path);
  288. free(parent);
  289. return 0;
  290. }
  291. int unlink_fs(char * name) {
  292. fs_node_t * parent;
  293. char *cwd = (char *)(current_process->wd_name);
  294. char *path = canonicalize_path(cwd, name);
  295. char * parent_path = malloc(strlen(path) + 4);
  296. sprintf(parent_path, "%s/..", path);
  297. char * f_path = path + strlen(path) - 1;
  298. while (f_path > path) {
  299. if (*f_path == '/') {
  300. f_path += 1;
  301. break;
  302. }
  303. f_path--;
  304. }
  305. while (*f_path == '/') {
  306. f_path++;
  307. }
  308. debug_print(WARNING, "unlinking file %s within %s (hope these strings are good)", f_path, parent_path);
  309. parent = kopen(parent_path, 0);
  310. free(parent_path);
  311. if (!parent) {
  312. free(path);
  313. return -1;
  314. }
  315. if (parent->unlink) {
  316. parent->unlink(parent, f_path);
  317. }
  318. free(path);
  319. free(parent);
  320. return 0;
  321. }
  322. int mkdir_fs(char *name, uint16_t permission) {
  323. fs_node_t * parent;
  324. char *cwd = (char *)(current_process->wd_name);
  325. char *path = canonicalize_path(cwd, name);
  326. char * parent_path = malloc(strlen(path) + 4);
  327. sprintf(parent_path, "%s/..", path);
  328. fs_node_t * this = kopen(path, 0);
  329. int _exists = 0;
  330. if (this) {
  331. debug_print(WARNING, "Tried to mkdir a dir that already exists? (%s)", path);
  332. _exists = 1;
  333. }
  334. char * f_path = path + strlen(path) - 1;
  335. while (f_path > path) {
  336. if (*f_path == '/') {
  337. f_path += 1;
  338. break;
  339. }
  340. f_path--;
  341. }
  342. while (*f_path == '/') {
  343. f_path++;
  344. }
  345. debug_print(WARNING, "creating directory %s within %s (hope these strings are good)", f_path, parent_path);
  346. parent = kopen(parent_path, 0);
  347. free(parent_path);
  348. if (!parent) {
  349. free(path);
  350. if (_exists) {
  351. return -EEXIST;
  352. }
  353. return -1;
  354. }
  355. if (parent->mkdir) {
  356. parent->mkdir(parent, f_path, permission);
  357. }
  358. free(path);
  359. close_fs(parent);
  360. if (_exists) {
  361. return -EEXIST;
  362. }
  363. return 0;
  364. }
  365. fs_node_t *clone_fs(fs_node_t *source) {
  366. if (!source) return NULL;
  367. if (source->refcount >= 0) {
  368. spin_lock(tmp_refcount_lock);
  369. source->refcount++;
  370. spin_unlock(tmp_refcount_lock);
  371. }
  372. return source;
  373. }
  374. int symlink_fs(char * target, char * name) {
  375. fs_node_t * parent;
  376. char *cwd = (char *)(current_process->wd_name);
  377. char *path = canonicalize_path(cwd, name);
  378. char * parent_path = malloc(strlen(path) + 4);
  379. sprintf(parent_path, "%s/..", path);
  380. char * f_path = path + strlen(path) - 1;
  381. while (f_path > path) {
  382. if (*f_path == '/') {
  383. f_path += 1;
  384. break;
  385. }
  386. f_path--;
  387. }
  388. debug_print(NOTICE, "creating symlink %s within %s", f_path, parent_path);
  389. parent = kopen(parent_path, 0);
  390. free(parent_path);
  391. if (!parent) {
  392. free(path);
  393. return -1;
  394. }
  395. if (parent->symlink) {
  396. parent->symlink(parent, target, f_path);
  397. }
  398. free(path);
  399. close_fs(parent);
  400. return 0;
  401. }
  402. int readlink_fs(fs_node_t *node, char * buf, uint32_t size) {
  403. if (!node) return -1;
  404. if (node->readlink) {
  405. return node->readlink(node, buf, size);
  406. } else {
  407. return -1;
  408. }
  409. }
  410. /**
  411. * canonicalize_path: Canonicalize a path.
  412. *
  413. * @param cwd Current working directory
  414. * @param input Path to append or canonicalize on
  415. * @returns An absolute path string
  416. */
  417. char *canonicalize_path(char *cwd, char *input) {
  418. /* This is a stack-based canonicalizer; we use a list as a stack */
  419. list_t *out = list_create();
  420. /*
  421. * If we have a relative path, we need to canonicalize
  422. * the working directory and insert it into the stack.
  423. */
  424. if (strlen(input) && input[0] != PATH_SEPARATOR) {
  425. /* Make a copy of the working directory */
  426. char *path = malloc((strlen(cwd) + 1) * sizeof(char));
  427. memcpy(path, cwd, strlen(cwd) + 1);
  428. /* Setup tokenizer */
  429. char *pch;
  430. char *save;
  431. pch = strtok_r(path,PATH_SEPARATOR_STRING,&save);
  432. /* Start tokenizing */
  433. while (pch != NULL) {
  434. /* Make copies of the path elements */
  435. char *s = malloc(sizeof(char) * (strlen(pch) + 1));
  436. memcpy(s, pch, strlen(pch) + 1);
  437. /* And push them */
  438. list_insert(out, s);
  439. pch = strtok_r(NULL,PATH_SEPARATOR_STRING,&save);
  440. }
  441. free(path);
  442. }
  443. /* Similarly, we need to push the elements from the new path */
  444. char *path = malloc((strlen(input) + 1) * sizeof(char));
  445. memcpy(path, input, strlen(input) + 1);
  446. /* Initialize the tokenizer... */
  447. char *pch;
  448. char *save;
  449. pch = strtok_r(path,PATH_SEPARATOR_STRING,&save);
  450. /*
  451. * Tokenize the path, this time, taking care to properly
  452. * handle .. and . to represent up (stack pop) and current
  453. * (do nothing)
  454. */
  455. while (pch != NULL) {
  456. if (!strcmp(pch,PATH_UP)) {
  457. /*
  458. * Path = ..
  459. * Pop the stack to move up a directory
  460. */
  461. node_t * n = list_pop(out);
  462. if (n) {
  463. free(n->value);
  464. free(n);
  465. }
  466. } else if (!strcmp(pch,PATH_DOT)) {
  467. /*
  468. * Path = .
  469. * Do nothing
  470. */
  471. } else {
  472. /*
  473. * Regular path, push it
  474. * XXX: Path elements should be checked for existence!
  475. */
  476. char * s = malloc(sizeof(char) * (strlen(pch) + 1));
  477. memcpy(s, pch, strlen(pch) + 1);
  478. list_insert(out, s);
  479. }
  480. pch = strtok_r(NULL, PATH_SEPARATOR_STRING, &save);
  481. }
  482. free(path);
  483. /* Calculate the size of the path string */
  484. size_t size = 0;
  485. foreach(item, out) {
  486. /* Helpful use of our foreach macro. */
  487. size += strlen(item->value) + 1;
  488. }
  489. /* join() the list */
  490. char *output = malloc(sizeof(char) * (size + 1));
  491. char *output_offset = output;
  492. if (size == 0) {
  493. /*
  494. * If the path is empty, we take this to mean the root
  495. * thus we synthesize a path of "/" to return.
  496. */
  497. output = realloc(output, sizeof(char) * 2);
  498. output[0] = PATH_SEPARATOR;
  499. output[1] = '\0';
  500. } else {
  501. /* Otherwise, append each element together */
  502. foreach(item, out) {
  503. output_offset[0] = PATH_SEPARATOR;
  504. output_offset++;
  505. memcpy(output_offset, item->value, strlen(item->value) + 1);
  506. output_offset += strlen(item->value);
  507. }
  508. }
  509. /* Clean up the various things we used to get here */
  510. list_destroy(out);
  511. list_free(out);
  512. free(out);
  513. /* And return a working, absolute path */
  514. return output;
  515. }
  516. void vfs_install(void) {
  517. /* Initialize the mountpoint tree */
  518. fs_tree = tree_create();
  519. struct vfs_entry * root = malloc(sizeof(struct vfs_entry));
  520. root->name = strdup("[root]");
  521. root->file = NULL; /* Nothing mounted as root */
  522. root->fs_type = NULL;
  523. root->device = NULL;
  524. tree_set_root(fs_tree, root);
  525. fs_types = hashmap_create(5);
  526. }
  527. int vfs_register(char * name, vfs_mount_callback callback) {
  528. if (hashmap_get(fs_types, name)) return 1;
  529. hashmap_set(fs_types, name, (void *)(uintptr_t)callback);
  530. return 0;
  531. }
  532. int vfs_mount_type(char * type, char * arg, char * mountpoint) {
  533. vfs_mount_callback t = (vfs_mount_callback)(uintptr_t)hashmap_get(fs_types, type);
  534. if (!t) {
  535. debug_print(WARNING, "Unknown filesystem type: %s", type);
  536. return -ENODEV;
  537. }
  538. fs_node_t * n = t(arg, mountpoint);
  539. if (!n) return -EINVAL;
  540. tree_node_t * node = vfs_mount(mountpoint, n);
  541. if (node && node->value) {
  542. struct vfs_entry * ent = (struct vfs_entry *)node->value;
  543. ent->fs_type = strdup(type);
  544. ent->device = strdup(arg);
  545. }
  546. debug_print(NOTICE, "Mounted %s[%s] to %s: 0x%x", type, arg, mountpoint, n);
  547. debug_print_vfs_tree();
  548. return 0;
  549. }
  550. //volatile uint8_t tmp_vfs_lock = 0;
  551. static spin_lock_t tmp_vfs_lock = { 0 };
  552. /**
  553. * vfs_mount - Mount a file system to the specified path.
  554. *
  555. * For example, if we have an EXT2 filesystem with a root node
  556. * of ext2_root and we want to mount it to /, we would run
  557. * vfs_mount("/", ext2_root); - or, if we have a procfs node,
  558. * we could mount that to /dev/procfs. Individual files can also
  559. * be mounted.
  560. *
  561. * Paths here must be absolute.
  562. */
  563. void * vfs_mount(char * path, fs_node_t * local_root) {
  564. if (!fs_tree) {
  565. debug_print(ERROR, "VFS hasn't been initialized, you can't mount things yet!");
  566. return NULL;
  567. }
  568. if (!path || path[0] != '/') {
  569. debug_print(ERROR, "Path must be absolute for mountpoint.");
  570. return NULL;
  571. }
  572. spin_lock(tmp_vfs_lock);
  573. local_root->refcount = -1;
  574. tree_node_t * ret_val = NULL;
  575. char * p = strdup(path);
  576. char * i = p;
  577. int path_len = strlen(p);
  578. /* Chop the path up */
  579. while (i < p + path_len) {
  580. if (*i == PATH_SEPARATOR) {
  581. *i = '\0';
  582. }
  583. i++;
  584. }
  585. /* Clean up */
  586. p[path_len] = '\0';
  587. i = p + 1;
  588. /* Root */
  589. tree_node_t * root_node = fs_tree->root;
  590. if (*i == '\0') {
  591. /* Special case, we're trying to set the root node */
  592. struct vfs_entry * root = (struct vfs_entry *)root_node->value;
  593. if (root->file) {
  594. debug_print(WARNING, "Path %s already mounted, unmount before trying to mount something else.", path);
  595. }
  596. root->file = local_root;
  597. /* We also keep a legacy shortcut around for that */
  598. fs_root = local_root;
  599. ret_val = root_node;
  600. } else {
  601. tree_node_t * node = root_node;
  602. char * at = i;
  603. while (1) {
  604. if (at >= p + path_len) {
  605. break;
  606. }
  607. int found = 0;
  608. debug_print(NOTICE, "Searching for %s", at);
  609. foreach(child, node->children) {
  610. tree_node_t * tchild = (tree_node_t *)child->value;
  611. struct vfs_entry * ent = (struct vfs_entry *)tchild->value;
  612. if (!strcmp(ent->name, at)) {
  613. found = 1;
  614. node = tchild;
  615. ret_val = node;
  616. break;
  617. }
  618. }
  619. if (!found) {
  620. debug_print(NOTICE, "Did not find %s, making it.", at);
  621. struct vfs_entry * ent = malloc(sizeof(struct vfs_entry));
  622. ent->name = strdup(at);
  623. ent->file = NULL;
  624. ent->device = NULL;
  625. ent->fs_type = NULL;
  626. node = tree_node_insert_child(fs_tree, node, ent);
  627. }
  628. at = at + strlen(at) + 1;
  629. }
  630. struct vfs_entry * ent = (struct vfs_entry *)node->value;
  631. if (ent->file) {
  632. debug_print(WARNING, "Path %s already mounted, unmount before trying to mount something else.", path);
  633. }
  634. ent->file = local_root;
  635. ret_val = node;
  636. }
  637. free(p);
  638. spin_unlock(tmp_vfs_lock);
  639. return ret_val;
  640. }
  641. void map_vfs_directory(char * c) {
  642. fs_node_t * f = vfs_mapper();
  643. struct vfs_entry * e = vfs_mount(c, f);
  644. if (!strcmp(c, "/")) {
  645. f->device = fs_tree->root;
  646. } else {
  647. f->device = e;
  648. }
  649. }
  650. void debug_print_vfs_tree_node(tree_node_t * node, size_t height) {
  651. /* End recursion on a blank entry */
  652. if (!node) return;
  653. char * tmp = malloc(512);
  654. memset(tmp, 0, 512);
  655. char * c = tmp;
  656. /* Indent output */
  657. for (uint32_t i = 0; i < height; ++i) {
  658. c += sprintf(c, " ");
  659. }
  660. /* Get the current process */
  661. struct vfs_entry * fnode = (struct vfs_entry *)node->value;
  662. /* Print the process name */
  663. if (fnode->file) {
  664. c += sprintf(c, "%s → %s 0x%x (%s, %s)", fnode->name, fnode->device, fnode->file, fnode->fs_type, fnode->file->name);
  665. } else {
  666. c += sprintf(c, "%s → (empty)", fnode->name);
  667. }
  668. /* Linefeed */
  669. debug_print(NOTICE, "%s", tmp);
  670. free(tmp);
  671. foreach(child, node->children) {
  672. /* Recursively print the children */
  673. debug_print_vfs_tree_node(child->value, height + 1);
  674. }
  675. }
  676. void debug_print_vfs_tree(void) {
  677. debug_print_vfs_tree_node(fs_tree->root, 0);
  678. }
  679. /**
  680. * get_mount_point
  681. *
  682. */
  683. fs_node_t *get_mount_point(char * path, unsigned int path_depth, char **outpath, unsigned int * outdepth) {
  684. size_t depth;
  685. for (depth = 0; depth <= path_depth; ++depth) {
  686. path += strlen(path) + 1;
  687. }
  688. /* Last available node */
  689. fs_node_t * last = fs_root;
  690. tree_node_t * node = fs_tree->root;
  691. char * at = *outpath;
  692. int _depth = 1;
  693. int _tree_depth = 0;
  694. while (1) {
  695. if (at >= path) {
  696. break;
  697. }
  698. int found = 0;
  699. debug_print(INFO, "Searching for %s", at);
  700. foreach(child, node->children) {
  701. tree_node_t * tchild = (tree_node_t *)child->value;
  702. struct vfs_entry * ent = (struct vfs_entry *)tchild->value;
  703. if (!strcmp(ent->name, at)) {
  704. found = 1;
  705. node = tchild;
  706. at = at + strlen(at) + 1;
  707. if (ent->file) {
  708. _tree_depth = _depth;
  709. last = ent->file;
  710. *outpath = at;
  711. }
  712. break;
  713. }
  714. }
  715. if (!found) {
  716. break;
  717. }
  718. _depth++;
  719. }
  720. *outdepth = _tree_depth;
  721. if (last) {
  722. fs_node_t * last_clone = malloc(sizeof(fs_node_t));
  723. memcpy(last_clone, last, sizeof(fs_node_t));
  724. return last_clone;
  725. }
  726. return last;
  727. }
  728. fs_node_t *kopen_recur(char *filename, uint32_t flags, uint32_t symlink_depth, char *relative_to) {
  729. /* Simple sanity checks that we actually have a file system */
  730. if (!filename) {
  731. return NULL;
  732. }
  733. /* Canonicalize the (potentially relative) path... */
  734. char *path = canonicalize_path(relative_to, filename);
  735. /* And store the length once to save recalculations */
  736. size_t path_len = strlen(path);
  737. /* If strlen(path) == 1, then path = "/"; return root */
  738. if (path_len == 1) {
  739. /* Clone the root file system node */
  740. fs_node_t *root_clone = malloc(sizeof(fs_node_t));
  741. memcpy(root_clone, fs_root, sizeof(fs_node_t));
  742. /* Free the path */
  743. free(path);
  744. open_fs(root_clone, flags);
  745. /* And return the clone */
  746. return root_clone;
  747. }
  748. /* Otherwise, we need to break the path up and start searching */
  749. char *path_offset = path;
  750. uint32_t path_depth = 0;
  751. while (path_offset < path + path_len) {
  752. /* Find each PATH_SEPARATOR */
  753. if (*path_offset == PATH_SEPARATOR) {
  754. *path_offset = '\0';
  755. path_depth++;
  756. }
  757. path_offset++;
  758. }
  759. /* Clean up */
  760. path[path_len] = '\0';
  761. path_offset = path + 1;
  762. /*
  763. * At this point, the path is tokenized and path_offset points
  764. * to the first token (directory) and path_depth is the number
  765. * of directories in the path
  766. */
  767. /*
  768. * Dig through the (real) tree to find the file
  769. */
  770. unsigned int depth = 0;
  771. /* Find the mountpoint for this file */
  772. fs_node_t *node_ptr = get_mount_point(path, path_depth, &path_offset, &depth);
  773. debug_print(INFO, "path_offset: %s", path_offset);
  774. debug_print(INFO, "depth: %d", depth);
  775. if (!node_ptr) return NULL;
  776. if (path_offset >= path+path_len) {
  777. free(path);
  778. open_fs(node_ptr, flags);
  779. return node_ptr;
  780. }
  781. fs_node_t *node_next = NULL;
  782. for (; depth < path_depth; ++depth) {
  783. /* Search the active directory for the requested directory */
  784. debug_print(INFO, "... Searching for %s", path_offset);
  785. node_next = finddir_fs(node_ptr, path_offset);
  786. free(node_ptr); /* Always a clone or an unopened thing */
  787. node_ptr = node_next;
  788. if (!node_ptr) {
  789. /* We failed to find the requested directory */
  790. free((void *)path);
  791. return NULL;
  792. }
  793. /*
  794. * This test is a little complicated, but we basically always resolve symlinks in the
  795. * of a path (like /home/symlink/file) even if O_NOFOLLOW and O_PATH are set. If we are
  796. * on the leaf of the path then we will look at those flags and act accordingly
  797. */
  798. if ((node_ptr->flags & FS_SYMLINK) &&
  799. !((flags & O_NOFOLLOW) && (flags & O_PATH) && depth == path_depth - 1)) {
  800. /* This ensures we don't return a path when NOFOLLOW is requested but PATH
  801. * isn't passed.
  802. */
  803. debug_print(NOTICE, "resolving symlink at %s", node_ptr->name);
  804. if ((flags & O_NOFOLLOW) && depth == path_depth - 1) {
  805. /* TODO(gerow): should probably be setting errno from this */
  806. debug_print(NOTICE, "Refusing to follow final entry for open with O_NOFOLLOW for %s.", node_ptr->name);
  807. free((void *)path);
  808. free(node_ptr);
  809. return NULL;
  810. }
  811. if (symlink_depth >= MAX_SYMLINK_DEPTH) {
  812. /* TODO(gerow): should probably be setting errno from this */
  813. debug_print(WARNING, "Reached max symlink depth on %s.", node_ptr->name);
  814. free((void *)path);
  815. free(node_ptr);
  816. return NULL;
  817. }
  818. /*
  819. * This may actually be big enough that we wouldn't want to allocate it on
  820. * the stack, especially considering this function is called recursively
  821. */
  822. char symlink_buf[MAX_SYMLINK_SIZE];
  823. int len = readlink_fs(node_ptr, symlink_buf, sizeof(symlink_buf));
  824. if (len < 0) {
  825. /* TODO(gerow): should probably be setting errno from this */
  826. debug_print(WARNING, "Got error %d from symlink for %s.", len, node_ptr->name);
  827. free((void *)path);
  828. free(node_ptr);
  829. return NULL;
  830. }
  831. if (symlink_buf[len] != '\0') {
  832. /* TODO(gerow): should probably be setting errno from this */
  833. debug_print(WARNING, "readlink for %s doesn't end in a null pointer. That's weird...", node_ptr->name);
  834. free((void *)path);
  835. free(node_ptr);
  836. return NULL;
  837. }
  838. fs_node_t * old_node_ptr = node_ptr;
  839. /* Rebuild our path up to this point. This is hella hacky. */
  840. char * relpath = malloc(path_len + 1);
  841. char * ptr = relpath;
  842. memcpy(relpath, path, path_len + 1);
  843. for (unsigned int i = 0; i < depth; i++) {
  844. while(*ptr != '\0') {
  845. ptr++;
  846. }
  847. *ptr = PATH_SEPARATOR;
  848. }
  849. node_ptr = kopen_recur(symlink_buf, 0, symlink_depth + 1, relpath);
  850. free(relpath);
  851. free(old_node_ptr);
  852. if (!node_ptr) {
  853. /* Dangling symlink? */
  854. debug_print(WARNING, "Failed to open symlink path %s. Perhaps it's a dangling symlink?", symlink_buf);
  855. free((void *)path);
  856. return NULL;
  857. }
  858. }
  859. if (depth == path_depth - 1) {
  860. /* We found the file and are done, open the node */
  861. open_fs(node_ptr, flags);
  862. free((void *)path);
  863. return node_ptr;
  864. }
  865. /* We are still searching... */
  866. path_offset += strlen(path_offset) + 1;
  867. }
  868. debug_print(INFO, "- Not found.");
  869. /* We failed to find the requested file, but our loop terminated. */
  870. free((void *)path);
  871. return NULL;
  872. }
  873. /**
  874. * kopen: Open a file by name.
  875. *
  876. * Explore the file system tree to find the appropriate node for
  877. * for a given path. The path can be relative to the working directory
  878. * and will be canonicalized by the kernel.
  879. *
  880. * @param filename Filename to open
  881. * @param flags Flag bits for read/write mode.
  882. * @returns A file system node element that the caller can free.
  883. */
  884. fs_node_t *kopen(char *filename, uint32_t flags) {
  885. debug_print(NOTICE, "kopen(%s)", filename);
  886. return kopen_recur(filename, flags, 0, (char *)(current_process->wd_name));
  887. }