blob: 35d050946e66e8a79b5da4cdb944ebf7fb3fa609 [file] [log] [blame]
Andrew Gerrand5ff06872013-07-17 15:02:27 +10001// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package vfs
6
7import (
8 "fmt"
Agniva De Sarker16d1af82018-01-28 19:53:55 +05309 "go/build"
Peter Weinberger365db562023-09-13 12:37:49 -040010 "io/ioutil"
Andrew Gerrand5ff06872013-07-17 15:02:27 +100011 "os"
12 pathpkg "path"
13 "path/filepath"
Agniva De Sarker16d1af82018-01-28 19:53:55 +053014 "runtime"
Andrew Gerrand5ff06872013-07-17 15:02:27 +100015)
16
Agniva De Sarker6c1c5e92018-08-24 22:48:03 +053017// We expose a new variable because otherwise we need to copy the findGOROOT logic again
18// from cmd/godoc which is already copied twice from the standard library.
19
Agniva De Sarkerb776bcb2018-08-25 10:22:28 +053020// GOROOT is the GOROOT path under which the godoc binary is running.
Agniva De Sarkerba93f942018-08-23 10:54:26 +053021// It is needed to check whether a filesystem root is under GOROOT or not.
Agniva De Sarkerb776bcb2018-08-25 10:22:28 +053022// This is set from cmd/godoc/main.go.
Agniva De Sarkerba93f942018-08-23 10:54:26 +053023var GOROOT = runtime.GOROOT()
24
Andrew Gerrand5ff06872013-07-17 15:02:27 +100025// OS returns an implementation of FileSystem reading from the
26// tree rooted at root. Recording a root is convenient everywhere
27// but necessary on Windows, because the slash-separated path
28// passed to Open has no way to specify a drive letter. Using a root
29// lets code refer to OS(`c:\`), OS(`d:\`) and so on.
30func OS(root string) FileSystem {
Agniva De Sarker16d1af82018-01-28 19:53:55 +053031 var t RootType
32 switch {
Agniva De Sarkerba93f942018-08-23 10:54:26 +053033 case root == GOROOT:
Agniva De Sarker16d1af82018-01-28 19:53:55 +053034 t = RootTypeGoRoot
35 case isGoPath(root):
36 t = RootTypeGoPath
Agniva De Sarker16d1af82018-01-28 19:53:55 +053037 }
38 return osFS{rootPath: root, rootType: t}
Andrew Gerrand5ff06872013-07-17 15:02:27 +100039}
40
Agniva De Sarker16d1af82018-01-28 19:53:55 +053041type osFS struct {
42 rootPath string
43 rootType RootType
44}
Andrew Gerrand5ff06872013-07-17 15:02:27 +100045
Agniva De Sarker16d1af82018-01-28 19:53:55 +053046func isGoPath(path string) bool {
47 for _, bp := range filepath.SplitList(build.Default.GOPATH) {
48 for _, gp := range filepath.SplitList(path) {
49 if bp == gp {
50 return true
51 }
52 }
53 }
54 return false
55}
56
57func (root osFS) String() string { return "os(" + root.rootPath + ")" }
58
59// RootType returns the root type for the filesystem.
60//
61// Note that we ignore the path argument because roottype is a property of
62// this filesystem. But for other filesystems, the roottype might need to be
63// dynamically deduced at call time.
64func (root osFS) RootType(path string) RootType {
65 return root.rootType
66}
Andrew Gerrand5ff06872013-07-17 15:02:27 +100067
68func (root osFS) resolve(path string) string {
69 // Clean the path so that it cannot possibly begin with ../.
70 // If it did, the result of filepath.Join would be outside the
71 // tree rooted at root. We probably won't ever see a path
72 // with .. in it, but be safe anyway.
73 path = pathpkg.Clean("/" + path)
74
Agniva De Sarker16d1af82018-01-28 19:53:55 +053075 return filepath.Join(root.rootPath, path)
Andrew Gerrand5ff06872013-07-17 15:02:27 +100076}
77
78func (root osFS) Open(path string) (ReadSeekCloser, error) {
79 f, err := os.Open(root.resolve(path))
80 if err != nil {
81 return nil, err
82 }
83 fi, err := f.Stat()
84 if err != nil {
Gustav Paul68353d22015-05-31 20:34:06 +020085 f.Close()
Andrew Gerrand5ff06872013-07-17 15:02:27 +100086 return nil, err
87 }
88 if fi.IsDir() {
Gustav Paul68353d22015-05-31 20:34:06 +020089 f.Close()
Andrew Gerrand5ff06872013-07-17 15:02:27 +100090 return nil, fmt.Errorf("Open: %s is a directory", path)
91 }
92 return f, nil
93}
94
95func (root osFS) Lstat(path string) (os.FileInfo, error) {
96 return os.Lstat(root.resolve(path))
97}
98
99func (root osFS) Stat(path string) (os.FileInfo, error) {
Ian Lance Taylorf03b3352017-08-07 16:04:23 -0700100 return os.Stat(root.resolve(path))
Andrew Gerrand5ff06872013-07-17 15:02:27 +1000101}
102
103func (root osFS) ReadDir(path string) ([]os.FileInfo, error) {
Peter Weinberger365db562023-09-13 12:37:49 -0400104 return ioutil.ReadDir(root.resolve(path)) // is sorted
Andrew Gerrand5ff06872013-07-17 15:02:27 +1000105}