Advertisement
VladNitu

5_pass_vlad_os

Mar 12th, 2024
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.20 KB | None | 0 0
  1. /**
  2. * @file os_assignment.c
  3. *
  4. * This is the file you will be working in. You will have to complete the (partial) implementation
  5. * given below. Any functions you have to complete are clearly marked as such.
  6. *
  7. * Good luck!
  8. */
  9.  
  10. #include "dfs.h"
  11. #include "dfs-path.h"
  12. #include "dfs-helpers.h"
  13. #include "strdup.h"
  14.  
  15. #define FUSE_USE_VERSION 31
  16. #include <fuse.h>
  17.  
  18. #include <assert.h>
  19. #include <errno.h>
  20. #include <fcntl.h>
  21. #include <stddef.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. /**
  27. * path = [<parent_path>/<entity_name>]
  28. * entity_name can be either the name of a file, or the name of a directory.
  29. */
  30. static int split_path(const char *path, char *parent_path, char *entity_name) {
  31. char *last_slash = strrchr(path, '/'); // Obtain a pointer to the last occurence of "/"
  32. if (NULL == last_slash) { // No "/" in the provided path
  33. return -1;
  34. }
  35. size_t parent_len = last_slash - path;
  36. strncpy(parent_path, path, parent_len);
  37. parent_path[parent_len] = '\0';
  38. strcpy(entity_name, last_slash + 1);
  39. return 0;
  40. }
  41.  
  42.  
  43. /**
  44. * The root directory of the file system.
  45. */
  46. DfsDir *root_dir;
  47.  
  48. /**
  49. * Initializes the default file system.
  50. *
  51. * This fills the DFS with a number of directories and files. Add, remove and rename some files
  52. * and directories, if you wish.
  53. *
  54. * Note how this creates a top-level directory root_dir. You will have to use this directory.
  55. */
  56. void create_dfs(void) {
  57. // Define some directories
  58. root_dir = dfs_create_dir();
  59.  
  60. DfsDir *files_dir = dfs_create_dir();
  61. DfsDir *pictures_dir = dfs_create_dir();
  62. DfsDir *important_files_dir = dfs_create_dir();
  63. assert(files_dir && pictures_dir && important_files_dir);
  64.  
  65. // Define some files
  66. DfsFile *welcome_file = make_file("Welcome to the DFS.\n");
  67. DfsFile *budget_file = make_file(budget_text);
  68. DfsFile *hello_1_file = make_file("Hello there!\n");
  69. DfsFile *hello_2_file = make_file("Hei siell !\n");
  70. DfsFile *image_1_file = make_binary_file(image_1, sizeof(image_1));
  71. DfsFile *image_2_file = make_binary_file(image_2, sizeof(image_2));
  72. assert(
  73. welcome_file && budget_file && hello_1_file && hello_2_file && image_1_file && image_2_file
  74. );
  75.  
  76. // Add everything together
  77. assert_dfs_ok(dfs_add_dir(root_dir, "Files", files_dir));
  78. assert_dfs_ok(dfs_add_dir(root_dir, "Pictures", pictures_dir));
  79.  
  80. assert_dfs_ok(dfs_add_dir(files_dir, "Important files", important_files_dir));
  81.  
  82. assert_dfs_ok(dfs_add_file(root_dir, "README.txt", welcome_file));
  83. assert_dfs_ok(dfs_add_file(files_dir, "hello.txt", hello_1_file));
  84. assert_dfs_ok(dfs_add_file(files_dir, "hello2.txt", hello_2_file));
  85. assert_dfs_ok(dfs_add_file(important_files_dir, "budget.csv", budget_file));
  86. assert_dfs_ok(dfs_add_file(pictures_dir, "some image.png", image_1_file));
  87. assert_dfs_ok(dfs_add_file(pictures_dir, "some other image.png", image_2_file));
  88. }
  89.  
  90. /**
  91. * @defgroup Assignment The assignment
  92. * These functions must be completed for the assignment.
  93. *
  94. * The functions here directly correspond to the syscall with the same name, unless noted otherwise.
  95. * @{
  96. */
  97.  
  98. /**
  99. * Lists files/directories available in a specific directory.
  100. *
  101. * This function is specific to FUSE; there is no directly corresponding system call.
  102. *
  103. * @param path directory which we are listing
  104. * @param buff buffer to fill with data
  105. * @param fill a function to help fill buffer
  106. * @param off not used
  107. * @param fi not used
  108. *
  109. * @return 0 or an appropriate error code
  110. */
  111. static int os_readdir(
  112. const char *path, void *buff, fuse_fill_dir_t fill, off_t off, struct fuse_file_info *fi
  113. ) {
  114. // Example: this is how you find the required directory.
  115. DfsDir *dir;
  116. DfsStatus dir_status = dfs_find_dir_str(root_dir, path, &dir); // Writes address of found directory to `dir`
  117. // This could fail though! You should return an error if this is so, in other functions as well
  118. if (dir_status != DFS_OK) {
  119. return -ENOENT; // Error: no entity
  120. }
  121. // Other errors are also possible
  122.  
  123. fill(buff, ".", NULL, 0);
  124. fill(buff, "..", NULL, 0);
  125.  
  126. // Iterate over all entries in a dir
  127. size_t cursor = 0;
  128. const char *name;
  129. DfsEntry* entry;
  130. while (dfs_get_next(dir, &cursor, &name, &entry) == DFS_OK && name != NULL)
  131. fill(buff, name, NULL, 0);
  132.  
  133. // Returning 0 means all-ok.
  134. return 0;
  135. }
  136.  
  137. /**
  138. * Creates a new directory.
  139. *
  140. * @param path the path to the new directory
  141. * @param mode the mode (permissions) of the new directory. Can be ignored
  142. *
  143. * @return 0 or an appropriate error code
  144. *
  145. * @see [`man 2 mkdir`](https://linux.die.net/man/2/mkdir)
  146. */
  147. static int os_mkdir(const char *path, mode_t mode) {
  148. // Example: this is how you find the required directory.
  149. char dir_name[1024] = {0};
  150. char parent_path[1024] = {0};
  151.  
  152. if (split_path(path, parent_path, dir_name) != 0)
  153. return -ENOENT;
  154.  
  155. DfsDir *parent_dir;
  156.  
  157. DfsStatus dir_status = dfs_find_dir_str(root_dir, parent_path, &parent_dir); // Writes address of found directory to `parent_dir`
  158. if (dir_status != DFS_OK)
  159. return -ENOENT; // Error: no entity
  160.  
  161.  
  162. DfsDir *new_dir = dfs_create_dir(); // Create new directory
  163. if (!new_dir)
  164. return -ENOENT;
  165.  
  166. // Add it to parent directory
  167. DfsStatus add_dir_status = dfs_add_entry(parent_dir, dir_name, (DfsDir*) new_dir);
  168. if (add_dir_status != DFS_OK) {
  169. dfs_destroy_dir(new_dir);
  170. return -EEXIST; // Error: Did already exists -> dir name conflict
  171. }
  172.  
  173. return 0;
  174.  
  175. }
  176.  
  177. /**
  178. * Removes a directory.
  179. *
  180. * This must return an error if the directory is not empty.
  181. *
  182. * @param path the path to the directory to remove
  183. *
  184. * @return 0 or an appropriate error code
  185. *
  186. * @see [`man 2 rmdir`](https://linux.die.net/man/2/rmdir)
  187. */
  188. static int os_rmdir(const char *path) {
  189.  
  190. char parent_path[1024] = {0};
  191. char dir_name[1024] = {0};
  192.  
  193. if (split_path(path, parent_path, dir_name) != 0)
  194. return -ENOENT;
  195.  
  196. DfsDir *parent_dir;
  197. DfsStatus dir_status = dfs_find_dir_str(root_dir, parent_path, &parent_dir); // Writes address of found directory to `parent_dir`
  198. if (dir_status != DFS_OK)
  199. return -ENOENT; // Error: no entity
  200.  
  201. DfsDir *dir_removed;
  202. DfsStatus find_dir = dfs_get_dir(parent_dir, dir_name, &dir_removed);
  203. if (find_dir != DFS_OK)
  204. return -ENOENT;
  205.  
  206. size_t cursor = 0;
  207. const char *next_name;
  208. DfsEntry* entry;
  209. if (dfs_get_next(dir_removed, &cursor, &next_name, NULL) == DFS_OK) // not empty
  210. return -ENOTEMPTY;
  211.  
  212. dfs_remove_dir(parent_dir, dir_name, NULL);
  213. return 0;
  214. }
  215.  
  216. /**
  217. * Reads (part of) a file.
  218. *
  219. * This may return fewer bytes than requested, but only if the end of the file was reached. Note
  220. * that the system call behaves differently!
  221. *
  222. * @param path the path to the file
  223. * @param buff where to write the read data
  224. * @param size the number of bytes to read
  225. * @param off where to start reading from
  226. * @param fi can be ignored
  227. *
  228. * @return the number of bytes read or an appropriate error code
  229. *
  230. * @see [`man 2 read`](https://linux.die.net/man/2/read)
  231. */
  232. static int os_read(
  233. const char *path, char *buff, size_t size, off_t off, struct fuse_file_info *fi
  234. ) {
  235. DfsFile *file;
  236. DfsStatus find_file_status = dfs_find_file_str(root_dir, path, &file); // , find the file to read from
  237. if (find_file_status != DFS_OK) {
  238. return -ENOENT; // Error: no entity
  239. }
  240.  
  241. // try to write after EOF
  242. if (off >= file->length)
  243. return 0;
  244.  
  245. size_t read_size = size;
  246. if (off + size > file->length)
  247. read_size = file->length - off;
  248.  
  249. memcpy(buff, file->contents + off, read_size); // copy the chunk of bytes to the buffer; TODO: Check if resize of buff neede
  250.  
  251. return read_size; // return # of bytes read
  252. }
  253.  
  254. /**
  255. * Writes (part of) a file.
  256. *
  257. * This must write all given bytes. Note that the system call behaves differently!
  258. *
  259. * @param path the path to the file
  260. * @param buff the data to write
  261. * @param size the number of bytes to write
  262. * @param off where to start writing from
  263. * @param fi can be ignored
  264. *
  265. * @return the number of bytes written or an appropriate error code
  266. *
  267. * @see [`man 2 write`](https://linux.die.net/man/2/write)
  268. */
  269. static int os_write(
  270. const char *path, const char *buff, size_t size, off_t off, struct fuse_file_info *fi
  271. ) {
  272. DfsFile *file;
  273. DfsStatus find_file_status = dfs_find_file_str(root_dir, path, &file); // , find the file to read from
  274. if (find_file_status != DFS_OK) {
  275. return -ENOENT; // Error: no entity
  276. }
  277.  
  278. if (file->length < off + size) { // file too short
  279. char* copy_contents = realloc(file->contents, off + size);
  280. if (!copy_contents)
  281. return -ENOMEM;
  282. memset(copy_contents + file->length, 0, (off + size) - file->length);
  283.  
  284. file->contents = copy_contents;
  285. file->length = off + size;
  286. }
  287.  
  288. memcpy(file->contents + off, buff, size);
  289. return size; // Return # of written bytes
  290. }
  291.  
  292. /**
  293. * Creates a file.
  294. *
  295. * @param path the path to the file
  296. * @param mode the mode (permissions) of the new file. Can be ignored
  297. * @param fi can be ignored
  298. *
  299. * @return 0 or an appropriate error code
  300. *
  301. * @see [`man 2 creat`](https://linux.die.net/man/2/creat) (that is not a typo)
  302. */
  303. static int os_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
  304. char file_name[1024];
  305. char parent_path[1024];
  306.  
  307. if (split_path(path, parent_path, file_name) != 0)
  308. return -ENOENT;
  309.  
  310. DfsDir *parent_dir;
  311.  
  312. DfsStatus dir_status = dfs_find_dir_str(root_dir, parent_path, &parent_dir); // Writes address of found directory to `parent_dir`
  313. if (dir_status != DFS_OK)
  314. return -ENOENT; // Error: no entity
  315.  
  316.  
  317. DfsFile *new_file = dfs_create_file(); // Create new file
  318. if (!new_file)
  319. return -ENOSPC; // mem. not allocd
  320.  
  321. // Add it to parent directory
  322. DfsStatus add_file_status = dfs_add_file(parent_dir, file_name, new_file);
  323. if (add_file_status != DFS_OK) {
  324. dfs_destroy_file(new_file);
  325. return -EEXIST; // Error: File already exists -> dir name conflict
  326. }
  327.  
  328. return 0;
  329. }
  330.  
  331. /**
  332. * Unlinks (deletes) a file.
  333. *
  334. * @param path the path to the file
  335. *
  336. * @return 0 or appropriate error code
  337. *
  338. * @see [`man 2 unlink`](https://linux.die.net/man/2/unlink)
  339. */
  340. static int os_unlink(const char *path) {
  341.  
  342. char file_name[1024] = {0};
  343. char parent_path[1024] = {0};
  344.  
  345. if (split_path(path, parent_path, file_name) != 0)
  346. return -ENOENT;
  347.  
  348.  
  349. DfsDir *parent_dir;
  350.  
  351. DfsStatus dir_status = dfs_find_dir_str(root_dir, parent_path, &parent_dir); // Writes address of found directory to `parent_dir`
  352. if (dir_status != DFS_OK)
  353. return -ENOENT; // Error: no entity
  354.  
  355.  
  356. DfsStatus removed_status = dfs_remove_file(parent_dir, file_name, NULL);
  357. if (removed_status != DFS_OK)
  358. return -ENOENT;
  359.  
  360. return 0;
  361. }
  362.  
  363. /// @}
  364. /**
  365. * @defgroup Predefined Predefined functions
  366. * You do not have to modify these for the assignment.
  367. * @{
  368. */
  369.  
  370. /**
  371. * Counts the number of (direct) subdirectories of a directory.
  372. *
  373. * @param dir the directory to scan
  374. *
  375. * @return the number of subdirectories
  376. */
  377. static size_t os_count_subdirs(DfsDir *dir) {
  378. size_t cursor = 0;
  379. size_t num_subdirs = 0;
  380. DfsEntry *entry;
  381. for (;;) {
  382. DfsStatus get_next_status = dfs_get_next(dir, &cursor, NULL, &entry);
  383. if (get_next_status == DFS_E_NO_MORE_ENTRIES) break;
  384. if (entry->type == DFS_ENT_DIR) ++num_subdirs;
  385. }
  386.  
  387. return num_subdirs;
  388. }
  389.  
  390. /**
  391. * Retrieves file/directory attributes.
  392. *
  393. * @param path the path for which attributes are requested
  394. * @param st struct to be filled with attributes
  395. *
  396. * @return 0 or an appropriate error code
  397. *
  398. * @see [`man 2 stat`](https://linux.die.net/man/2/stat)
  399. */
  400. static int os_getattr(const char *path, struct stat *st) {
  401. DfsEntry *entry;
  402. DfsStatus entry_status = dfs_find_entry_str(root_dir, path, &entry);
  403. if (entry_status == DFS_E_MALLOC_FAILURE) return -ENOMEM;
  404. if (entry_status == DFS_E_ENTRY_DOES_NOT_EXIST) return -ENOENT;
  405.  
  406. st->st_uid = entry->user;
  407. st->st_gid = entry->group;
  408. st->st_ctime = entry->ctime.tv_sec;
  409. st->st_mtime = entry->mtime.tv_sec;
  410. st->st_atime = entry->atime.tv_sec;
  411.  
  412. if (entry->type == DFS_ENT_FILE) {
  413. DfsFile *file = (DfsFile *) entry;
  414. st->st_mode = S_IFREG | entry->mode; // Requested item is (probably) a regular file
  415. st->st_nlink = 1; // Number of hard links: a file has at least one
  416. st->st_size = file->length;
  417. } else if (entry->type == DFS_ENT_DIR) {
  418. DfsDir *dir = (DfsDir *) entry;
  419. st->st_mode = S_IFDIR | entry->mode;
  420. st->st_nlink = os_count_subdirs(dir) + 1;
  421. st->st_size = dfs_get_dir_size(dir) * 32; // Estimate :)
  422. }
  423.  
  424. return 0;
  425. }
  426.  
  427. /**
  428. * Resizes a file.
  429. *
  430. * @param path the path to the file
  431. * @param off the new size of the file in bytes
  432. *
  433. * @return 0 or an appropriate error code
  434. *
  435. * @see [`man 2 truncate`](https://linux.die.net/man/2/truncate)
  436. */
  437. static int os_truncate(const char *path, off_t off) {
  438. DfsFile *file;
  439. DfsStatus file_status = dfs_find_file_str(root_dir, path, &file);
  440. if (file_status == DFS_E_MALLOC_FAILURE) return -ENOMEM;
  441. if (file_status == DFS_E_ENTRY_DOES_NOT_EXIST) return -ENOENT;
  442. if (file_status == DFS_E_NOT_A_FILE) return -EISDIR;
  443.  
  444. if (off == 0) {
  445. free(file->contents);
  446. file->contents = NULL;
  447. file->length = 0;
  448. return 0;
  449. }
  450.  
  451. char *new_contents = realloc(file->contents, off);
  452. if (!new_contents) return -ENOMEM;
  453.  
  454. file->contents = new_contents;
  455.  
  456. if ((size_t) off > file->length) {
  457. memset(file->contents + file->length, 0, off - file->length);
  458. }
  459.  
  460. file->length = off;
  461.  
  462. return 0;
  463. }
  464.  
  465. /**
  466. * Sets extended attributes on an entry.
  467. *
  468. * This is currently not implemented (and you do not have to implement it yourself).
  469. *
  470. * @param path the path to the file
  471. * @param name the name of the attribute
  472. * @param value the value of the attribute
  473. * @param length the length of the attribute
  474. * @param flags any flags
  475. *
  476. * @return 0 or an appropriate error code
  477. */
  478. static int os_setxattr(
  479. const char *path, const char *name, const char *value, size_t length, int flags
  480. ) {
  481. return -ENOTSUP;
  482. }
  483.  
  484. /**
  485. * Changes the mode (permissions) of an entry.
  486. *
  487. * @param path the path to the file
  488. * @param mode the new mode
  489. *
  490. * @return 0 or an appropriate error code
  491. *
  492. * @see [`man 2 chmod`](https://linux.die.net/man/2/chmod)
  493. */
  494. static int os_chmod(const char *path, mode_t mode) {
  495. DfsEntry *entry;
  496. DfsStatus entry_status = dfs_find_entry_str(root_dir, path, &entry);
  497. if (entry_status == DFS_E_MALLOC_FAILURE) return -ENOMEM;
  498. if (entry_status == DFS_E_ENTRY_DOES_NOT_EXIST) return -ENOENT;
  499.  
  500. entry->mode = mode;
  501.  
  502. return 0;
  503. }
  504.  
  505. /**
  506. * Changes the owning user and group of an entry.
  507. *
  508. * @param path the path to the file
  509. * @param uid the new owning user
  510. * @param gid the new owning group
  511. *
  512. * @return 0 or an appropriate error code
  513. *
  514. * @see [`man 2 chown`](https://linux.die.net/man/2/chown)
  515. */
  516. static int os_chown(const char *path, uid_t uid, gid_t gid) {
  517. DfsEntry *entry;
  518. DfsStatus entry_status = dfs_find_entry_str(root_dir, path, &entry);
  519. if (entry_status == DFS_E_MALLOC_FAILURE) return -ENOMEM;
  520. if (entry_status == DFS_E_ENTRY_DOES_NOT_EXIST) return -ENOENT;
  521.  
  522. entry->user = uid;
  523. entry->group = gid;
  524.  
  525. return 0;
  526. }
  527.  
  528. /**
  529. * Changes the atime and mtime of an entry.
  530. *
  531. * @param path the path to the entry
  532. * @param tv the new atime and mtime values, respectively
  533. *
  534. * @return 0 or an appropriate error code
  535. *
  536. * @see [`man 2 utimensat`](https://linux.die.net/man/2/utimensat)
  537. */
  538. static int os_utimens(const char *path, const struct timespec tv[2]) {
  539. DfsEntry *entry;
  540. DfsStatus entry_status = dfs_find_entry_str(root_dir, path, &entry);
  541. if (entry_status == DFS_E_MALLOC_FAILURE) return -ENOMEM;
  542. if (entry_status == DFS_E_ENTRY_DOES_NOT_EXIST) return -ENOENT;
  543.  
  544. entry->atime = tv[0];
  545. entry->mtime = tv[1];
  546.  
  547. return 0;
  548. }
  549.  
  550. /**
  551. * Here we define the operations FUSE has access to.
  552. *
  553. * Not all members have been populated and you should not call those!
  554. */
  555. static struct fuse_operations operations = {
  556. .getattr = os_getattr,
  557. .readdir = os_readdir,
  558. .read = os_read,
  559. .mkdir = os_mkdir,
  560. .rmdir = os_rmdir,
  561. .write = os_write,
  562. .setxattr = os_setxattr,
  563. .truncate = os_truncate,
  564. .chmod = os_chmod,
  565. .chown = os_chown,
  566. .utimens = os_utimens,
  567. .create = os_create,
  568. .unlink = os_unlink
  569. };
  570.  
  571. /**
  572. * Main function.
  573. *
  574. * @param argc the number of arguments
  575. * @param argv the arguments
  576. */
  577. int main(int argc, char **argv) {
  578. // Setup dumb file system
  579. create_dfs();
  580.  
  581. // Pass arguments on to FUSE.
  582. return fuse_main(argc, argv, &operations, NULL);
  583. }
  584.  
  585. /// @}
  586.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement