Commit dcef9812 authored by Robert Griesemer's avatar Robert Griesemer

godoc/httpzip.go: use correct path in Readdir

Fixes a problem where Readdir would always return
empty directories (Readdir is only called by godoc
if the usual directory handler is commented out
in godoc.go, and if a zip file system is provided;
thus, this bug never manifested itself in godoc).

Also:
- better choice of variable/field names
- simplified error handling a bit
- better comments

R=bradfitz
CC=golang-dev
https://golang.org/cl/4813047
parent 8fdc2851
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
// - The zip file system treats the file paths found in the zip internally // - The zip file system treats the file paths found in the zip internally
// like absolute paths w/o a leading '/'; i.e., the paths are considered // like absolute paths w/o a leading '/'; i.e., the paths are considered
// relative to the root of the file system. // relative to the root of the file system.
// - All path arguments to file system methods must be absolute paths. // - All path arguments to file system methods are considered relative to
// the root specified with NewHttpZipFS (even if the paths start with a '/').
// TODO(gri) Should define a commonly used FileSystem API that is the same // TODO(gri) Should define a commonly used FileSystem API that is the same
// for http and godoc. Then we only need one zip-file based file // for http and godoc. Then we only need one zip-file based file
...@@ -43,6 +44,7 @@ const ( ...@@ -43,6 +44,7 @@ const (
// httpZipFile is the zip-file based implementation of http.File // httpZipFile is the zip-file based implementation of http.File
type httpZipFile struct { type httpZipFile struct {
path string // absolute path within zip FS without leading '/'
info os.FileInfo info os.FileInfo
io.ReadCloser // nil for directory io.ReadCloser // nil for directory
list zipList list zipList
...@@ -61,12 +63,8 @@ func (f *httpZipFile) Stat() (*os.FileInfo, os.Error) { ...@@ -61,12 +63,8 @@ func (f *httpZipFile) Stat() (*os.FileInfo, os.Error) {
} }
func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, os.Error) { func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, os.Error) {
if f.info.IsRegular() {
return nil, fmt.Errorf("Readdir called for regular file: %s", f.info.Name)
}
var list []os.FileInfo var list []os.FileInfo
dirname := zipPath(f.info.Name) + "/" dirname := f.path + "/"
prevname := "" prevname := ""
for i, e := range f.list { for i, e := range f.list {
if count == 0 { if count == 0 {
...@@ -114,13 +112,6 @@ func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, os.Error) { ...@@ -114,13 +112,6 @@ func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, os.Error) {
return list, nil return list, nil
} }
func (f *httpZipFile) Read(buf []byte) (int, os.Error) {
if f.info.IsRegular() {
return f.ReadCloser.Read(buf)
}
return 0, fmt.Errorf("Read called for directory: %s", f.info.Name)
}
func (f *httpZipFile) Seek(offset int64, whence int) (int64, os.Error) { func (f *httpZipFile) Seek(offset int64, whence int) (int64, os.Error) {
return 0, fmt.Errorf("Seek not implemented for zip file entry: %s", f.info.Name) return 0, fmt.Errorf("Seek not implemented for zip file entry: %s", f.info.Name)
} }
...@@ -132,11 +123,13 @@ type httpZipFS struct { ...@@ -132,11 +123,13 @@ type httpZipFS struct {
root string root string
} }
func (fs *httpZipFS) Open(abspath string) (http.File, os.Error) { func (fs *httpZipFS) Open(name string) (http.File, os.Error) {
name := path.Join(fs.root, abspath) // name is clean // fs.root does not start with '/'.
index, exact := fs.list.lookup(name) path := path.Join(fs.root, name) // path is clean
if index < 0 { index, exact := fs.list.lookup(path)
return nil, fmt.Errorf("file not found: %s", abspath) if index < 0 || !strings.HasPrefix(path, fs.root) {
// file not found or not under root
return nil, fmt.Errorf("file not found: %s", name)
} }
if exact { if exact {
...@@ -147,8 +140,9 @@ func (fs *httpZipFS) Open(abspath string) (http.File, os.Error) { ...@@ -147,8 +140,9 @@ func (fs *httpZipFS) Open(abspath string) (http.File, os.Error) {
return nil, err return nil, err
} }
return &httpZipFile{ return &httpZipFile{
path,
os.FileInfo{ os.FileInfo{
Name: abspath, Name: name,
Mode: S_IFREG, Mode: S_IFREG,
Size: int64(f.UncompressedSize), Size: int64(f.UncompressedSize),
Mtime_ns: f.Mtime_ns(), Mtime_ns: f.Mtime_ns(),
...@@ -160,8 +154,9 @@ func (fs *httpZipFS) Open(abspath string) (http.File, os.Error) { ...@@ -160,8 +154,9 @@ func (fs *httpZipFS) Open(abspath string) (http.File, os.Error) {
// not an exact match - must be a directory // not an exact match - must be a directory
return &httpZipFile{ return &httpZipFile{
path,
os.FileInfo{ os.FileInfo{
Name: abspath, Name: name,
Mode: S_IFDIR, Mode: S_IFDIR,
// no size or mtime_ns for directories // no size or mtime_ns for directories
}, },
...@@ -175,6 +170,9 @@ func (fs *httpZipFS) Close() os.Error { ...@@ -175,6 +170,9 @@ func (fs *httpZipFS) Close() os.Error {
return fs.ReadCloser.Close() return fs.ReadCloser.Close()
} }
// NewHttpZipFS creates a new http.FileSystem based on the contents of
// the zip file rc restricted to the directory tree specified by root;
// root must be an absolute path.
func NewHttpZipFS(rc *zip.ReadCloser, root string) http.FileSystem { func NewHttpZipFS(rc *zip.ReadCloser, root string) http.FileSystem {
list := make(zipList, len(rc.File)) list := make(zipList, len(rc.File))
copy(list, rc.File) // sort a copy of rc.File copy(list, rc.File) // sort a copy of rc.File
......
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