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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
extern crate nc;
use nc::Errno;
use crate::expand_env;
pub struct LnOptions {
pub expand_env: bool,
pub force: bool,
pub physical: bool,
pub logical: bool,
pub symbolic: bool,
}
impl Default for LnOptions {
fn default() -> LnOptions {
LnOptions {
expand_env: true,
force: false,
physical: true,
logical: false,
symbolic: false,
}
}
}
pub fn ln<T: AsRef<str>>(src: T, target: T, options: &LnOptions) -> Result<(), Errno> {
let src = if options.expand_env {
expand_env(src)
} else {
src.as_ref().to_string()
};
let logical_src: String = if options.logical {
let mut stat = nc::stat_t::default();
let _ret = nc::newfstatat(nc::AT_FDCWD, &src, &mut stat, 0)?;
if stat.st_mode == nc::S_IFLNK {
let mut buf: Vec<u8> = Vec::with_capacity(nc::PATH_MAX as usize);
let read_size = nc::readlinkat(nc::AT_FDCWD, &src, &mut buf)?;
let mut real_src = String::from_utf8_lossy(&buf).into_owned();
real_src.truncate((read_size + 1) as usize);
real_src
} else {
src
}
} else {
src
};
let target = if options.expand_env {
expand_env(target)
} else {
target.as_ref().to_string()
};
if options.force {
let _ret = nc::unlink(&target);
}
if options.symbolic {
return nc::symlink(&logical_src, &target);
} else {
return nc::link(&logical_src, &target);
}
}