This repository has been archived by the owner on Mar 29, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add files/ - was previously in go-ipfs-cmds
- Loading branch information
0 parents
commit 8cd78b7
Showing
9 changed files
with
771 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
Oops, something went wrong.