rune/
dired.rs

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
89
use crate::core::{
    gc::Context,
    object::{Object, OptionalFlag, NIL, TRUE},
};
use rune_core::macros::list;
use rune_macros::defun;
use std::path::Path;

#[defun]
fn file_attributes<'ob>(filename: &str, _id_format: OptionalFlag, cx: &'ob Context) -> Object<'ob> {
    let file = Path::new(filename);
    if file.exists() {
        metadata_attributes(file, cx)
    } else {
        NIL
    }
}

#[cfg(unix)]
fn metadata_attributes<'ob>(file: &Path, cx: &'ob Context) -> Object<'ob> {
    use std::os::unix::fs::MetadataExt;
    let metadata = &file.metadata().unwrap();

    //  0. t for directory, string (name linked to) for symbolic link, or nil.
    let file_type = get_file_type(file, cx);
    //  1. Number of hardlinks to file.
    let links = metadata.nlink();
    //  2. File uid as a string or (if ID-FORMAT is integer or a string value
    //   cannot be looked up) as an integer.
    let uid = metadata.uid();
    //  3. File gid, likewise.
    let gid = metadata.gid();
    //  4. Last access time, in the style of current-time.
    //   (See a note below about access time on FAT-based filesystems.)
    let atime = metadata.atime();
    //  5. Last modification time, likewise.  This is the time of the last
    //   change to the file's contents.
    let mtime = metadata.mtime();
    //  6. Last status change time, likewise.  This is the time of last change
    //   to the file's attributes: owner and group, access mode bits, etc.
    let ctime = metadata.ctime();
    //  7. Size in bytes, as an integer.
    let size = metadata.size();
    //  8. File modes, as a string of ten letters or dashes as in ls -l.
    let mode = metadata.mode();
    //  9. An unspecified value, present only for backward compatibility.
    // 10. inode number, as a nonnegative integer.
    let inode = metadata.ino();
    // 11. Filesystem device identifier, as an integer or a cons cell of integers.
    let dev = metadata.dev();
    list![file_type, links, uid, gid, atime, mtime, ctime, size, mode, TRUE, inode, dev; cx]
}

#[cfg(windows)]
fn metadata_attributes<'ob>(file: &Path, cx: &'ob Context) -> Object<'ob> {
    use std::os::windows::fs::MetadataExt;
    let metadata = &file.metadata().unwrap();

    //  0. t for directory, string (name linked to) for symbolic link, or nil.
    let file_type = get_file_type(file, cx);
    // TODO: implement the rest of the attributes
    //  1. Number of hardlinks to file.
    //  2. File uid as a string or (if ID-FORMAT is integer or a string value
    //   cannot be looked up) as an integer.
    //  3. File gid, likewise.
    //  4. Last access time, in the style of current-time.
    //   (See a note below about access time on FAT-based filesystems.)
    //  5. Last modification time, likewise.  This is the time of the last
    //   change to the file's contents.
    //  6. Last status change time, likewise.  This is the time of last change
    //   to the file's attributes: owner and group, access mode bits, etc.
    //  7. Size in bytes, as an integer.
    //  8. File modes, as a string of ten letters or dashes as in ls -l.
    //  9. An unspecified value, present only for backward compatibility.
    // 10. inode number, as a nonnegative integer.
    // 11. Filesystem device identifier, as an integer or a cons cell of integers.
    panic!("file-attributes are not yet implemented for non-unix systems");
}

fn get_file_type<'ob>(file: &Path, cx: &'ob Context) -> Object<'ob> {
    if file.is_dir() {
        TRUE
    } else if file.is_symlink() {
        let target = file.read_link().unwrap();
        cx.add(target.to_str().unwrap())
    } else {
        NIL
    }
}