mirror of
https://github.com/vlang/v.git
synced 2025-08-03 17:57:59 -04:00
os: add os.stat() and helpers (#20739)
This commit is contained in:
parent
ee55e9b461
commit
205f2ddd30
15
vlib/os/os.v
15
vlib/os/os.v
@ -977,3 +977,18 @@ pub fn config_dir() !string {
|
|||||||
}
|
}
|
||||||
return error('Cannot find config directory')
|
return error('Cannot find config directory')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Stat {
|
||||||
|
pub:
|
||||||
|
dev u64
|
||||||
|
inode u64
|
||||||
|
mode u32
|
||||||
|
nlink u64
|
||||||
|
uid u32
|
||||||
|
gid u32
|
||||||
|
rdev u64
|
||||||
|
size u64
|
||||||
|
atime i64
|
||||||
|
mtime i64
|
||||||
|
ctime i64
|
||||||
|
}
|
||||||
|
81
vlib/os/os_stat_default.c.v
Normal file
81
vlib/os/os_stat_default.c.v
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
module os
|
||||||
|
|
||||||
|
// stat returns a platform-agnostic Stat struct comparable to what is
|
||||||
|
// available in other programming languages and fails with the POSIX
|
||||||
|
// error if the stat call fails. If a link is stat'd, the stat info
|
||||||
|
// for the link is provided.
|
||||||
|
pub fn stat(path string) !Stat {
|
||||||
|
mut s := C.stat{}
|
||||||
|
unsafe {
|
||||||
|
res := C.lstat(&char(path.str), &s)
|
||||||
|
if res != 0 {
|
||||||
|
return error_posix()
|
||||||
|
}
|
||||||
|
return Stat{
|
||||||
|
dev: s.st_dev
|
||||||
|
inode: s.st_ino
|
||||||
|
nlink: s.st_nlink
|
||||||
|
mode: s.st_mode
|
||||||
|
uid: s.st_uid
|
||||||
|
gid: s.st_gid
|
||||||
|
rdev: s.st_rdev
|
||||||
|
size: s.st_size
|
||||||
|
atime: s.st_atime
|
||||||
|
mtime: s.st_mtime
|
||||||
|
ctime: s.st_ctime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_filetype returns the FileType from the Stat struct
|
||||||
|
pub fn (st Stat) get_filetype() FileType {
|
||||||
|
match st.mode & u32(C.S_IFMT) {
|
||||||
|
u32(C.S_IFREG) {
|
||||||
|
return .regular
|
||||||
|
}
|
||||||
|
u32(C.S_IFDIR) {
|
||||||
|
return .directory
|
||||||
|
}
|
||||||
|
u32(C.S_IFCHR) {
|
||||||
|
return .character_device
|
||||||
|
}
|
||||||
|
u32(C.S_IFBLK) {
|
||||||
|
return .block_device
|
||||||
|
}
|
||||||
|
u32(C.S_IFIFO) {
|
||||||
|
return .fifo
|
||||||
|
}
|
||||||
|
u32(C.S_IFLNK) {
|
||||||
|
return .symbolic_link
|
||||||
|
}
|
||||||
|
u32(C.S_IFSOCK) {
|
||||||
|
return .socket
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return .unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_mode returns the file type and permissions (readable, writable, executable)
|
||||||
|
// in owner/group/others format
|
||||||
|
pub fn (st Stat) get_mode() FileMode {
|
||||||
|
return FileMode{
|
||||||
|
typ: st.get_filetype()
|
||||||
|
owner: FilePermission{
|
||||||
|
read: (st.mode & u32(C.S_IRUSR)) != 0
|
||||||
|
write: (st.mode & u32(C.S_IWUSR)) != 0
|
||||||
|
execute: (st.mode & u32(C.S_IXUSR)) != 0
|
||||||
|
}
|
||||||
|
group: FilePermission{
|
||||||
|
read: (st.mode & u32(C.S_IRGRP)) != 0
|
||||||
|
write: (st.mode & u32(C.S_IWGRP)) != 0
|
||||||
|
execute: (st.mode & u32(C.S_IXGRP)) != 0
|
||||||
|
}
|
||||||
|
others: FilePermission{
|
||||||
|
read: (st.mode & u32(C.S_IROTH)) != 0
|
||||||
|
write: (st.mode & u32(C.S_IWOTH)) != 0
|
||||||
|
execute: (st.mode & u32(C.S_IXOTH)) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
vlib/os/os_stat_test.v
Normal file
57
vlib/os/os_stat_test.v
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import os
|
||||||
|
import rand
|
||||||
|
import time
|
||||||
|
|
||||||
|
fn test_stat() {
|
||||||
|
start_time := time.utc()
|
||||||
|
|
||||||
|
temp_dir := os.join_path(os.temp_dir(), rand.ulid())
|
||||||
|
os.mkdir(temp_dir)!
|
||||||
|
defer {
|
||||||
|
os.rmdir(temp_dir) or {}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_file := os.join_path(temp_dir, rand.ulid())
|
||||||
|
test_content := rand.ulid()
|
||||||
|
os.write_file(test_file, test_content)!
|
||||||
|
defer {
|
||||||
|
os.rm(test_file) or {}
|
||||||
|
}
|
||||||
|
|
||||||
|
end_time := time.utc()
|
||||||
|
|
||||||
|
mut fstat := os.stat(test_file)!
|
||||||
|
assert fstat.get_filetype() == .regular
|
||||||
|
assert fstat.size == u64(test_content.len)
|
||||||
|
assert fstat.ctime >= start_time.unix
|
||||||
|
assert fstat.ctime <= end_time.unix
|
||||||
|
assert fstat.mtime >= start_time.unix
|
||||||
|
assert fstat.mtime <= end_time.unix
|
||||||
|
|
||||||
|
$if !windows {
|
||||||
|
os.chmod(test_file, 0o600)!
|
||||||
|
fstat = os.stat(test_file)!
|
||||||
|
|
||||||
|
mut fmode := fstat.get_mode()
|
||||||
|
assert fmode.typ == .regular
|
||||||
|
assert fmode.owner.read && fmode.owner.write && !fmode.owner.execute
|
||||||
|
assert !fmode.group.read && !fmode.group.write && !fmode.group.execute
|
||||||
|
assert !fmode.others.read && !fmode.others.write && !fmode.others.execute
|
||||||
|
|
||||||
|
os.chmod(test_file, 0o421)!
|
||||||
|
fstat = os.stat(test_file)!
|
||||||
|
fmode = fstat.get_mode()
|
||||||
|
assert fmode.owner.read && !fmode.owner.write && !fmode.owner.execute
|
||||||
|
assert !fmode.group.read && fmode.group.write && !fmode.group.execute
|
||||||
|
assert !fmode.others.read && !fmode.others.write && fmode.others.execute
|
||||||
|
|
||||||
|
os.chmod(test_file, 0o600)!
|
||||||
|
}
|
||||||
|
|
||||||
|
// When using the Time struct, allow for up to 1 second difference due to nanoseconds
|
||||||
|
// which are not captured in the timestamp
|
||||||
|
dstat := os.stat(temp_dir)!
|
||||||
|
assert dstat.get_filetype() == .directory
|
||||||
|
assert fstat.dev == dstat.dev, 'File and directory should be created on same device'
|
||||||
|
assert fstat.rdev == dstat.rdev, 'File and directory should have same device ID'
|
||||||
|
}
|
63
vlib/os/os_stat_windows.c.v
Normal file
63
vlib/os/os_stat_windows.c.v
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
module os
|
||||||
|
|
||||||
|
// stat returns a platform-agnostic Stat struct comparable to what is
|
||||||
|
// available in other programming languages and fails with the POSIX
|
||||||
|
// error if the stat call fails. If a link is stat'd, the stat info
|
||||||
|
// for the link is provided.
|
||||||
|
pub fn stat(path string) !Stat {
|
||||||
|
mut s := C.__stat64{}
|
||||||
|
unsafe {
|
||||||
|
res := C._wstat64(path.to_wide(), &s)
|
||||||
|
if res != 0 {
|
||||||
|
return error_posix()
|
||||||
|
}
|
||||||
|
return Stat{
|
||||||
|
dev: s.st_dev
|
||||||
|
inode: s.st_ino
|
||||||
|
nlink: s.st_nlink
|
||||||
|
mode: s.st_mode
|
||||||
|
uid: s.st_uid
|
||||||
|
gid: s.st_gid
|
||||||
|
rdev: s.st_rdev
|
||||||
|
size: s.st_size
|
||||||
|
atime: s.st_atime
|
||||||
|
mtime: s.st_mtime
|
||||||
|
ctime: s.st_ctime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_filetype returns the FileType from the Stat struct
|
||||||
|
pub fn (st Stat) get_filetype() FileType {
|
||||||
|
match st.mode & u32(C.S_IFMT) {
|
||||||
|
u32(C.S_IFDIR) {
|
||||||
|
return .directory
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return .regular
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_mode returns the file type and permissions (readable, writable, executable)
|
||||||
|
// in owner/group/others format, however, they will all be the same for Windows
|
||||||
|
pub fn (st Stat) get_mode() FileMode {
|
||||||
|
return FileMode{
|
||||||
|
typ: st.get_filetype()
|
||||||
|
owner: FilePermission{
|
||||||
|
read: (st.mode & u32(C.S_IREAD)) != 0
|
||||||
|
write: (st.mode & u32(C.S_IWRITE)) != 0
|
||||||
|
execute: (st.mode & u32(C.S_IEXEC)) != 0
|
||||||
|
}
|
||||||
|
group: FilePermission{
|
||||||
|
read: (st.mode & u32(C.S_IREAD)) != 0
|
||||||
|
write: (st.mode & u32(C.S_IWRITE)) != 0
|
||||||
|
execute: (st.mode & u32(C.S_IEXEC)) != 0
|
||||||
|
}
|
||||||
|
others: FilePermission{
|
||||||
|
read: (st.mode & u32(C.S_IREAD)) != 0
|
||||||
|
write: (st.mode & u32(C.S_IWRITE)) != 0
|
||||||
|
execute: (st.mode & u32(C.S_IEXEC)) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,19 @@
|
|||||||
module os
|
module os
|
||||||
|
|
||||||
|
// Minimal stat struct as specified in
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html
|
||||||
pub struct C.stat {
|
pub struct C.stat {
|
||||||
st_size u64
|
st_dev u64
|
||||||
|
st_ino u64
|
||||||
st_mode u32
|
st_mode u32
|
||||||
|
st_nlink u64
|
||||||
|
st_uid u32
|
||||||
|
st_gid u32
|
||||||
|
st_rdev u64
|
||||||
|
st_size u64
|
||||||
|
st_atime int
|
||||||
st_mtime int
|
st_mtime int
|
||||||
|
st_ctime int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct C.__stat64 {
|
pub struct C.__stat64 {
|
||||||
|
15
vlib/os/os_structs_stat_windows.v
Normal file
15
vlib/os/os_structs_stat_windows.v
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
module os
|
||||||
|
|
||||||
|
pub struct C.__stat64 {
|
||||||
|
st_dev u32 // 4
|
||||||
|
st_ino u16 // 2
|
||||||
|
st_mode u16 // 2
|
||||||
|
st_nlink u16 // 2
|
||||||
|
st_uid u16 // 2
|
||||||
|
st_gid u16 // 2
|
||||||
|
st_rdev u32 // 4
|
||||||
|
st_size u64 // 8
|
||||||
|
st_atime i64 // 8
|
||||||
|
st_mtime i64 // 8
|
||||||
|
st_ctime i64 // 8
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user