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

initial support for Mode and ModTime on Node interface #31

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"io"
"os"
"time"
)

var (
Expand All @@ -17,6 +18,14 @@ var (
type Node interface {
io.Closer

// Mode returns the file's mode
Mode() os.FileMode

// ModTime returns the files last modification time.
//
// If the last modification time is unknown/unspecified the mtime is the Unix epoch (default timestamp).
ModTime() (mtime time.Time)

// Size returns size of this file (if this file is a directory, total size of
// all files stored in the tree should be returned). Some implementations may
// choose not to implement this
Expand Down
9 changes: 9 additions & 0 deletions linkfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package files
import (
"os"
"strings"
"time"
)

type Symlink struct {
Expand All @@ -18,6 +19,14 @@ func NewLinkFile(target string, stat os.FileInfo) File {
return lf
}

func (lf *Symlink) Mode() os.FileMode {
panic("Implement me")
kstuart marked this conversation as resolved.
Show resolved Hide resolved
}

func (lf *Symlink) ModTime() time.Time {
panic("Implement me")
}

func (lf *Symlink) Close() error {
return nil
}
Expand Down
10 changes: 10 additions & 0 deletions multipartfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (
"mime"
"mime/multipart"
"net/url"
"os"
"path"
"strings"
"time"
)

const (
Expand All @@ -29,6 +31,14 @@ type multipartDirectory struct {
part *multipart.Part
}

func (f *multipartDirectory) Mode() os.FileMode {
panic("implement me")
}

func (f *multipartDirectory) ModTime() time.Time {
panic("implement me")
}

type multipartWalker struct {
part *multipart.Part
reader *multipart.Reader
Expand Down
9 changes: 9 additions & 0 deletions readerfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"time"
)

// ReaderFile is a implementation of File created from an `io.Reader`.
Expand All @@ -18,6 +19,14 @@ type ReaderFile struct {
fsize int64
}

func (f *ReaderFile) Mode() os.FileMode {
return f.stat.Mode()
}

func (f *ReaderFile) ModTime() time.Time {
return f.stat.ModTime()
}

func NewBytesFile(b []byte) File {
return &ReaderFile{"", NewReaderFile(bytes.NewReader(b)), nil, int64(len(b))}
}
Expand Down
9 changes: 9 additions & 0 deletions serialfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"time"
)

// serialFile implements Node, and reads from a path on the OS filesystem.
Expand Down Expand Up @@ -156,5 +157,13 @@ func (f *serialFile) Size() (int64, error) {
return du, err
}

func (f *serialFile) Mode() os.FileMode {
panic("implement me")
}

func (f *serialFile) ModTime() time.Time {
panic("implement me")
}

var _ Directory = &serialFile{}
var _ DirIterator = &serialIterator{}
14 changes: 13 additions & 1 deletion slicedirectory.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package files

import "sort"
import (
"os"
"sort"
"time"
)

type fileEntry struct {
name string
Expand Down Expand Up @@ -51,6 +55,14 @@ type SliceFile struct {
files []DirEntry
}

func (f *SliceFile) Mode() os.FileMode {
panic("implement me")
}

func (f *SliceFile) ModTime() time.Time {
panic("implement me")
}

func NewMapDirectory(f map[string]Node) Directory {
ents := make([]DirEntry, 0, len(f))
for name, nd := range f {
Expand Down
50 changes: 38 additions & 12 deletions tarwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"archive/tar"
"fmt"
"io"
"os"
"path"
"time"
)
Expand Down Expand Up @@ -39,7 +40,20 @@ func (w *TarWriter) writeFile(f File, fpath string) error {
return err
}

if err := writeFileHeader(w.TarW, fpath, uint64(size)); err != nil {
mode, mtime, err := getFileMeta(f)
if err != nil {
return err
}

err = w.TarW.WriteHeader(&tar.Header{
Name: fpath,
Size: size,
Typeflag: tar.TypeReg,
Mode: int64(mode),
ModTime: mtime,
})

if err != nil {
return err
}

Expand Down Expand Up @@ -79,17 +93,6 @@ func writeDirHeader(w *tar.Writer, fpath string) error {
})
}

func writeFileHeader(w *tar.Writer, fpath string, size uint64) error {
return w.WriteHeader(&tar.Header{
Name: fpath,
Size: int64(size),
Typeflag: tar.TypeReg,
Mode: 0644,
ModTime: time.Now(),
// TODO: set mode, dates, etc. when added to unixFS
})
}

func writeSymlinkHeader(w *tar.Writer, target, fpath string) error {
return w.WriteHeader(&tar.Header{
Name: fpath,
Expand All @@ -98,3 +101,26 @@ func writeSymlinkHeader(w *tar.Writer, target, fpath string) error {
Typeflag: tar.TypeSymlink,
})
}

func getFileMeta(f File) (os.FileMode, time.Time, error) {
var err error = nil
mode := f.Mode()
mtime := f.ModTime()

if mode == 0 {
switch nd := f.(type) {
case File:
mode = 0644
case Directory:
mode = 0777
default:
err = fmt.Errorf("mode for file type %T is not supported", nd)
}
}

if !mtime.IsZero() {
mtime = time.Now()
}

return mode, mtime, err
}
38 changes: 38 additions & 0 deletions webfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,33 @@ import (
"net/http"
"net/url"
"os"
"strconv"
"time"
)

// the HTTP Response header that provides the last modified timestamp
const lastModifiedHeaderName = "Last-Modified"

// the HTTP Response header that provides the unix file mode
const fileModeHeaderName = "X-FileMode"

// WebFile is an implementation of File which reads it
// from a Web URL (http). A GET request will be performed
// against the source when calling Read().
type WebFile struct {
body io.ReadCloser
url *url.URL
contentLength int64
mode os.FileMode
mtime time.Time
}

func (wf *WebFile) Mode() os.FileMode {
return wf.mode
}

func (wf *WebFile) ModTime() time.Time {
return wf.mtime
}

// NewWebFile creates a WebFile with the given URL, which
Expand All @@ -38,10 +56,30 @@ func (wf *WebFile) start() error {
}
wf.body = resp.Body
wf.contentLength = resp.ContentLength
wf.getResponseMetaData(resp)
}
return nil
}

func (wf *WebFile) getResponseMetaData(resp *http.Response) {
ts := resp.Header.Get(lastModifiedHeaderName)
if ts != "" {
if mtime, err := time.Parse(time.RFC1123, ts); err != nil {
fmt.Printf("failed to parse %s header: %s\n", lastModifiedHeaderName, err.Error())
} else {
wf.mtime = mtime
}
}
md := resp.Header.Get(fileModeHeaderName)
if md != "" {
if mode, err := strconv.ParseInt(md, 8, 32); err != nil {
fmt.Printf("failed to parse %s header: %s\n", fileModeHeaderName, err.Error())
} else {
wf.mode = os.FileMode(mode)
}
}
}

// Read reads the File from it's web location. On the first
// call to Read, a GET request will be performed against the
// WebFile's URL, using Go's default HTTP client. Any further
Expand Down