Skip to content

Commit

Permalink
Basic mkfifo implementation (#169)
Browse files Browse the repository at this point in the history
* stat: fmt code

* Basic mkfifo implementation
  • Loading branch information
mengzhuo authored Sep 26, 2024
1 parent d3e0e9b commit b28511e
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ compare against the true GNU coreutils version on the Linux-based tests first.
| ✓ | ls | List directory contents |
| ✓ | md5sum | Print or check MD5 digests |
| ✓ | mkdir | Make directories |
| | mkfifo | Make FIFOs (named pipes) |
| ✓ | mkfifo | Make FIFOs (named pipes) |
| | mknod | Make block or character special files |
| ✓ | mktemp | Create temporary file or directory |
| ✓ | mv | Move (rename) files |
Expand Down
Empty file removed src/mkfifo/delete.me
Empty file.
53 changes: 53 additions & 0 deletions src/mkfifo/mkfifo.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import os
import common

const name = 'mkfifo'
const default_mode = u32(0o600)

struct Options {
mode u32
}

fn mkfifo_cmd(list []string, opts &Options) {
for path in list {
ret := mkfifo(path, opts.mode)
if ret != 0 {
common.exit_with_error_message(name, os.posix_get_error_msg(ret))
}
}
}

fn run_mkfifo(args []string) {
mut fp := common.flag_parser(args)
fp.application(name)
fp.usage_example('[OPTION]... NAME...')
fp.description('Create named pipes (FIFOs) with the given NAMEs.')
fp.description('Mandatory arguments to long options are mandatory for short options too.')

mut opts := Options{
mode: u32(fp.int('mode', `m`, int(default_mode), 'set file permission bits to MODE, not a=rw - umask'))
}

help := fp.bool('help', 0, false, 'display this help and exit')
version := fp.bool('version', 0, false, 'output version information and exit')
if help {
println(fp.usage())
exit(0)
}
if version {
println('${name} ${common.coreutils_version()}')
exit(0)
}

file_args := fp.finalize() or { common.exit_with_error_message(name, err.msg()) }
if file_args.len == 0 {
common.exit_with_error_message(name, 'missing operand')
}

mkfifo_cmd(file_args, &opts)
}

fn main() {
run_mkfifo(os.args)
exit(0)
}
4 changes: 4 additions & 0 deletions src/mkfifo/mkfifo_default.c.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// mkfifo on unsupported platforms
fn mkfifo(pathname string, mode int) int {
return -1
}
5 changes: 5 additions & 0 deletions src/mkfifo/mkfifo_nix.c.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn C.mkfifo(&char, int) int

fn mkfifo(pathname string, mode u32) int {
return C.mkfifo(pathname.str, mode)
}
55 changes: 55 additions & 0 deletions src/mkfifo/mkfifo_nix_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import os
import common.testing

const rig = testing.prepare_rig(util: util)
const tfolder = os.join_path(os.temp_dir(), 'coreutils', 'mkfifo_test')

const util = 'mkfifo'
const platform_util = util

const executable_under_test = testing.prepare_executable(util)
const cmd = testing.new_paired_command(platform_util, executable_under_test)

fn test_help_and_version() {
rig.assert_help_and_version_options_work()
}

fn testsuite_begin() {
rig.assert_platform_util()
os.chdir(testing.temp_folder)!
eprintln('testsuite_begin, tfolder = ${tfolder}')
os.rmdir_all(tfolder) or {}
assert !os.is_dir(tfolder)
os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder) or {}
assert os.is_dir(tfolder)
}

fn testsuite_end() {
os.chdir(os.wd_at_startup) or {}
os.rmdir_all(tfolder) or {}
assert !os.is_dir(tfolder)
eprintln('testsuite_end , tfolder = ${tfolder} removed.')
}

fn test_default_create_single_pipe() {
target := 'test_piped'
res := os.execute('${executable_under_test} ${target}')
assert res.exit_code == 0
assert res.output.trim_space() == ''
assert os.is_file(target)
st := os.stat(target)!
assert st.get_filetype() == os.FileType.fifo
}

fn test_default_create_multiple_pipes() {
target := 'tp1 tp2 tp3'
res := os.execute('${executable_under_test} ${target}')
assert res.exit_code == 0
assert res.output.trim_space() == ''
for p in target.split(' ') {
assert os.is_file(p)
st := os.stat(p)!
assert st.get_filetype() == os.FileType.fifo
}
}
6 changes: 3 additions & 3 deletions src/stat/stat.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,14 @@ pub fn get_filetype(mode u16) FileType {

pub fn get_mode2(mode u16) FileMode {
return FileMode{
typ: get_filetype(mode)
owner: FilePermission{
typ: get_filetype(mode)
owner: FilePermission{
read: (mode & u32(C.S_IRUSR)) != 0
write: (mode & u32(C.S_IWUSR)) != 0
execute: (mode & u32(C.S_IXUSR)) != 0
special: (mode & u32(C.S_ISUID)) != 0
}
group: FilePermission{
group: FilePermission{
read: (mode & u32(C.S_IRGRP)) != 0
write: (mode & u32(C.S_IWGRP)) != 0
execute: (mode & u32(C.S_IXGRP)) != 0
Expand Down

0 comments on commit b28511e

Please sign in to comment.