Commit c30cd9ea authored by Jeromy's avatar Jeromy

implement symlinks in unixfs, first draft

License: MIT
Signed-off-by: default avatarJeromy <jeromyj@gmail.com>
parent 59033650
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)
}
package files
import (
"io/ioutil"
"mime"
"mime/multipart"
"net/http"
......@@ -30,6 +31,17 @@ func NewFileFromPart(part *multipart.Part) (File, error) {
}
contentType := part.Header.Get(contentTypeHeader)
if contentType == "symlink" {
out, err := ioutil.ReadAll(part)
if err != nil {
return nil, err
}
return &Symlink{
Target: string(out),
name: f.FileName(),
}, nil
}
var params map[string]string
var err error
......
......@@ -84,10 +84,25 @@ func (f *serialFile) NextFile() (File, error) {
// open the next file
fileName := fp.Join(f.name, stat.Name())
filePath := fp.Join(f.path, stat.Name())
st, err := os.Lstat(filePath)
if err != nil {
return nil, err
}
if st.Mode()&os.ModeSymlink != 0 {
f.current = nil
target, err := os.Readlink(filePath)
if err != nil {
return nil, err
}
return NewLinkFile(fileName, filePath, target, st), nil
}
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
f.current = file
// recursively call the constructor on the next file
......
......@@ -64,13 +64,23 @@ func (mfr *MultiFileReader) Read(buf []byte) (written int, err error) {
// handle starting a new file part
if !mfr.closed {
if file.IsDirectory() {
var contentType string
if s, ok := file.(*files.Symlink); ok {
mfr.currentFile = s
// TODO(why): this is a hack. pick a real contentType
contentType = "symlink"
} else if file.IsDirectory() {
// if file is a directory, create a multifilereader from it
// (using 'multipart/mixed')
mfr.currentFile = NewMultiFileReader(file, false)
nmfr := NewMultiFileReader(file, false)
mfr.currentFile = nmfr
contentType = fmt.Sprintf("multipart/mixed; boundary=%s", nmfr.Boundary())
} else {
// otherwise, use the file as a reader to read its contents
mfr.currentFile = file
contentType = "application/octet-stream"
}
// write the boundary and headers
......@@ -83,12 +93,7 @@ func (mfr *MultiFileReader) Read(buf []byte) (written int, err error) {
header.Set("Content-Disposition", fmt.Sprintf("file; filename=\"%s\"", filename))
}
if file.IsDirectory() {
boundary := mfr.currentFile.(*MultiFileReader).Boundary()
header.Set("Content-Type", fmt.Sprintf("multipart/mixed; boundary=%s", boundary))
} else {
header.Set("Content-Type", "application/octet-stream")
}
header.Set("Content-Type", contentType)
_, err := mfr.mpWriter.CreatePart(header)
if err != nil {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment