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  }