dirent.cpp 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #include <dirent.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <fcntl.h>
  8. #include <Kernel/Syscall.h>
  9. extern "C" {
  10. DIR* opendir(const char* name)
  11. {
  12. int fd = open(name, O_RDONLY | O_DIRECTORY);
  13. if (fd == -1)
  14. return nullptr;
  15. DIR* dirp = (DIR*)malloc(sizeof(DIR));
  16. dirp->fd = fd;
  17. dirp->buffer = nullptr;
  18. dirp->buffer_size = 0;
  19. dirp->nextptr = nullptr;
  20. return dirp;
  21. }
  22. int closedir(DIR* dirp)
  23. {
  24. if (!dirp || dirp->fd == -1)
  25. return -EBADF;
  26. if (dirp->buffer)
  27. free(dirp->buffer);
  28. int rc = close(dirp->fd);
  29. if (rc == 0)
  30. dirp->fd = -1;
  31. free(dirp);
  32. return rc;
  33. }
  34. struct [[gnu::packed]] sys_dirent {
  35. ino_t ino;
  36. byte file_type;
  37. size_t namelen;
  38. char name[];
  39. size_t total_size()
  40. {
  41. return sizeof(ino_t) + sizeof(byte) + sizeof(size_t) + sizeof(char) * namelen;
  42. }
  43. };
  44. dirent* readdir(DIR* dirp)
  45. {
  46. if (!dirp)
  47. return nullptr;
  48. if (dirp->fd == -1)
  49. return nullptr;
  50. if (!dirp->buffer) {
  51. // FIXME: Figure out how much to actually allocate.
  52. dirp->buffer = (char*)malloc(4096);
  53. ssize_t nread = syscall(SC_get_dir_entries, dirp->fd, dirp->buffer, 4096);
  54. dirp->buffer_size = nread;
  55. dirp->nextptr = dirp->buffer;
  56. }
  57. if (dirp->nextptr >= (dirp->buffer + dirp->buffer_size))
  58. return nullptr;
  59. auto* sys_ent = (sys_dirent*)dirp->nextptr;
  60. dirp->cur_ent.d_ino = sys_ent->ino;
  61. dirp->cur_ent.d_type = sys_ent->file_type;
  62. dirp->cur_ent.d_off = 0;
  63. dirp->cur_ent.d_reclen = sys_ent->total_size();
  64. for (size_t i = 0; i < sys_ent->namelen; ++i)
  65. dirp->cur_ent.d_name[i] = sys_ent->name[i];
  66. // FIXME: I think this null termination behavior is not supposed to be here.
  67. dirp->cur_ent.d_name[sys_ent->namelen] = '\0';
  68. dirp->nextptr += sys_ent->total_size();
  69. return &dirp->cur_ent;
  70. }
  71. }