Compare commits

1 Commits

Author SHA1 Message Date
cff030a107 Index parsing 2026-03-04 14:27:22 +01:00
2 changed files with 113 additions and 32 deletions

View File

@@ -1,23 +1,77 @@
use std::{ use std::{
io::{ io::{
self, self,
prelude::*,
Error, Error,
}, },
fs::File,
fmt::Display,
path::Path,
}; };
use std::ffi::CStr;
use sha1::{Sha1, Digest};
use crate::GIT_DIR; use crate::GIT_DIR;
#[derive(Debug)]
pub enum ObjectType {
Regular,
SymLink,
GitLink,
}
impl Display for ObjectType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Self::Regular => write!(f, "Regular"),
Self::SymLink => write!(f, "Symlink"),
Self::GitLink => write!(f, "Gitlink"),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct IndexEntry { pub struct IndexEntry {
file_size: u32, entry_size: usize,
object_type: ObjectType,
permissions: u16,
hash: [u8; 20], hash: [u8; 20],
name: String, name: String,
} }
impl IndexEntry { impl IndexEntry {
fn from_bytes(bytes: Vec<u8>) -> io::Result<Self> { fn from_bytes(bytes: &[u8]) -> io::Result<Self> {
let mode = &bytes[24..28];
let ot_bin = mode[2] >> 4;
let object_type = match ot_bin {
0b1000 => ObjectType::Regular,
0b1010 => ObjectType::SymLink,
0b1110 => ObjectType::GitLink,
_ => return Err(Error::other(format!("Invalid object type: {}", ot_bin)))
};
let permissions = u16::from_be_bytes(mode[2..4].try_into().unwrap()) &!0xFE00;
match (permissions, &object_type) {
(0, ObjectType::GitLink) => (),
(0, ObjectType::SymLink) => (),
(0o755, ObjectType::Regular) => (),
(0o644, ObjectType::Regular) => (),
_ => return Err(Error::other(format!("Invalid permissions (0o{:o}) for type {}", permissions, object_type)))
};
return Err(Error::other("Not implemented")) let hash: [u8; 20] = bytes[40..60].try_into().unwrap();
let cname = CStr::from_bytes_until_nul(&bytes[62..]).unwrap();
let name = String::from(cname.to_str().unwrap());
let entry_size = usize::div_ceil(62 + cname.count_bytes(), 8) * 8;
Ok(IndexEntry { entry_size, object_type, permissions, hash, name })
}
fn to_bytes(&self) -> io::Result<Vec<u8>> {
let bytes = Vec::new();
Ok(bytes)
// Err(Error::other("Not implemented"))
} }
} }
@@ -28,29 +82,56 @@ pub struct Index {
} }
impl Index { impl Index {
pub fn from_bytes(bytes: Vec<u8>) -> io::Result<Self> { pub fn load() -> io::Result<Self> {
let magic: [u8; 4] = match bytes.first_chunk() { let path = Path::new(GIT_DIR)
None => return Err(Error::other("Error parsing index")), .join("index");
Some(magic) => *magic, let mut file = File::open(&path)?;
let mut content: Vec<u8> = Vec::new();
file.read_to_end(&mut content)?;
Index::from_bytes(content)
}
fn from_bytes(bytes: Vec<u8>) -> io::Result<Self> {
match &bytes[0..4] {
b"DIRC" => (),
_ => return Err(Error::other("Invalid index signature"))
}; };
match str::from_utf8(&magic) { let version = u32::from_be_bytes(bytes[4..8].try_into().unwrap());
Ok("DIRC") => (), let count = u32::from_be_bytes(bytes[8..12].try_into().unwrap());
_ => return Err(Error::other("Invalid index"))
let mut entries: Vec<IndexEntry> = Vec::with_capacity(usize::try_from(count).unwrap());
let mut offset = 12;
for _i in 0..count {
let entry = IndexEntry::from_bytes(&bytes[offset..])?;
offset += entry.entry_size;
entries.push(entry);
}; };
let version_bytes = <[u8; 4]>::try_from(&bytes.as_slice()[4..8]).unwrap(); let mut hasher = Sha1::new();
let version = u32::from_be_bytes(version_bytes); hasher.update(&bytes[..offset]);
let hash = hasher.finalize();
let count_bytes = <[u8; 4]>::try_from(&bytes.as_slice()[8..12]).unwrap();
let count = u32::from_be_bytes(count_bytes);
let entries: Vec<IndexEntry> = Vec::with_capacity(usize::try_from(count).unwrap());
for i in 0..=count {
};
if bytes[offset..] != *hash {
return Err(Error::other("Invalid index"));
}
return Ok(Index { version, entries}); return Ok(Index { version, entries});
} }
pub fn to_bytes(&self) -> io::Result<Vec<u8>> {
let mut bytes: Vec<u8> = Vec::new();
bytes.extend("DIRC".as_bytes());
bytes.extend(self.version.to_be_bytes());
let count: u32 = self.entries.len() as u32;
bytes.extend(count.to_be_bytes());
for entry in &self.entries {
bytes.extend(entry.to_bytes()?);
}
Ok(bytes)
}
} }

View File

@@ -1,6 +1,11 @@
use clap::Parser; use clap::Parser;
use std::fs; use std::{
fs::{File},
io::prelude::*,
path::Path
};
use crate::subcommands::Subcommand; use crate::subcommands::Subcommand;
use crate::git_fs::index::Index;
use super::CmdResult; use super::CmdResult;
@@ -11,18 +16,13 @@ pub struct TestSubcommand {
impl Subcommand for TestSubcommand { impl Subcommand for TestSubcommand {
fn run(&self) -> CmdResult { fn run(&self) -> CmdResult {
let metadata = match fs::metadata(self.path.clone()) { let index = Index::load().unwrap();
Ok(metadata) => metadata,
_ => return Err(String::from("")),
};
let mtime = match metadata.modified() { println!("{index:?}");
Ok(mtime) => mtime,
_ => return Err(String::from("")),
};
// mtime let path = Path::new(&self.path);
println!("{mtime:?}"); let mut file = File::create(path).unwrap();
let _ = file.write_all(&index.to_bytes().unwrap());
Ok(String::from("")) Ok(String::from(""))
} }