From 571b4d49765b22dd763a0ea5dc06ebf32f67db91 Mon Sep 17 00:00:00 2001 From: jD91mZM2 <me@krake.one> Date: Thu, 1 Nov 2018 10:57:39 +0100 Subject: [PATCH] Fix getdents on redox --- src/header/dirent/mod.rs | 20 ++----- src/platform/redox/mod.rs | 111 ++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 51 deletions(-) diff --git a/src/header/dirent/mod.rs b/src/header/dirent/mod.rs index b2a133bd..fadb8576 100644 --- a/src/header/dirent/mod.rs +++ b/src/header/dirent/mod.rs @@ -21,9 +21,8 @@ pub struct DIR { index: usize, len: usize, - // Offset is like the total index, never erased It is used as an - // alternative to dirent's d_off, but works on redox too. - offset: usize, + // The last value of d_off, used by telldir + offset: usize } #[repr(C)] @@ -89,20 +88,7 @@ pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent { let ptr = (*dir).buf.as_mut_ptr().offset((*dir).index as isize) as *mut dirent; - #[cfg(target_os = "redox")] - { - if (*dir).index != 0 || (*dir).offset != 0 { - // This should happen every time but the first, making the offset - // point to the current element and not the next - (*dir).offset += mem::size_of::<dirent>(); - } - (*ptr).d_off = (*dir).offset as off_t; - } - #[cfg(not(target_os = "redox"))] - { - (*dir).offset = (*ptr).d_off as usize; - } - + (*dir).offset = (*ptr).d_off as usize; (*dir).index += (*ptr).d_reclen as usize; ptr } diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 92972a89..df4f67ad 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -418,50 +418,93 @@ impl Pal for Sys { } } - fn getdents(fd: c_int, mut dirents: *mut dirent, mut bytes: usize) -> c_int { - let mut amount = 0; + fn getdents(fd: c_int, mut dirents: *mut dirent, max_bytes: usize) -> c_int { + // Get initial reading position + let mut read = match syscall::lseek(fd as usize, 0, SEEK_CUR) { + Ok(pos) => pos as isize, + Err(err) => return -err.errno + }; + let mut written = 0; let mut buf = [0; 1024]; - let mut bindex = 0; - let mut blen = 0; let mut name = [0; 256]; - let mut nindex = 0; - - loop { - if bindex >= blen { - bindex = 0; - blen = match syscall::read(fd as usize, &mut buf) { - Ok(0) => return amount, - Ok(n) => n, - Err(err) => return -err.errno, + let mut i = 0; + + let mut flush = |written: &mut usize, i: &mut usize, name: &mut [c_char; 256]| { + if *i < name.len() { + // Set NUL byte + name[*i] = 0; + } + // Get size: full size - unused bytes + let size = mem::size_of::<dirent>() - name.len().saturating_sub(*i + 1); + if *written + size > max_bytes { + // Seek back to after last read entry and return + match syscall::lseek(fd as usize, read, SEEK_SET as usize) { + Ok(_) => return Some(*written as c_int), + Err(err) => return Some(-err.errno) + } + } + unsafe { + *dirents = dirent { + d_ino: 0, + d_off: read as off_t, + d_reclen: size as c_ushort, + d_type: 0, + d_name: *name }; + dirents = (dirents as *mut u8).offset(size as isize) as *mut dirent; } + read += *i as isize + /* newline */ 1; + *written += size; + *i = 0; + None + }; - if buf[bindex] == b'\n' { - // Put a NUL byte either at the end, or if it's too big, at where it's truncated. - name[nindex.min(name.len() - 1)] = 0; - unsafe { - *dirents = dirent { - d_ino: 0, - d_off: 0, - d_reclen: mem::size_of::<dirent>() as c_ushort, - d_type: 0, - d_name: name, + loop { + // Read a chunk from the directory + let len = match syscall::read(fd as usize, &mut buf) { + Ok(0) => { + if i > 0 { + if let Some(value) = flush(&mut written, &mut i, &mut name) { + return value; + } + } + return written as c_int; + }, + Ok(n) => n, + Err(err) => return -err.errno + }; + + // Handle everything + let mut start = 0; + while start < len { + let buf = &buf[start..len]; + + // Copy everything up until a newline + let newline = buf.iter().position(|&c| c == b'\n'); + let pre_len = newline.unwrap_or(buf.len()); + let post_len = newline.map(|i| i + 1).unwrap_or(buf.len()); + if i < pre_len { + // Reserve space for NUL byte + let name_len = name.len()-1; + let name = &mut name[i..name_len]; + let copy = pre_len.min(name.len()); + let buf = unsafe { + slice::from_raw_parts(buf.as_ptr() as *const c_char, copy) }; - dirents = dirents.offset(1); - } - amount += 1; - if bytes <= mem::size_of::<dirent>() { - return amount; + name[..copy].copy_from_slice(buf); } - bytes -= mem::size_of::<dirent>(); - } else { - if nindex < name.len() { - name[nindex] = buf[bindex] as c_char; + + i += pre_len; + start += post_len; + + // Write the directory entry + if newline.is_some() { + if let Some(value) = flush(&mut written, &mut i, &mut name) { + return value; + } } - nindex += 1; - bindex += 1; } } } -- GitLab