github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/ls/fileinfo_plan9.go (about) 1 // Copyright 2017 the u-root 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 5 // +build plan9 6 7 package ls 8 9 import ( 10 "fmt" 11 "os" 12 "regexp" 13 "strconv" 14 "time" 15 16 humanize "github.com/dustin/go-humanize" 17 ) 18 19 // Matches characters which would interfere with ls's formatting. 20 var unprintableRe = regexp.MustCompile("[[:cntrl:]\n]") 21 22 // FileInfo holds file metadata. 23 // 24 // Since `os.FileInfo` is an interface, it is difficult to tweak some of its 25 // internal values. For example, replacing the starting directory with a dot. 26 // `extractImportantParts` populates our own struct which we can modify at will 27 // before printing. 28 type FileInfo struct { 29 Name string 30 Mode os.FileMode 31 UID string 32 Size int64 33 MTime time.Time 34 } 35 36 // FromOSFileInfo converts os.FileInfo to an ls.FileInfo. 37 func FromOSFileInfo(path string, fi os.FileInfo) FileInfo { 38 return FileInfo{ 39 Name: fi.Name(), 40 Mode: fi.Mode(), 41 // Plan 9 UIDs from the file system are strings. 42 // os.FileInfo only allows ints. 43 // The Plan 9 runtime does not attach syscall.Dir to the Sys 44 // on FileInfo or there would be no problem. 45 // This is going to require some fixes to the Go runtime. 46 // os.FileInfo botched a few things. 47 // That said, it is a rare case that you could unpack a cpio 48 // in Plan 9 and set file ownership; that's not how it works. 49 // so ... bootes it is. 50 UID: "bootes", 51 Size: fi.Size(), 52 MTime: fi.ModTime(), 53 } 54 } 55 56 // PrintableName returns a printable file name. 57 func (fi FileInfo) PrintableName() string { 58 return unprintableRe.ReplaceAllLiteralString(fi.Name, "?") 59 } 60 61 // Stringer provides a consistent way to format FileInfo. 62 type Stringer interface { 63 // FileString formats a FileInfo. 64 FileString(fi FileInfo) string 65 } 66 67 // NameStringer is a Stringer implementation that just prints the name. 68 type NameStringer struct{} 69 70 // FileString implements Stringer.FileString and just returns fi's name. 71 func (ns NameStringer) FileString(fi FileInfo) string { 72 return fi.PrintableName() 73 } 74 75 // QuotedStringer is a Stringer that returns the file name surrounded by qutoes 76 // with escaped control characters. 77 type QuotedStringer struct{} 78 79 // FileString returns the name surrounded by quotes with escaped control characters. 80 func (qs QuotedStringer) FileString(fi FileInfo) string { 81 return fmt.Sprintf("%#v", fi.Name) 82 } 83 84 // LongStringer is a Stringer that returns the file info formatted in `ls -l` 85 // long format. 86 type LongStringer struct { 87 Human bool 88 Name Stringer 89 } 90 91 // FileString implements Stringer.FileString. 92 func (ls LongStringer) FileString(fi FileInfo) string { 93 94 var size string 95 if ls.Human { 96 size = humanize.Bytes(uint64(fi.Size)) 97 } else { 98 size = strconv.FormatInt(fi.Size, 10) 99 } 100 // Ex: -rw-rw---- myuser 1256 Feb 6 09:31 recipes.txt 101 return fmt.Sprintf("%s\t%s\t%s\t%v\t%s", 102 fi.Mode.String(), 103 fi.UID, 104 size, 105 fi.MTime.Format("Jan _2 15:04"), 106 ls.Name.FileString(fi)) 107 }