Skip to content

Instantly share code, notes, and snippets.

@sajattack
Last active November 10, 2017 02:18
Show Gist options
  • Save sajattack/f9fbe988be4ef8e9c3eade8c606fb86e to your computer and use it in GitHub Desktop.
Save sajattack/f9fbe988be4ef8e9c3eade8c606fb86e to your computer and use it in GitHub Desktop.
use ::{c_int, c_char};
extern crate libc;
extern crate core;
use syscall::{self, O_CLOEXEC, O_RDONLY, O_DIRECTORY, Stat};
use core::ptr::null;
use core::ptr;
use core::default::Default;
use core::mem::swap;
use alloc::boxed::Box;
use ::file::PATH_MAX;
use ::types::{ino_t, off_t};
use libc::*;
extern crate quicksort;
#[repr(C)]
pub struct dirent {
pub d_ino: ino_t,
pub d_off: off_t,
pub d_reclen: c_ushort,
pub d_type: c_uchar,
pub d_name: [c_char; PATH_MAX]
}
impl core::default::Default for dirent {
fn default() -> dirent {
dirent {
d_ino: 0,
d_off: 0,
d_reclen: 0,
d_type: 0,
d_name: [0; PATH_MAX],
}
}
}
pub struct DIR {
pub fd: ::RawFile,
pub ent: dirent,
pub buf: [u8; PATH_MAX],
pub count: usize,
pub pos: usize
}
libc_fn!(unsafe opendir(path: *mut c_char) -> Result<*mut DIR> {
let path = ::cstr_to_slice(path);
let fd = ::RawFile::open(path, O_RDONLY | O_CLOEXEC | O_DIRECTORY)?;
let dir = Box::new(DIR {
fd,
ent: dirent::default(),
buf: [0; PATH_MAX],
count: 0,
pos: 0
});
Ok(Box::into_raw(dir))
});
libc_fn!(unsafe readdir(dir: *mut DIR) -> Result<*const dirent> {
if let Some(dir) = dir.as_mut() {
let mut i = 0;
'outer: while i < PATH_MAX - 1 {
while dir.pos < dir.count {
dir.ent.d_name[i] = dir.buf[dir.pos] as c_char;
dir.pos += 1;
if dir.buf[dir.pos-1] == b'\n' {
break 'outer;
}
i += 1;
}
dir.count = syscall::read(*dir.fd, &mut dir.buf)?;
if dir.count == 0 {
break;
}
dir.pos = 0;
}
if i != 0 {
dir.ent.d_name[i] = 0;
return Ok(&dir.ent);
}
}
Ok(null())
});
libc_fn!(unsafe rewinddir(dir: *mut DIR) {
if let Some(dir) = dir.as_mut() {
dir.count = 0;
let _ = syscall::lseek(*dir.fd, 0, syscall::SEEK_SET);
}
});
libc_fn!(unsafe closedir(dir: *mut DIR) -> Result<c_int> {
Box::from_raw(dir);
Ok(0)
});
/*macro_rules! DIRSZ {
($dp:expr) => (sizeof(dirent) - sizeof($dp.d_name)) + ((($dp)->d_reclen + 1 + 3) &~ 3);
}*/
libc_fn!(unsafe scandir(dirname: *mut c_char,
namelist: *mut *mut *mut dirent,
filter: fn(*const dirent) -> Result<c_int, c_int>,
compar: fn(*const c_void, *const c_void) -> c_int)
-> Result<c_int, c_int> {
let mut d: dirent = dirent::default();
let mut p: dirent = dirent::default();
let mut nitems: size_t = 0;
let mut stb: syscall::Stat = Stat::default();
let mut arraysz: usize = 0;
let dirp: *mut DIR;
let dirname = "file:/home/user/\0".as_bytes().as_ptr() as *mut c_char;
let dirname_slice = ::cstr_to_slice(dirname);
let _ = syscall::write(2, dirname_slice);
let _ = syscall::write(2, "\n".as_bytes());
dirp = opendir(dirname);
if dirp.is_null() {
let _ = syscall::write(2, "null ptr at line 116\n".as_bytes());
perror("scandir\0".as_bytes().as_ptr() as *const c_char);
return Err(-1);
}
if let Some(dirp) = dirp.as_mut() {
if !syscall::call::fstat(*dirp.fd, &mut stb).is_ok() {
let _ = syscall::write(2, "error calling fstat at line 114\n".as_bytes());
return Err(-1);
}
/*
* estimate the array size by taking the size of the directory file
* and dividing it by a multiple of the minimum size entry.
*/
arraysz = (stb.st_size as usize) / 24;
let mut names: *mut *mut dirent = malloc(arraysz * ::mem::size_of::<dirent>()) as *mut _;
if names.is_null() {
let _ = syscall::write(2, "null ptr at line 131\n".as_bytes());
return Err(-1);
}
nitems = 0;
loop {
let d_ptr = readdir(dirp);
if d_ptr.is_null() {
break;
}
d = ptr::read(d_ptr);
let _ = syscall::write(2, ::cstr_to_slice(d.d_name.as_ptr()));
let _ = syscall::write(2, "\n".as_bytes());
/*if !filter(&mut d)
{ continue; }*/
p.d_ino = d.d_ino;
p.d_reclen = d.d_reclen;
p.d_name = d.d_name;
/*
* Check to make sure the array has space left and
* realloc the maximum size.
*/
if nitems+1 >= arraysz as usize {
if !syscall::call::fstat(*dirp.fd, &mut stb).is_ok() {
let _ = syscall::write(2, "error calling fstat line 157\n".as_bytes());
return Err(-1);
}
arraysz = (stb.st_size as usize) / 12;
let _ = syscall::write(2, "got to line 162\n".as_bytes());
names = realloc(names as *mut c_void, arraysz * ::mem::size_of::<dirent>() as usize) as *mut _;
if names.is_null() {
let _ = syscall::write(2, "null ptr at line 163\n".as_bytes());
return Err(-1);
}
}
*names.offset(nitems as isize -1) = &mut p;
let _ = syscall::write(2, "got to line 169\n".as_bytes());
nitems+=1;
let _ = syscall::write(2, ::cstr_to_slice(format!("{}\n", nitems).as_str().as_bytes().as_ptr() as *const c_char));
}
//closedir(dirp);
let _ = syscall::write(2, "got to line 175\n".as_bytes());
qsort(names, nitems, ::mem::size_of::<dirent>(), compar);
swap(&mut *namelist, &mut names);
}
Ok(nitems as i32)
});
libc_fn!(unsafe alphasort(a: *mut c_void, b: *mut c_void) -> c_int {
let _ = syscall::write(2, "got to alphasort\n".as_bytes());
let a: &mut dirent = unsafe { &mut *(a as *mut dirent) };
let b: &mut dirent = unsafe { &mut *(b as *mut dirent) };
strcmp(a.d_name.as_ptr(), b.d_name.as_ptr())
});
#[link(name="c")]
libc_fn!(qsort(base: *mut c_void, nmemb: size_t, size: size_t,
compar: extern fn(*const c_void, *const c_void, *const c_void) -> i32) {
});
fn native_compar<T>(a: *const T, b: *const T) -> c_int where T: Ord {
let mut rv: c_int = -2;
if *a < *b {
rv = -1;
} else if *a > *b {
rv = 1;
} else if *a == *b {
rv = 0;
}
rv
}
fn sort<T>(v: &mut [T]) where T: Ord {
unsafe {
qsort(v.as_mut_ptr() as *mut c_void,
v.len() as size_t,
::mem::size_of::<T>() as size_t,
native_compar);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment