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