Skip to content

Commit 99c34b9

Browse files
committed
feat: add more directory query syscalls
Signed-off-by: Theo Paris <theo@theoparis.com>
1 parent 4f1d0b2 commit 99c34b9

File tree

3 files changed

+451
-2
lines changed

3 files changed

+451
-2
lines changed

kernel/nt.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub const STATUS_END_OF_FILE: NtStatus = 0xC000_0011u32 as i32;
2929
pub const STATUS_UNSUCCESSFUL: NtStatus = 0xC000_0001u32 as i32;
3030
pub const STATUS_PENDING: NtStatus = 0x0000_0103u32 as i32;
3131
pub const STATUS_TIMEOUT: NtStatus = 0x0000_0102u32 as i32;
32+
pub const STATUS_NO_MORE_ENTRIES: NtStatus = 0x8000_001Au32 as i32;
3233
pub const STATUS_IMAGE_MACHINE_TYPE_MISMATCH: NtStatus = 0x4000_002Eu32 as i32;
3334
pub const STATUS_INVALID_IMAGE_FORMAT: NtStatus = 0xC000_007Bu32 as i32;
3435
pub const STATUS_NOT_SUPPORTED: NtStatus = 0xC000_00BBu32 as i32;
@@ -82,6 +83,12 @@ pub const FILE_STANDARD_INFORMATION_CLASS: u32 = 5;
8283
pub const FILE_POSITION_INFORMATION_CLASS: u32 = 14;
8384
pub const FILE_NAME_INFORMATION_CLASS: u32 = 9;
8485
pub const MEMORY_BASIC_INFORMATION_CLASS: u32 = 0;
86+
pub const FILE_FS_SIZE_INFORMATION_CLASS: u32 = 3;
87+
pub const FILE_FS_DEVICE_INFORMATION_CLASS: u32 = 4;
88+
pub const FILE_FS_ATTRIBUTE_INFORMATION_CLASS: u32 = 5;
89+
pub const FILE_DEVICE_DISK: u32 = 0x00000007;
90+
pub const FILE_CASE_SENSITIVE_SEARCH: u32 = 0x00000001;
91+
pub const FILE_CASE_PRESERVED_NAMES: u32 = 0x00000002;
8592

8693
pub const EVENT_TYPE_NOTIFICATION: u32 = 0;
8794
pub const EVENT_TYPE_SYNCHRONIZATION: u32 = 1;
@@ -751,6 +758,128 @@ pub fn open_section(name: &str) -> Result<u32, NtStatus> {
751758
Err(STATUS_OBJECT_NAME_NOT_FOUND)
752759
}
753760

761+
pub fn open_directory(name: &str) -> Result<u32, NtStatus> {
762+
init_namespace();
763+
let canonical = canonicalize_nt_path(name);
764+
let mut objects = OBJECTS.lock();
765+
let Some(id) = objects.named.get(&canonical).copied() else {
766+
return Err(STATUS_OBJECT_NAME_NOT_FOUND);
767+
};
768+
let Some(record) = objects.objects.get_mut(&id) else {
769+
return Err(STATUS_OBJECT_NAME_NOT_FOUND);
770+
};
771+
if record.object_type != ObjectType::Directory {
772+
return Err(STATUS_OBJECT_TYPE_MISMATCH);
773+
}
774+
record.refs = record.refs.saturating_add(1);
775+
Ok(id)
776+
}
777+
778+
pub fn open_symbolic_link(name: &str) -> Result<u32, NtStatus> {
779+
init_namespace();
780+
let canonical = canonicalize_nt_path(name);
781+
let mut objects = OBJECTS.lock();
782+
let Some(id) = objects.named.get(&canonical).copied() else {
783+
return Err(STATUS_OBJECT_NAME_NOT_FOUND);
784+
};
785+
let Some(record) = objects.objects.get_mut(&id) else {
786+
return Err(STATUS_OBJECT_NAME_NOT_FOUND);
787+
};
788+
if record.object_type != ObjectType::SymbolicLink {
789+
return Err(STATUS_OBJECT_TYPE_MISMATCH);
790+
}
791+
record.refs = record.refs.saturating_add(1);
792+
Ok(id)
793+
}
794+
795+
pub fn query_symbolic_link_target(object_id: u32) -> Result<String, NtStatus> {
796+
let objects = OBJECTS.lock();
797+
let Some(record) = objects.objects.get(&object_id) else {
798+
return Err(STATUS_INVALID_HANDLE);
799+
};
800+
match &record.data {
801+
ObjectData::SymbolicLink { target } => Ok(target.clone()),
802+
_ => Err(STATUS_OBJECT_TYPE_MISMATCH),
803+
}
804+
}
805+
806+
fn object_type_name(kind: ObjectType) -> &'static str {
807+
match kind {
808+
ObjectType::Directory => "Directory",
809+
ObjectType::SymbolicLink => "SymbolicLink",
810+
ObjectType::File => "File",
811+
ObjectType::Key => "Key",
812+
ObjectType::Section => "Section",
813+
ObjectType::Process => "Process",
814+
ObjectType::Thread => "Thread",
815+
ObjectType::Event => "Event",
816+
}
817+
}
818+
819+
pub fn query_directory_entries(object_id: u32) -> Result<Vec<(String, String)>, NtStatus> {
820+
let objects = OBJECTS.lock();
821+
let Some(record) = objects.objects.get(&object_id) else {
822+
return Err(STATUS_INVALID_HANDLE);
823+
};
824+
if record.object_type != ObjectType::Directory {
825+
return Err(STATUS_OBJECT_TYPE_MISMATCH);
826+
}
827+
let Some(dir_path) = record.name.as_ref() else {
828+
return Err(STATUS_OBJECT_NAME_NOT_FOUND);
829+
};
830+
831+
let mut entries: BTreeMap<String, String> = BTreeMap::new();
832+
if dir_path == "\\" {
833+
for (name, child_id) in &objects.named {
834+
if name == "\\" {
835+
continue;
836+
}
837+
let Some(rest) = name.strip_prefix('\\') else {
838+
continue;
839+
};
840+
if rest.is_empty() {
841+
continue;
842+
}
843+
let child = rest.split('\\').next().unwrap_or("");
844+
if child.is_empty() {
845+
continue;
846+
}
847+
let full = format!("\\{}", child);
848+
let Some(child_record) = objects.objects.get(child_id) else {
849+
continue;
850+
};
851+
entries.insert(
852+
child.to_string(),
853+
object_type_name(child_record.object_type).to_string(),
854+
);
855+
let _ = full;
856+
}
857+
} else {
858+
let prefix = format!("{dir_path}\\");
859+
for (name, child_id) in &objects.named {
860+
if !name.starts_with(&prefix) {
861+
continue;
862+
}
863+
let rest = &name[prefix.len()..];
864+
if rest.is_empty() {
865+
continue;
866+
}
867+
let child = rest.split('\\').next().unwrap_or("");
868+
if child.is_empty() {
869+
continue;
870+
}
871+
let Some(child_record) = objects.objects.get(child_id) else {
872+
continue;
873+
};
874+
entries.insert(
875+
child.to_string(),
876+
object_type_name(child_record.object_type).to_string(),
877+
);
878+
}
879+
}
880+
Ok(entries.into_iter().collect())
881+
}
882+
754883
pub fn create_process(pid: u32) -> u32 {
755884
let mut objects = OBJECTS.lock();
756885
insert_unnamed(

kernel/syscall.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ extern "sysv64" fn syscall_dispatch(frame: *mut SyscallFrame) -> usize {
300300
frame.r9 as u32,
301301
stack_arg(frame, 0) != 0,
302302
) as usize,
303-
73 => user::query_information_file(
303+
73 => user::query_volume_information_file(
304304
frame.r10,
305305
frame.rdx as *mut nt::IoStatusBlock,
306306
frame.r8 as *mut u8,
@@ -332,6 +332,30 @@ extern "sysv64" fn syscall_dispatch(frame: *mut SyscallFrame) -> usize {
332332
) as usize,
333333
91 => user::query_system_time(frame.r10 as *mut i64) as usize,
334334
228 => user::display_string(frame.r10 as *const nt::UnicodeString) as usize,
335+
88 => user::open_directory_object(
336+
frame.r10 as *mut usize,
337+
frame.rdx as u32,
338+
frame.r8 as *const nt::ObjectAttributes,
339+
) as usize,
340+
312 => user::open_symbolic_link_object(
341+
frame.r10 as *mut usize,
342+
frame.rdx as u32,
343+
frame.r8 as *const nt::ObjectAttributes,
344+
) as usize,
345+
334 => user::query_directory_object(
346+
frame.r10,
347+
frame.rdx as *mut u8,
348+
frame.r8 as u32,
349+
frame.r9 != 0,
350+
stack_arg(frame, 0) != 0,
351+
stack_arg(frame, 1) as *mut u32,
352+
stack_arg(frame, 2) as *mut u32,
353+
) as usize,
354+
363 => user::query_symbolic_link_object(
355+
frame.r10,
356+
frame.rdx as *mut nt::UnicodeString,
357+
frame.r8 as *mut u32,
358+
) as usize,
335359
nt::SYSCALL_NT_CLOSE => user::close_handle(frame.a0) as usize,
336360
nt::SYSCALL_NT_QUERY_INFORMATION_PROCESS => user::query_information_process(
337361
frame.a0,

0 commit comments

Comments
 (0)