Skip to content

Commit

Permalink
Add fsys directory operations (#109)
Browse files Browse the repository at this point in the history
* Add fsys directory operations

Signed-off-by: Kimmo Lehto <[email protected]>

* Slight tuning to retrigger workflow

Signed-off-by: Kimmo Lehto <[email protected]>

---------

Signed-off-by: Kimmo Lehto <[email protected]>
  • Loading branch information
kke authored Jun 21, 2023
1 parent 933a552 commit dbce37c
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 10 deletions.
15 changes: 14 additions & 1 deletion cmd/rigtest/rigtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,23 @@ func main() {
require.True(t, bytes.Equal(readSha.Sum(nil), shasum.Sum(nil)), "sha256 mismatch after io.copy from remote to local after seek")

require.NoError(t, destf.Close(), "close after seek + read")
require.NoError(t, fsys.Delete(fn), "remove file")
require.NoError(t, fsys.Remove(fn), "remove file")
_, err = destf.Stat()
require.ErrorIs(t, err, fs.ErrNotExist, "file still exists")

// fsys dirops
require.NoError(t, fsys.MkDirAll("tmpdir/nested", 0644), "make nested dir")
_, err = fsys.Stat("tmpdir")
require.NoError(t, err, "tmpdir was not created")
_, err = fsys.Stat("tmpdir/nested")
require.NoError(t, err, "tmpdir/nested was not created")

require.NoError(t, fsys.RemoveAll("tmpdir"), "remove recursive")
_, err = fsys.Stat("tmpdir/nested")
require.ErrorIs(t, err, fs.ErrNotExist, "nested dir still exists")
_, err = fsys.Stat("tmpdir")
require.ErrorIs(t, err, fs.ErrNotExist, "dir still exists")

require.NoError(t, h.Configurer.MkDir(h, "tmp/testdir/subdir"), "make dir")
require.NoError(t, h.Configurer.WriteFile(h, "tmp/testdir/subdir/testfile1", "test", "0644"), "write file")
require.NoError(t, h.Configurer.WriteFile(h, "tmp/testdir/testfile2", "test", "0644"), "write file")
Expand Down
35 changes: 33 additions & 2 deletions pkg/rigfs/posixfsys.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"io/fs"
"math/big"
"os"
"strings"
"time"

Expand Down Expand Up @@ -375,10 +376,40 @@ func (fsys *PosixFsys) ReadDir(name string) ([]fs.DirEntry, error) {
return entries, nil
}

// Delete removes the named file or (empty) directory.
func (fsys *PosixFsys) Delete(name string) error {
// Remove deletes the named file or (empty) directory.
func (fsys *PosixFsys) Remove(name string) error {
if err := fsys.conn.Exec(fmt.Sprintf("rm -f %s", shellescape.Quote(name)), fsys.opts...); err != nil {
return fmt.Errorf("%w: delete %s: %w", ErrCommandFailed, name, err)
}
return nil
}

// RemoveAll removes path and any children it contains.
func (fsys *PosixFsys) RemoveAll(name string) error {
if err := fsys.conn.Exec(fmt.Sprintf("rm -rf %s", shellescape.Quote(name)), fsys.opts...); err != nil {
return fmt.Errorf("%w: remove all %s: %w", ErrCommandFailed, name, err)
}
return nil
}

// MkDirAll creates a new directory structure with the specified name and permission bits.
// If the directory already exists, MkDirAll does nothing and returns nil.
func (fsys *PosixFsys) MkDirAll(name string, perm FileMode) error {
dir := shellescape.Quote(name)
if existing, err := fsys.Stat(name); err == nil {
if existing.IsDir() {
return nil
}
return fmt.Errorf("%w: mkdir %s: %w", ErrCommandFailed, name, fs.ErrExist)
}

if err := fsys.conn.Exec(fmt.Sprintf("mkdir -p %s", dir), fsys.opts...); err != nil {
return fmt.Errorf("%w: mkdir %s: %w", ErrCommandFailed, name, err)
}

if err := fsys.conn.Exec(fmt.Sprintf("chmod %#o %s", os.FileMode(perm).Perm(), dir), fsys.opts...); err != nil {
return fmt.Errorf("%w: chmod (mkdir) %s: %w", ErrCommandFailed, name, err)
}

return nil
}
4 changes: 3 additions & 1 deletion pkg/rigfs/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ type Fsys interface {
OpenFile(string, FileMode, FileMode) (File, error)
Sha256(string) (string, error)
Stat(string) (fs.FileInfo, error)
Delete(string) error
Remove(string) error
RemoveAll(string) error
MkDirAll(string, FileMode) error
}

// FileMode is used to set the type of allowed operations when opening remote files
Expand Down
51 changes: 45 additions & 6 deletions pkg/rigfs/winfsys.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ func (fsys *WinFsys) Open(name string) (fs.File, error) {
return f, nil
}

// OpenFile opens the named remote file with the specified FileMode. perm is ignored on Windows.
func (fsys *WinFsys) OpenFile(name string, mode FileMode, perm FileMode) (File, error) {
// OpenFile opens the named remote file with the specified FileMode. Permission bits are ignored on Windows.
func (fsys *WinFsys) OpenFile(name string, mode FileMode, _ FileMode) (File, error) {
var modeStr string
switch mode {
case ModeRead:
Expand All @@ -378,7 +378,7 @@ func (fsys *WinFsys) OpenFile(name string, mode FileMode, perm FileMode) (File,
return nil, &fs.PathError{Op: "open", Path: name, Err: fmt.Errorf("%w: invalid mode: %d", ErrRcpCommandFailed, mode)}
}

log.Debugf("opening remote file %s (mode %s)", name, modeStr, perm)
log.Debugf("opening remote file %s (mode %s)", name, modeStr)
_, err := fsys.rcp.command(fmt.Sprintf("o %s %s", modeStr, filepath.FromSlash(name)))
if err != nil {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
Expand Down Expand Up @@ -427,10 +427,49 @@ func (fsys *WinFsys) ReadDir(name string) ([]fs.DirEntry, error) {
return entries, nil
}

// Delete removes the named file or (empty) directory.
func (fsys *WinFsys) Delete(name string) error {
// Remove deletes the named file or (empty) directory.
func (fsys *WinFsys) Remove(name string) error {
if existing, err := fsys.Stat(name); err == nil && existing.IsDir() {
return fsys.removeDir(name)
}

if err := fsys.conn.Exec(fmt.Sprintf("del %s", ps.DoubleQuote(filepath.FromSlash(name)))); err != nil {
return fmt.Errorf("%w: delete %s: %w", ErrCommandFailed, name, err)
return fmt.Errorf("%w: remove %s: %w", ErrCommandFailed, name, err)
}
return nil
}

// RemoveAll deletes the named file or directory and all its child items
func (fsys *WinFsys) RemoveAll(name string) error {
if existing, err := fsys.Stat(name); err == nil && existing.IsDir() {
return fsys.removeDirAll(name)
}

if err := fsys.conn.Exec(fmt.Sprintf("del %s", ps.DoubleQuote(filepath.FromSlash(name)))); err != nil {
return fmt.Errorf("%w: remove all %s: %w", ErrCommandFailed, name, err)
}
return nil
}

func (fsys *WinFsys) removeDir(name string) error {
if err := fsys.conn.Exec(fmt.Sprintf("rmdir /q %s", ps.DoubleQuote(filepath.FromSlash(name)))); err != nil {
return fmt.Errorf("%w: rmdir %s: %w", ErrCommandFailed, name, err)
}
return nil
}

func (fsys *WinFsys) removeDirAll(name string) error {
if err := fsys.conn.Exec(fmt.Sprintf("rmdir /s /q %s", ps.DoubleQuote(filepath.FromSlash(name)))); err != nil {
return fmt.Errorf("%w: rmdir %s: %w", ErrCommandFailed, name, err)
}
return nil
}

// MkDirAll creates a directory named path, along with any necessary parents. The permission bits perm are ignored on Windows.
func (fsys *WinFsys) MkDirAll(path string, _ FileMode) error {
if err := fsys.conn.Exec(fmt.Sprintf("mkdir -p %s", ps.DoubleQuote(filepath.FromSlash(path)))); err != nil {
return fmt.Errorf("%w: mkdir %s: %w", ErrCommandFailed, path, err)
}

return nil
}

0 comments on commit dbce37c

Please sign in to comment.