pub fn parse_index() -> Result<(IndexHeader, Vec<IndexFile>), String> {
    let mut file = fs::File::open(INDEX_PATH).expect("Could not read index file");

    let mut header = [0; 12];
    file.read_exact(&mut header).expect("Invalid index file");

    // Check magic number (DIRC)
    if header[..4].to_vec() != vec![0x44, 0x49, 0x52, 0x43] {
        return Err("invalid file type, expected DIRC".to_owned());
    }

    // Check verison number (2)
    // 3 and 4 are also valid versions, but not currently supported
    if header[4..8].to_vec() != vec![0x00, 0x00, 0x00, 0x02] {
        return Err("unsupported index version".to_owned());
    }

    let num_file = array_to_int(&header[8..]);

    // First 2 fields should be constant since we check for the magic 'number'
    // and only support 1 verison
    let index_header = IndexHeader {
        magic: String::from("DIRC"),
        version: 2,
        num_files: num_file,
    };

    let mut index_files = Vec::<IndexFile>::new();

    for _ in 0..num_file {
        // Read 6 32-bit (24-byte) info fields
        // ctime seconds, ctime nanosecond fractions, mtime seconds, mtime nanosecond fractions, dev (null on windows), ino (null on windows)
        let mut info_fields = [0; 24];
        file.read_exact(&mut info_fields)
            .expect("Invalid index format");

        let ctime = array_to_int(&info_fields[0..4]);
        let ctime_fractions = array_to_int(&info_fields[4..8]);
        let mtime = array_to_int(&info_fields[8..12]);
        let mtime_fractions = array_to_int(&info_fields[12..16]);
        let dev = array_to_int(&info_fields[16..20]);
        let ino = array_to_int(&info_fields[20..24]);

        let mut mode = [0; 2];
        file.read_exact(&mut mode).expect("Invalid index format");

        // read 3 32-bit (12 bytes) info fields
        // uid (null on windows), guid (null on windows), file size
        let mut file_info = [0; 12];
        file.read_exact(&mut file_info)
            .expect("Invalid index format");

        let uid = array_to_int(&file_info[0..4]);
        let guid = array_to_int(&file_info[4..8]);
        let size = array_to_int(&file_info[8..12]);

        let mut hash = [0; 20];
        file.read_exact(&mut hash).expect("Invalid index format");

        let mut flags = [0; 2];
        file.read_exact(&mut flags).expect("Invalid index format");
        let filename_length = flags_to_length(&flags);

        let mut filename_buf = vec![0; filename_length as usize].into_boxed_slice();
        file.read_exact(&mut filename_buf)
            .expect("Invalid index format");

        // Read at least one NUL byte (and up to 8),
        // the filename ends with a NUL-terminator, and is padded to the nearest multiple of 8 bytes (for the entry)
        let bytes_read = 60; // bytes written for an entry
        let total_bytes = bytes_read + filename_length;
        let padding = 8 - (total_bytes % 8);
        let mut nul_buf = vec![0; padding as usize].into_boxed_slice();
        file.read_exact(&mut nul_buf).expect("Invalid index format");

        let permissions = mode_to_permissions(&mode);
        let filename = str::from_utf8(&filename_buf).unwrap();

        index_files.push(IndexFile {
            ctime,
            ctime_fractions,
            mtime,
            mtime_fractions,
            dev: if dev == 0 { None } else { Some(dev) },
            ino: if ino == 0 { None } else { Some(ino) },
            permissions: String::from(permissions),
            uid: if uid == 0 { None } else { Some(uid) },
            gid: if guid == 0 { None } else { Some(guid) },
            size,
            object_hash: object_util::to_hex_string(&hash),
            filename: String::from(filename),
        });
    }

    Ok((index_header, index_files))
}
/// Parse the index file and return the index header and index files
Parse the index file and return the index header and index files
Parse the index file and return the index header and index files
pub fn parse_index() -> Result<(IndexHeader, Vec<IndexFile>), String> {
    let mut file = fs::File::open(INDEX_PATH).expect("Could not read index file");
    let mut header = [0; 12];
    file.read_exact(&mut header).expect("Invalid index file");
    // Check magic number (DIRC)
    if header[..4].to_vec() != vec![0x44, 0x49, 0x52, 0x43] {
        return Err("invalid file type, expected DIRC".to_owned());
    }
    // Check verison number (2)
    // 3 and 4 are also valid versions, but not currently supported
    if header[4..8].to_vec() != vec![0x00, 0x00, 0x00, 0x02] {
        return Err("unsupported index version".to_owned());
    }
    let num_file = array_to_int(&header[8..]);
    // First 2 fields should be constant since we check for the magic 'number'
    // and only support 1 verison
    let index_header = IndexHeader {
        magic: String::from("DIRC"),
        version: 2,
        num_files: num_file,
    };
    let mut index_files = Vec::<IndexFile>::new();
    for _ in 0..num_file {
        // Read 6 32-bit (24-byte) info fields
        // ctime seconds, ctime nanosecond fractions, mtime seconds, mtime nanosecond fractions, dev (null on windows), ino (null on windows)
        let mut info_fields = [0; 24];
        file.read_exact(&mut info_fields)
            .expect("Invalid index format");
        let ctime = array_to_int(&info_fields[0..4]);
        let ctime_fractions = array_to_int(&info_fields[4..8]);
        let mtime = array_to_int(&info_fields[8..12]);
        let mtime_fractions = array_to_int(&info_fields[12..16]);
        let dev = array_to_int(&info_fields[16..20]);
        let ino = array_to_int(&info_fields[20..24]);
        let mut mode = [0; 2];
        file.read_exact(&mut mode).expect("Invalid index format");
        // read 3 32-bit (12 bytes) info fields
        // uid (null on windows), guid (null on windows), file size
        let mut file_info = [0; 12];
        file.read_exact(&mut file_info)
            .expect("Invalid index format");
        let uid = array_to_int(&file_info[0..4]);
        let guid = array_to_int(&file_info[4..8]);
        let size = array_to_int(&file_info[8..12]);
        let mut hash = [0; 20];
        file.read_exact(&mut hash).expect("Invalid index format");
        let mut flags = [0; 2];
        file.read_exact(&mut flags).expect("Invalid index format");
        let filename_length = flags_to_length(&flags);
        let mut filename_buf = vec![0; filename_length as usize].into_boxed_slice();
        file.read_exact(&mut filename_buf)
            .expect("Invalid index format");
        // Read at least one NUL byte (and up to 8),
        // the filename ends with a NUL-terminator, and is padded to the nearest multiple of 8 bytes (for the entry)
        let bytes_read = 60; // bytes written for an entry
        let total_bytes = bytes_read + filename_length;
        let padding = 8 - (total_bytes % 8);
        let mut nul_buf = vec![0; padding as usize].into_boxed_slice();
        file.read_exact(&mut nul_buf).expect("Invalid index format");
        let permissions = mode_to_permissions(&mode);
        let filename = str::from_utf8(&filename_buf).unwrap();
        index_files.push(IndexFile {
            ctime,
            ctime_fractions,
            mtime,
            mtime_fractions,
            dev: if dev == 0 { None } else { Some(dev) },
            ino: if ino == 0 { None } else { Some(ino) },
            permissions: String::from(permissions),
            uid: if uid == 0 { None } else { Some(uid) },
            gid: if guid == 0 { None } else { Some(guid) },
            size,
            object_hash: object_util::to_hex_string(&hash),
            filename: String::from(filename),
        });
    }
    Ok((index_header, index_files))
}
pub fn parse_index ( ) -> Result < ( IndexHeader , Vec < IndexFile > ) , String > { let mut file = fs :: File :: open ( INDEX_PATH ) . expect ( " " ) ; let mut header = [ 0 ; 12 ] ; file . read_exact ( & mut header ) . expect ( " " ) ; // Check magic number (DIRC) if header [ .. 4 ] . to_vec ( ) != vec ! [ 0x44 0x49 0x52 0x43 ] { return Err ( " " . to_owned ( ) ) ; } // Check verison number (2) // 3 and 4 are also valid versions, but not currently supported if header [ 4 .. 8 ] . to_vec ( ) != vec ! [ 0x00 0x00 0x00 0x02 ] { return Err ( " " . to_owned ( ) ) ; } let num_file = array_to_int ( & header [ 8 .. ] ) ; // First 2 fields should be constant since we check for the magic 'number' // and only support 1 verison let index_header = IndexHeader { magic : String :: from ( " " ) , version : 2 , num_files : num_file , } ; let mut index_files = Vec :: < IndexFile > :: new ( ) ; for _ in 0 .. num_file { // Read 6 32-bit (24-byte) info fields // ctime seconds, ctime nanosecond fractions, mtime seconds, mtime nanosecond fractions, dev (null on windows), ino (null on windows) let mut info_fields = [ 0 ; 24 ] ; file . read_exact ( & mut info_fields ) . expect ( " " ) ; let ctime = array_to_int ( & info_fields [ 0 .. 4 ] ) ; let ctime_fractions = array_to_int ( & info_fields [ 4 .. 8 ] ) ; let mtime = array_to_int ( & info_fields [ 8 .. 12 ] ) ; let mtime_fractions = array_to_int ( & info_fields [ 12 .. 16 ] ) ; let dev = array_to_int ( & info_fields [ 16 .. 20 ] ) ; let ino = array_to_int ( & info_fields [ 20 .. 24 ] ) ; let mut mode = [ 0 ; 2 ] ; file . read_exact ( & mut mode ) . expect ( " " ) ; // read 3 32-bit (12 bytes) info fields // uid (null on windows), guid (null on windows), file size let mut file_info = [ 0 ; 12 ] ; file . read_exact ( & mut file_info ) . expect ( " " ) ; let uid = array_to_int ( & file_info [ 0 .. 4 ] ) ; let guid = array_to_int ( & file_info [ 4 .. 8 ] ) ; let size = array_to_int ( & file_info [ 8 .. 12 ] ) ; let mut hash = [ 0 ; 20 ] ; file . read_exact ( & mut hash ) . expect ( " " ) ; let mut flags = [ 0 ; 2 ] ; file . read_exact ( & mut flags ) . expect ( " " ) ; let filename_length = flags_to_length ( & flags ) ; let mut filename_buf = vec ! [ 0 filename_length as usize ] . into_boxed_slice ( ) ; file . read_exact ( & mut filename_buf ) . expect ( " " ) ; // Read at least one NUL byte (and up to 8), // the filename ends with a NUL-terminator, and is padded to the nearest multiple of 8 bytes (for the entry) let bytes_read = 60 ; // bytes written for an entry let total_bytes = bytes_read + filename_length ; let padding = 8 - ( total_bytes % 8 ) ; let mut nul_buf = vec ! [ 0 padding as usize ] . into_boxed_slice ( ) ; file . read_exact ( & mut nul_buf ) . expect ( " " ) ; let permissions = mode_to_permissions ( & mode ) ; let filename = str :: from_utf8 ( & filename_buf ) . unwrap ( ) ; index_files . push ( IndexFile { ctime , ctime_fractions , mtime , mtime_fractions , dev : if dev == 0 { None } else { Some ( dev ) } , ino : if ino == 0 { None } else { Some ( ino ) } , permissions : String :: from ( permissions ) , uid : if uid == 0 { None } else { Some ( uid ) } , gid : if guid == 0 { None } else { Some ( guid ) } , size , object_hash : object_util :: to_hex_string ( & hash ) , filename : String :: from ( filename ) , } ) ; } Ok ( ( index_header , index_files ) ) }
Parse the index file and return the index header and index files
Parse the index file and return the index header and index files