1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use std::path::PathBuf;

extern crate path_absolutize;
use path_absolutize::Absolutize;

#[no_mangle]
///Mutates the path in-place
///Canonicalizes the entire path, if it is possible 
///If it is not possible, then it canonicalizes the head of the path and then appends the tail to it 
///Repeats the process until either the head is successfully canonicalized or the head is the root directory  
fn step_by_step_canonicalize(path: &mut PathBuf) {

    let mut components = path.components().collect::<Vec<_>>();
    let mut head = path.clone();
    let mut tail = PathBuf::new();
    let mut result = head.canonicalize(); 
    let mut component; 
    let mut cx; 

    //Canonicalize the head 
    //If error is raised, head = head.parent 
    //And then loop again
    //If head.parent is None, then return the original path without mutation 
    //Otherwise, return the canonicalized head with the tail components attached 
    while result.is_err(){
        head = match head.parent(){
            Some(parent) => parent.to_path_buf(),
            None => return,
        };

        result = head.canonicalize();
        component = components.pop();

        match component{
            Some(component) => {
                //tail = component\tail
                cx = PathBuf::from(component.as_os_str());
                tail = cx.join(tail);
            }
            None => return,
        } 
    }
    
    let result = result.unwrap().join(tail);
    let result = result.absolutize().unwrap().to_path_buf();
    
    //Remove last / from the result 

    *path = result;

}


///Takes a PathBuf as input 
///Normalizes it, removes any trailing slashes, intermediate dots, and such 
///Traces symlinks and processes as far as can be canonicalized
///If only a part of the path is canonicalize-able, then the remaining part is appended as is to the canonicalized part
///Returns the canonicalized path as a PathBuf
///Returns an Error if there is some problem with absolutization/canonicalization
///Error => std::io::Error
pub fn realpath(path: &PathBuf) -> Result<PathBuf, std::io::Error> {
    
    let mut path = path.absolutize()?.to_path_buf();

    step_by_step_canonicalize(&mut path);
    Ok(path)
}