diff options
Diffstat (limited to 'src/cmd/godoc/httpzip.go')
-rw-r--r-- | src/cmd/godoc/httpzip.go | 190 |
1 files changed, 0 insertions, 190 deletions
diff --git a/src/cmd/godoc/httpzip.go b/src/cmd/godoc/httpzip.go deleted file mode 100644 index 12e99646d..000000000 --- a/src/cmd/godoc/httpzip.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file provides an implementation of the http.FileSystem -// interface based on the contents of a .zip file. -// -// Assumptions: -// -// - The file paths stored in the zip file must use a slash ('/') as path -// separator; and they must be relative (i.e., they must not start with -// a '/' - this is usually the case if the file was created w/o special -// options). -// - 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 -// relative to the root of the file system. -// - 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 -// for http and godoc. Then we only need one zip-file based file -// system implementation. - -package main - -import ( - "archive/zip" - "fmt" - "io" - "net/http" - "os" - "path" - "sort" - "strings" - "time" -) - -type fileInfo struct { - name string - mode os.FileMode - size int64 - mtime time.Time -} - -func (fi *fileInfo) Name() string { return fi.name } -func (fi *fileInfo) Mode() os.FileMode { return fi.mode } -func (fi *fileInfo) Size() int64 { return fi.size } -func (fi *fileInfo) ModTime() time.Time { return fi.mtime } -func (fi *fileInfo) IsDir() bool { return fi.mode.IsDir() } -func (fi *fileInfo) Sys() interface{} { return nil } - -// httpZipFile is the zip-file based implementation of http.File -type httpZipFile struct { - path string // absolute path within zip FS without leading '/' - info os.FileInfo - io.ReadCloser // nil for directory - list zipList -} - -func (f *httpZipFile) Close() error { - if !f.info.IsDir() { - return f.ReadCloser.Close() - } - f.list = nil - return nil -} - -func (f *httpZipFile) Stat() (os.FileInfo, error) { - return f.info, nil -} - -func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, error) { - var list []os.FileInfo - dirname := f.path + "/" - prevname := "" - for i, e := range f.list { - if count == 0 { - f.list = f.list[i:] - break - } - if !strings.HasPrefix(e.Name, dirname) { - f.list = nil - break // not in the same directory anymore - } - name := e.Name[len(dirname):] // local name - var mode os.FileMode - var size int64 - var mtime time.Time - if i := strings.IndexRune(name, '/'); i >= 0 { - // We infer directories from files in subdirectories. - // If we have x/y, return a directory entry for x. - name = name[0:i] // keep local directory name only - mode = os.ModeDir - // no size or mtime for directories - } else { - mode = 0 - size = int64(e.UncompressedSize) - mtime = e.ModTime() - } - // If we have x/y and x/z, don't return two directory entries for x. - // TODO(gri): It should be possible to do this more efficiently - // by determining the (fs.list) range of local directory entries - // (via two binary searches). - if name != prevname { - list = append(list, &fileInfo{ - name, - mode, - size, - mtime, - }) - prevname = name - count-- - } - } - - if count >= 0 && len(list) == 0 { - return nil, io.EOF - } - - return list, nil -} - -func (f *httpZipFile) Seek(offset int64, whence int) (int64, error) { - return 0, fmt.Errorf("Seek not implemented for zip file entry: %s", f.info.Name()) -} - -// httpZipFS is the zip-file based implementation of http.FileSystem -type httpZipFS struct { - *zip.ReadCloser - list zipList - root string -} - -func (fs *httpZipFS) Open(name string) (http.File, error) { - // fs.root does not start with '/'. - path := path.Join(fs.root, name) // path is clean - index, exact := fs.list.lookup(path) - 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 { - // exact match found - must be a file - f := fs.list[index] - rc, err := f.Open() - if err != nil { - return nil, err - } - return &httpZipFile{ - path, - &fileInfo{ - name, - 0, - int64(f.UncompressedSize), - f.ModTime(), - }, - rc, - nil, - }, nil - } - - // not an exact match - must be a directory - return &httpZipFile{ - path, - &fileInfo{ - name, - os.ModeDir, - 0, // no size for directory - time.Time{}, // no mtime for directory - }, - nil, - fs.list[index:], - }, nil -} - -func (fs *httpZipFS) Close() error { - fs.list = nil - 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 { - list := make(zipList, len(rc.File)) - copy(list, rc.File) // sort a copy of rc.File - sort.Sort(list) - return &httpZipFS{rc, list, zipPath(root)} -} |