@cryptotaxi247 / kubo / commits / ccc9cd6a6

Refactor serialfile

License: MIT Signed-off-by: rht <rhtbot@gmail.com>

rht committed Sep 4, 2015 at 14:03 UTC ccc9cd6a6cc0747f10689e22bbd547cfb8ab6600
1 file changed +25 -70
commands/files/serialfile.go
+25 -70
@@ -3,18 +3,12 @@ package files
3 import (
4 "fmt"
5 "io"
6 + "io/ioutil"
7 "os"
8 fp "path/filepath"
8 - "sort"
9 "syscall"
10 )
11
12 -type sortFIByName []os.FileInfo
13 -
14 -func (es sortFIByName) Len() int { return len(es) }
15 -func (es sortFIByName) Swap(i, j int) { es[i], es[j] = es[j], es[i] }
16 -func (es sortFIByName) Less(i, j int) bool { return es[i].Name() < es[j].Name() }
17 -
12 // serialFile implements File, and reads from a path on the OS filesystem.
13 // No more than one file will be opened at a time (directories will advance
14 // to the next file when NextFile() is called).
@@ -23,55 +17,34 @@ type serialFile struct {
17 path string
18 files []os.FileInfo
19 stat os.FileInfo
26 - current *os.File
20 + current *File
21 }
22
23 func NewSerialFile(name, path string, stat os.FileInfo) (File, error) {
24 switch mode := stat.Mode(); {
31 - case mode.IsDir() || mode.IsRegular():
32 - break
25 + case mode.IsRegular():
26 + file, err := os.Open(path)
27 + if err != nil {
28 + return nil, err
29 + }
30 + return NewReaderFile(name, path, file, stat), nil
31 + case mode.IsDir():
32 + // for directories, stat all of the contents first, so we know what files to
33 + // open when NextFile() is called
34 + contents, err := ioutil.ReadDir(path)
35 + if err != nil {
36 + return nil, err
37 + }
38 + return &serialFile{name, path, contents, stat, nil}, nil
39 case mode&os.ModeSymlink != 0:
40 target, err := os.Readlink(path)
41 if err != nil {
42 return nil, err
43 }
38 -
39 - return NewLinkFile("", path, target, stat), nil
44 + return NewLinkFile(name, path, target, stat), nil
45 default:
41 - return nil, fmt.Errorf("Unrecognized file type for %s: %s", stat.Name(), mode.String())
42 - }
43 -
44 - file, err := os.Open(path)
45 - if err != nil {
46 - return nil, err
47 - }
48 -
49 - return newSerialFile(name, path, file, stat)
50 -}
51 -
52 -func newSerialFile(name, path string, file *os.File, stat os.FileInfo) (File, error) {
53 - // for non-directories, return a ReaderFile
54 - if !stat.IsDir() {
55 - return &ReaderFile{name, path, file, stat}, nil
56 - }
57 -
58 - // for directories, stat all of the contents first, so we know what files to
59 - // open when NextFile() is called
60 - contents, err := file.Readdir(0)
61 - if err != nil {
62 - return nil, err
46 + return nil, fmt.Errorf("Unrecognized file type for %s: %s", name, mode.String())
47 }
64 -
65 - // we no longer need our root directory file (we already statted the contents),
66 - // so close it
67 - if err := file.Close(); err != nil {
68 - return nil, err
69 - }
70 -
71 - // make sure contents are sorted so -- repeatably -- we get the same inputs.
72 - sort.Sort(sortFIByName(contents))
73 -
74 - return &serialFile{name, path, contents, stat, nil}, nil
48 }
49
50 func (f *serialFile) IsDirectory() bool {
@@ -98,36 +71,18 @@ func (f *serialFile) NextFile() (File, error) {
71 // open the next file
72 fileName := fp.Join(f.name, stat.Name())
73 filePath := fp.Join(f.path, stat.Name())
101 - st, err := os.Lstat(filePath)
102 - if err != nil {
103 - return nil, err
104 - }
74
106 - switch mode := st.Mode(); {
107 - case mode.IsDir() || mode.IsRegular():
108 - break
109 - case mode&os.ModeSymlink != 0:
110 - f.current = nil
111 - target, err := os.Readlink(filePath)
112 - if err != nil {
113 - return nil, err
114 - }
115 - return NewLinkFile(fileName, filePath, target, st), nil
116 - default:
117 - return nil, fmt.Errorf("Unrecognized file type for %s: %s", st.Name(), mode.String())
118 - }
119 -
120 - file, err := os.Open(filePath)
75 + // recursively call the constructor on the next file
76 + // if it's a regular file, we will open it as a ReaderFile
77 + // if it's a directory, files in it will be opened serially
78 + sf, err := NewSerialFile(fileName, filePath, stat)
79 if err != nil {
80 return nil, err
81 }
82
125 - f.current = file
83 + f.current = &sf
84
127 - // recursively call the constructor on the next file
128 - // if it's a regular file, we will open it as a ReaderFile
129 - // if it's a directory, files in it will be opened serially
130 - return newSerialFile(fileName, filePath, file, stat)
85 + return sf, nil
86 }
87
88 func (f *serialFile) FileName() string {
@@ -145,7 +100,7 @@ func (f *serialFile) Read(p []byte) (int, error) {
100 func (f *serialFile) Close() error {
101 // close the current file if there is one
102 if f.current != nil {
148 - err := f.current.Close()
103 + err := (*f.current).Close()
104 // ignore EINVAL error, the file might have already been closed
105 if err != nil && err != syscall.EINVAL {
106 return err