dirent.c 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <dirent.h>
  4. #include <string.h>
  5. #include <syscall.h>
  6. DIR* opendir(const char* name)
  7. {
  8. // TODO: set flags
  9. int fd = open(name, O_DIRECTORY);
  10. if (fd < 0)
  11. return NULL;
  12. return fdopendir(fd);
  13. }
  14. DIR* fdopendir(int fd)
  15. {
  16. static DIR dirs[64];
  17. static int next = 0;
  18. dirs[next].fd = fd;
  19. dirs[next].bpos = 0;
  20. return dirs + next++;
  21. }
  22. struct kernel_dirent {
  23. ino_t d_ino; // inode number
  24. uint32_t d_off; // ignored
  25. uint16_t d_reclen; // length of this struct user_dirent
  26. char d_name[1]; // file name with a padding zero
  27. // uint8_t d_type; // file type, with offset of (d_reclen - 1)
  28. };
  29. size_t fill_dirent(struct dirent* dent, char* buffer, size_t bpos)
  30. {
  31. struct kernel_dirent* dp = (struct kernel_dirent*)(buffer + bpos);
  32. dent->d_ino = dp->d_ino;
  33. dent->d_off = dp->d_off;
  34. dent->d_reclen = dp->d_reclen;
  35. dent->d_type = buffer[bpos + dp->d_reclen - 1];
  36. strncpy(dent->d_name, dp->d_name, sizeof(dent->d_name));
  37. dent->d_name[sizeof(dent->d_name) - 1] = 0;
  38. return bpos + dp->d_reclen;
  39. }
  40. struct dirent* readdir(DIR* dirp)
  41. {
  42. if (dirp->bpos) {
  43. if (dirp->bpos >= dirp->blen) {
  44. dirp->bpos = 0;
  45. } else {
  46. goto fill;
  47. }
  48. }
  49. dirp->blen = syscall3(SYS_getdents,
  50. dirp->fd,
  51. (uint32_t)dirp->buffer,
  52. sizeof(dirp->buffer)
  53. );
  54. if (dirp->blen <= 0) {
  55. if (dirp->blen < 0) {
  56. errno = -dirp->blen;
  57. dirp->blen = 0;
  58. }
  59. return NULL;
  60. }
  61. fill:
  62. dirp->bpos = fill_dirent(&dirp->dent, dirp->buffer, dirp->bpos);
  63. return &dirp->dent;
  64. }