Source code
Revision control
Copy as Markdown
Other Tools
use std::{
ffi::{CString, OsString},
fs::{self, DirEntry},
mem::{self},
os::unix::prelude::OsStrExt,
path::{Path, PathBuf},
};
use crate::mem_writer::MemoryWriter;
use super::*;
fn file_stat(path: &Path) -> Option<libc::stat> {
let c_path = CString::new(path.as_os_str().as_bytes()).ok()?;
let mut stat = unsafe { std::mem::zeroed::<libc::stat>() };
let result = unsafe { libc::stat(c_path.as_ptr(), &mut stat) };
if result == 0 {
Some(stat)
} else {
None
}
}
fn direntry_to_descriptor(buffer: &mut DumpBuf, entry: &DirEntry) -> Option<MDRawHandleDescriptor> {
let handle = filename_to_fd(&entry.file_name())?;
let realpath = fs::read_link(entry.path()).ok()?;
let path_rva = write_string_to_location(buffer, realpath.to_string_lossy().as_ref()).ok()?;
let stat = file_stat(&entry.path())?;
// TODO: We store the contents of `st_mode` into the `attributes` field, but
// we could also store a human-readable string of the file type inside
// `type_name_rva`. We might move this missing information (and
// more) inside a custom `MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE` blob.
// That would make this conversion loss-less.
Some(MDRawHandleDescriptor {
handle,
type_name_rva: 0,
object_name_rva: path_rva.rva,
attributes: stat.st_mode,
granted_access: 0,
handle_count: 0,
pointer_count: 0,
})
}
fn filename_to_fd(filename: &OsString) -> Option<u64> {
let filename = filename.to_string_lossy();
filename.parse::<u64>().ok()
}
pub fn write(
config: &mut MinidumpWriter,
buffer: &mut DumpBuf,
) -> Result<MDRawDirectory, errors::SectionHandleDataStreamError> {
let proc_fd_path = PathBuf::from(format!("/proc/{}/fd", config.process_id));
let proc_fd_iter = fs::read_dir(proc_fd_path)?;
let descriptors: Vec<_> = proc_fd_iter
.filter_map(|entry| entry.ok())
.filter_map(|entry| direntry_to_descriptor(buffer, &entry))
.collect();
let number_of_descriptors = descriptors.len() as u32;
let stream_header = MemoryWriter::<MDRawHandleDataStream>::alloc_with_val(
buffer,
MDRawHandleDataStream {
size_of_header: mem::size_of::<MDRawHandleDataStream>() as u32,
size_of_descriptor: mem::size_of::<MDRawHandleDescriptor>() as u32,
number_of_descriptors,
reserved: 0,
},
)?;
let mut dirent = MDRawDirectory {
stream_type: MDStreamType::HandleDataStream as u32,
location: stream_header.location(),
};
let descriptor_list =
MemoryArrayWriter::<MDRawHandleDescriptor>::alloc_from_iter(buffer, descriptors)?;
dirent.location.data_size += descriptor_list.location().data_size;
Ok(dirent)
}