mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 21:03:12 +00:00
parent
fa4daeee0f
commit
b64045dc18
4 changed files with 49 additions and 20 deletions
18
src/libc.c
18
src/libc.c
|
@ -1,3 +1,4 @@
|
||||||
|
#include <dirent.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -5,6 +6,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define UNUSED(x) (void)(x)
|
#define UNUSED(x) (void)(x)
|
||||||
|
@ -180,3 +182,19 @@ int C_RLIMIT_NTHR() {
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool C_portable_readdir(DIR* dirp, const char** d_name, size_t* d_name_len, uint64_t* d_ino, unsigned char* d_type) {
|
||||||
|
struct dirent *dent = readdir(dirp);
|
||||||
|
if (!dent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*d_name = dent->d_name;
|
||||||
|
*d_name_len = sizeof dent->d_name / sizeof **d_name;
|
||||||
|
#if defined(__BSD__)
|
||||||
|
*d_ino = dent->d_fileno;
|
||||||
|
#else
|
||||||
|
*d_ino = dent->d_ino;
|
||||||
|
#endif
|
||||||
|
*d_type = dent->d_type;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
20
src/libc.rs
20
src/libc.rs
|
@ -59,3 +59,23 @@ CVAR!(C_RLIMIT_RTTIME, RLIMIT_RTTIME, i32);
|
||||||
CVAR!(C_RLIMIT_KQUEUES, RLIMIT_KQUEUES, i32);
|
CVAR!(C_RLIMIT_KQUEUES, RLIMIT_KQUEUES, i32);
|
||||||
CVAR!(C_RLIMIT_NPTS, RLIMIT_NPTS, i32);
|
CVAR!(C_RLIMIT_NPTS, RLIMIT_NPTS, i32);
|
||||||
CVAR!(C_RLIMIT_NTHR, RLIMIT_NTHR, i32);
|
CVAR!(C_RLIMIT_NTHR, RLIMIT_NTHR, i32);
|
||||||
|
|
||||||
|
pub(crate) fn portable_readdir(dirp: *mut libc::DIR) -> Option<(*const c_char, usize, u64, u8)> {
|
||||||
|
let mut d_name = unsafe { std::mem::zeroed() };
|
||||||
|
let mut d_name_len = unsafe { std::mem::zeroed() };
|
||||||
|
let mut d_ino = unsafe { std::mem::zeroed() };
|
||||||
|
let mut d_type = unsafe { std::mem::zeroed() };
|
||||||
|
if !unsafe { C_portable_readdir(dirp, &mut d_name, &mut d_name_len, &mut d_ino, &mut d_type) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some((d_name, d_name_len, d_ino, d_type))
|
||||||
|
}
|
||||||
|
extern "C" {
|
||||||
|
fn C_portable_readdir(
|
||||||
|
dirp: *mut libc::DIR,
|
||||||
|
d_name: *mut *const c_char,
|
||||||
|
d_name_len: *mut usize,
|
||||||
|
d_ino: *mut u64,
|
||||||
|
d_type: *mut u8,
|
||||||
|
) -> bool;
|
||||||
|
}
|
||||||
|
|
|
@ -901,7 +901,7 @@ mod expander {
|
||||||
// Ensure we don't fall into a symlink loop.
|
// Ensure we don't fall into a symlink loop.
|
||||||
// Ideally we would compare both devices and inodes, but devices require a stat call, so we
|
// Ideally we would compare both devices and inodes, but devices require a stat call, so we
|
||||||
// use inodes exclusively.
|
// use inodes exclusively.
|
||||||
let mut visited_inodes: HashSet<libc::ino_t> = HashSet::new();
|
let mut visited_inodes: HashSet<u64> = HashSet::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut unique_entry = WString::new();
|
let mut unique_entry = WString::new();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use super::wopendir;
|
use super::wopendir;
|
||||||
use crate::common::{cstr2wcstring, wcs2zstring};
|
use crate::common::{cstr2wcstring, wcs2zstring};
|
||||||
|
use crate::libc::portable_readdir;
|
||||||
use crate::wchar::{wstr, WString};
|
use crate::wchar::{wstr, WString};
|
||||||
use crate::wutil::DevInode;
|
use crate::wutil::DevInode;
|
||||||
use libc::{
|
use libc::{
|
||||||
|
@ -34,7 +35,7 @@ pub struct DirEntry {
|
||||||
pub name: WString,
|
pub name: WString,
|
||||||
|
|
||||||
/// inode of this entry.
|
/// inode of this entry.
|
||||||
pub inode: libc::ino_t,
|
pub inode: u64,
|
||||||
|
|
||||||
// Device, inode pair for this entry, or none if not yet computed.
|
// Device, inode pair for this entry, or none if not yet computed.
|
||||||
dev_inode: Cell<Option<DevInode>>,
|
dev_inode: Cell<Option<DevInode>>,
|
||||||
|
@ -252,8 +253,7 @@ impl DirIter {
|
||||||
#[allow(clippy::should_implement_trait)]
|
#[allow(clippy::should_implement_trait)]
|
||||||
pub fn next(&mut self) -> Option<io::Result<&DirEntry>> {
|
pub fn next(&mut self) -> Option<io::Result<&DirEntry>> {
|
||||||
errno::set_errno(errno::Errno(0));
|
errno::set_errno(errno::Errno(0));
|
||||||
let dent = unsafe { libc::readdir(self.dir.dir()).as_ref() };
|
let Some((d_name, d_name_len, d_ino, d_type)) = portable_readdir(self.dir.dir()) else {
|
||||||
let Some(dent) = dent else {
|
|
||||||
// readdir distinguishes between EOF and error via errno.
|
// readdir distinguishes between EOF and error via errno.
|
||||||
let err = errno::errno().0;
|
let err = errno::errno().0;
|
||||||
if err == 0 {
|
if err == 0 {
|
||||||
|
@ -263,9 +263,10 @@ impl DirIter {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let d_name = unsafe { slice::from_raw_parts(d_name, d_name_len) };
|
||||||
// dent.d_name is c_char; pretend it's u8.
|
// dent.d_name is c_char; pretend it's u8.
|
||||||
assert!(std::mem::size_of::<libc::c_char>() == std::mem::size_of::<u8>());
|
assert!(std::mem::size_of::<libc::c_char>() == std::mem::size_of::<u8>());
|
||||||
let d_name_cchar = &dent.d_name;
|
let d_name_cchar = &d_name;
|
||||||
let d_name = unsafe {
|
let d_name = unsafe {
|
||||||
slice::from_raw_parts(d_name_cchar.as_ptr() as *const u8, d_name_cchar.len())
|
slice::from_raw_parts(d_name_cchar.as_ptr() as *const u8, d_name_cchar.len())
|
||||||
};
|
};
|
||||||
|
@ -276,22 +277,12 @@ impl DirIter {
|
||||||
return self.next();
|
return self.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
let nul_pos = dent.d_name.iter().position(|b| *b == 0).unwrap();
|
let nul_pos = d_name.iter().position(|b| *b == 0).unwrap();
|
||||||
let d_name: Vec<u8> = dent.d_name[..nul_pos + 1]
|
let d_name = &d_name[..nul_pos + 1];
|
||||||
.iter()
|
|
||||||
.map(|b| *b as u8)
|
|
||||||
.collect();
|
|
||||||
self.entry.reset();
|
self.entry.reset();
|
||||||
self.entry.name = cstr2wcstring(&d_name);
|
self.entry.name = cstr2wcstring(d_name);
|
||||||
#[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
self.entry.inode = d_ino;
|
||||||
{
|
let typ = dirent_type_to_entry_type(d_type);
|
||||||
self.entry.inode = dent.d_fileno;
|
|
||||||
}
|
|
||||||
#[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
|
|
||||||
{
|
|
||||||
self.entry.inode = dent.d_ino;
|
|
||||||
}
|
|
||||||
let typ = dirent_type_to_entry_type(dent.d_type);
|
|
||||||
// Do not store symlinks as we will need to resolve them.
|
// Do not store symlinks as we will need to resolve them.
|
||||||
if typ != Some(DirEntryType::lnk) {
|
if typ != Some(DirEntryType::lnk) {
|
||||||
self.entry.typ.set(typ);
|
self.entry.typ.set(typ);
|
||||||
|
|
Loading…
Reference in a new issue