mod.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. //! dirent implementation following http://pubs.opengroup.org/onlinepubs/009695399/basedefs/dirent.h.html
  2. use alloc::boxed::Box;
  3. use core::{mem, ptr};
  4. use c_str::CStr;
  5. use fs::File;
  6. use header::{errno, fcntl, stdlib, string};
  7. use io::{Seek, SeekFrom};
  8. use platform;
  9. use platform::types::*;
  10. use platform::{Pal, Sys};
  11. const DIR_BUF_SIZE: usize = mem::size_of::<dirent>() * 3;
  12. // No repr(C) needed, C won't see the content
  13. pub struct DIR {
  14. file: File,
  15. buf: [c_char; DIR_BUF_SIZE],
  16. // index and len are specified in bytes
  17. index: usize,
  18. len: usize,
  19. // The last value of d_off, used by telldir
  20. offset: usize,
  21. }
  22. #[repr(C)]
  23. #[derive(Clone)]
  24. pub struct dirent {
  25. pub d_ino: ino_t,
  26. pub d_off: off_t,
  27. pub d_reclen: c_ushort,
  28. pub d_type: c_uchar,
  29. pub d_name: [c_char; 256],
  30. }
  31. #[no_mangle]
  32. pub unsafe extern "C" fn opendir(path: *const c_char) -> *mut DIR {
  33. let path = CStr::from_ptr(path);
  34. let file = match File::open(
  35. path,
  36. fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC,
  37. ) {
  38. Ok(file) => file,
  39. Err(_) => return ptr::null_mut(),
  40. };
  41. Box::into_raw(Box::new(DIR {
  42. file,
  43. buf: [0; DIR_BUF_SIZE],
  44. index: 0,
  45. len: 0,
  46. offset: 0,
  47. }))
  48. }
  49. #[no_mangle]
  50. pub unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int {
  51. let ret = {
  52. let mut dir = Box::from_raw(dir);
  53. let ret = Sys::close(*dir.file);
  54. // Reference files aren't closed when dropped
  55. dir.file.reference = true;
  56. //TODO: find out why dropping dir can crash
  57. mem::forget(dir);
  58. ret
  59. };
  60. ret
  61. }
  62. #[no_mangle]
  63. pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
  64. if (*dir).index >= (*dir).len {
  65. let read = Sys::getdents(
  66. *(*dir).file,
  67. (*dir).buf.as_mut_ptr() as *mut dirent,
  68. (*dir).buf.len(),
  69. );
  70. if read <= 0 {
  71. if read != 0 && read != -errno::ENOENT {
  72. platform::errno = -read;
  73. }
  74. return ptr::null_mut();
  75. }
  76. (*dir).index = 0;
  77. (*dir).len = read as usize;
  78. }
  79. let ptr = (*dir).buf.as_mut_ptr().add((*dir).index) as *mut dirent;
  80. (*dir).offset = (*ptr).d_off as usize;
  81. (*dir).index += (*ptr).d_reclen as usize;
  82. ptr
  83. }
  84. // #[no_mangle]
  85. pub extern "C" fn readdir_r(
  86. _dir: *mut DIR,
  87. _entry: *mut dirent,
  88. _result: *mut *mut dirent,
  89. ) -> *mut dirent {
  90. unimplemented!(); // plus, deprecated
  91. }
  92. #[no_mangle]
  93. pub unsafe extern "C" fn telldir(dir: *mut DIR) -> c_long {
  94. (*dir).offset as c_long
  95. }
  96. #[no_mangle]
  97. pub unsafe extern "C" fn seekdir(dir: *mut DIR, off: c_long) {
  98. let _ = (*dir).file.seek(SeekFrom::Start(off as u64));
  99. (*dir).offset = off as usize;
  100. (*dir).index = 0;
  101. (*dir).len = 0;
  102. }
  103. #[no_mangle]
  104. pub unsafe extern "C" fn rewinddir(dir: *mut DIR) {
  105. seekdir(dir, 0)
  106. }
  107. #[no_mangle]
  108. pub unsafe extern "C" fn alphasort(first: *mut *const dirent, second: *mut *const dirent) -> c_int {
  109. string::strcoll((**first).d_name.as_ptr(), (**second).d_name.as_ptr())
  110. }
  111. #[no_mangle]
  112. pub unsafe extern "C" fn scandir(
  113. dirp: *const c_char,
  114. namelist: *mut *mut *mut dirent,
  115. filter: Option<extern "C" fn(_: *const dirent) -> c_int>,
  116. compare: Option<extern "C" fn(_: *mut *const dirent, _: *mut *const dirent) -> c_int>,
  117. ) -> c_int {
  118. let dir = opendir(dirp);
  119. if dir.is_null() {
  120. return -1;
  121. }
  122. let old_errno = platform::errno;
  123. let mut len: isize = 0;
  124. let mut cap: isize = 4;
  125. *namelist = platform::alloc(cap as usize * mem::size_of::<*mut dirent>()) as *mut *mut dirent;
  126. loop {
  127. platform::errno = 0;
  128. let entry = readdir(dir);
  129. if entry.is_null() {
  130. break;
  131. }
  132. if let Some(filter) = filter {
  133. if filter(entry) == 0 {
  134. continue;
  135. }
  136. }
  137. if len >= cap {
  138. cap *= 2;
  139. *namelist = platform::realloc(
  140. *namelist as *mut c_void,
  141. cap as usize * mem::size_of::<*mut dirent>(),
  142. ) as *mut *mut dirent;
  143. }
  144. let copy = platform::alloc(mem::size_of::<dirent>()) as *mut dirent;
  145. *copy = (*entry).clone();
  146. *(*namelist).offset(len) = copy;
  147. len += 1;
  148. }
  149. closedir(dir);
  150. if platform::errno != 0 {
  151. while len > 0 {
  152. len -= 1;
  153. platform::free(*(*namelist).offset(len) as *mut c_void);
  154. }
  155. platform::free(*namelist as *mut c_void);
  156. -1
  157. } else {
  158. platform::errno = old_errno;
  159. stdlib::qsort(
  160. *namelist as *mut c_void,
  161. len as size_t,
  162. mem::size_of::<*mut dirent>(),
  163. mem::transmute(compare),
  164. );
  165. len as c_int
  166. }
  167. }