Skip to content
This repository has been archived by the owner on Mar 29, 2023. It is now read-only.

Commit

Permalink
add files/ - was previously in go-ipfs-cmds
Browse files Browse the repository at this point in the history
  • Loading branch information
keks committed Apr 16, 2017
0 parents commit 8cd78b7
Show file tree
Hide file tree
Showing 9 changed files with 771 additions and 0 deletions.
62 changes: 62 additions & 0 deletions file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package files

import (
"errors"
"io"
"os"
)

var (
ErrNotDirectory = errors.New("Couldn't call NextFile(), this isn't a directory")
ErrNotReader = errors.New("This file is a directory, can't use Reader functions")
)

// File is an interface that provides functionality for handling
// files/directories as values that can be supplied to commands. For
// directories, child files are accessed serially by calling `NextFile()`.
type File interface {
// Files implement ReadCloser, but can only be read from or closed if
// they are not directories
io.ReadCloser

// FileName returns a filename associated with this file
FileName() string

// FullPath returns the full path used when adding with this file
FullPath() string

// IsDirectory returns true if the File is a directory (and therefore
// supports calling `NextFile`) and false if the File is a normal file
// (and therefor supports calling `Read` and `Close`)
IsDirectory() bool

// NextFile returns the next child file available (if the File is a
// directory). It will return (nil, io.EOF) if no more files are
// available. If the file is a regular file (not a directory), NextFile
// will return a non-nil error.
NextFile() (File, error)
}

type StatFile interface {
File

Stat() os.FileInfo
}

type PeekFile interface {
SizeFile

Peek(n int) File
Length() int
}

type SizeFile interface {
File

Size() (int64, error)
}

type FileInfo interface {
AbsPath() string
Stat() os.FileInfo
}
203 changes: 203 additions & 0 deletions file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package files

import (
"io"
"io/ioutil"
"mime/multipart"
"strings"
"testing"
)

func TestSliceFiles(t *testing.T) {
name := "testname"
files := []File{
NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil),
NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
NewReaderFile("boop.txt", "boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil),
}
buf := make([]byte, 20)

sf := NewSliceFile(name, name, files)

if !sf.IsDirectory() {
t.Fatal("SliceFile should always be a directory")
}

if n, err := sf.Read(buf); n > 0 || err != io.EOF {
t.Fatal("Shouldn't be able to read data from a SliceFile")
}

if err := sf.Close(); err != ErrNotReader {
t.Fatal("Shouldn't be able to call `Close` on a SliceFile")
}

file, err := sf.NextFile()
if file == nil || err != nil {
t.Fatal("Expected a file and nil error")
}
read, err := file.Read(buf)
if read != 11 || err != nil {
t.Fatal("NextFile got a file in the wrong order")
}

file, err = sf.NextFile()
if file == nil || err != nil {
t.Fatal("Expected a file and nil error")
}
file, err = sf.NextFile()
if file == nil || err != nil {
t.Fatal("Expected a file and nil error")
}

file, err = sf.NextFile()
if file != nil || err != io.EOF {
t.Fatal("Expected a nil file and io.EOF")
}
}

func TestReaderFiles(t *testing.T) {
message := "beep boop"
rf := NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(message)), nil)
buf := make([]byte, len(message))

if rf.IsDirectory() {
t.Fatal("ReaderFile should never be a directory")
}
file, err := rf.NextFile()
if file != nil || err != ErrNotDirectory {
t.Fatal("Expected a nil file and ErrNotDirectory")
}

if n, err := rf.Read(buf); n == 0 || err != nil {
t.Fatal("Expected to be able to read")
}
if err := rf.Close(); err != nil {
t.Fatal("Should be able to close")
}
if n, err := rf.Read(buf); n != 0 || err != io.EOF {
t.Fatal("Expected EOF when reading after close")
}
}

func TestMultipartFiles(t *testing.T) {
data := `
--Boundary!
Content-Type: text/plain
Content-Disposition: file; filename="name"
Some-Header: beep
beep
--Boundary!
Content-Type: application/x-directory
Content-Disposition: file; filename="dir"
--Boundary!
Content-Type: text/plain
Content-Disposition: file; filename="dir/nested"
some content
--Boundary!
Content-Type: application/symlink
Content-Disposition: file; filename="dir/simlynk"
anotherfile
--Boundary!--
`

reader := strings.NewReader(data)
mpReader := multipart.NewReader(reader, "Boundary!")
buf := make([]byte, 20)

// test properties of a file created from the first part
part, err := mpReader.NextPart()
if part == nil || err != nil {
t.Fatal("Expected non-nil part, nil error")
}
mpf, err := NewFileFromPart(part)
if mpf == nil || err != nil {
t.Fatal("Expected non-nil MultipartFile, nil error")
}
if mpf.IsDirectory() {
t.Fatal("Expected file to not be a directory")
}
if mpf.FileName() != "name" {
t.Fatal("Expected filename to be \"name\"")
}
if file, err := mpf.NextFile(); file != nil || err != ErrNotDirectory {
t.Fatal("Expected a nil file and ErrNotDirectory")
}
if n, err := mpf.Read(buf); n != 4 || err != nil {
t.Fatal("Expected to be able to read 4 bytes")
}
if err := mpf.Close(); err != nil {
t.Fatal("Expected to be able to close file")
}

// test properties of file created from second part (directory)
part, err = mpReader.NextPart()
if part == nil || err != nil {
t.Fatal("Expected non-nil part, nil error")
}
mpf, err = NewFileFromPart(part)
if mpf == nil || err != nil {
t.Fatal("Expected non-nil MultipartFile, nil error")
}
if !mpf.IsDirectory() {
t.Fatal("Expected file to be a directory")
}
if mpf.FileName() != "dir" {
t.Fatal("Expected filename to be \"dir\"")
}
if n, err := mpf.Read(buf); n > 0 || err != ErrNotReader {
t.Fatal("Shouldn't be able to call `Read` on a directory")
}
if err := mpf.Close(); err != ErrNotReader {
t.Fatal("Shouldn't be able to call `Close` on a directory")
}

// test properties of file created from third part (nested file)
part, err = mpReader.NextPart()
if part == nil || err != nil {
t.Fatal("Expected non-nil part, nil error")
}
mpf, err = NewFileFromPart(part)
if mpf == nil || err != nil {
t.Fatal("Expected non-nil MultipartFile, nil error")
}
if mpf.IsDirectory() {
t.Fatal("Expected file, got directory")
}
if mpf.FileName() != "dir/nested" {
t.Fatalf("Expected filename to be \"nested\", got %s", mpf.FileName())
}
if n, err := mpf.Read(buf); n != 12 || err != nil {
t.Fatalf("expected to be able to read 12 bytes from file: %s (got %d)", err, n)
}
if err := mpf.Close(); err != nil {
t.Fatalf("should be able to close file: %s", err)
}

// test properties of symlink created from fourth part (symlink)
part, err = mpReader.NextPart()
if part == nil || err != nil {
t.Fatal("Expected non-nil part, nil error")
}
mpf, err = NewFileFromPart(part)
if mpf == nil || err != nil {
t.Fatal("Expected non-nil MultipartFile, nil error")
}
if mpf.IsDirectory() {
t.Fatal("Expected file to be a symlink")
}
if mpf.FileName() != "dir/simlynk" {
t.Fatal("Expected filename to be \"dir/simlynk\"")
}
slink, ok := mpf.(*Symlink)
if !ok {
t.Fatalf("expected file to be a symlink")
}
if slink.Target != "anotherfile" {
t.Fatal("expected link to point to anotherfile")
}
}
19 changes: 19 additions & 0 deletions is_hidden.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// +build !windows

package files

import (
"path/filepath"
"strings"
)

func IsHidden(f File) bool {

fName := filepath.Base(f.FileName())

if strings.HasPrefix(fName, ".") && len(fName) > 1 {
return true
}

return false
}
29 changes: 29 additions & 0 deletions is_hidden_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// +build windows

package files

import (
"path/filepath"
"strings"
"syscall"
)

func IsHidden(f File) bool {

fName := filepath.Base(f.FileName())

if strings.HasPrefix(fName, ".") && len(fName) > 1 {
return true
}

p, e := syscall.UTF16PtrFromString(f.FileName())
if e != nil {
return false
}

attrs, e := syscall.GetFileAttributes(p)
if e != nil {
return false
}
return attrs&syscall.FILE_ATTRIBUTE_HIDDEN != 0
}
50 changes: 50 additions & 0 deletions linkfile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package files

import (
"io"
"os"
"strings"
)

type Symlink struct {
name string
path string
Target string
stat os.FileInfo

reader io.Reader
}

func NewLinkFile(name, path, target string, stat os.FileInfo) File {
return &Symlink{
name: name,
path: path,
Target: target,
stat: stat,
reader: strings.NewReader(target),
}
}

func (lf *Symlink) IsDirectory() bool {
return false
}

func (lf *Symlink) NextFile() (File, error) {
return nil, io.EOF
}

func (f *Symlink) FileName() string {
return f.name
}

func (f *Symlink) Close() error {
return nil
}

func (f *Symlink) FullPath() string {
return f.path
}

func (f *Symlink) Read(b []byte) (int, error) {
return f.reader.Read(b)
}
Loading

0 comments on commit 8cd78b7

Please sign in to comment.