github.com/Cloud-Foundations/Dominator@v0.3.4/lib/filesystem/list.go (about)

     1  package filesystem
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"path"
     7  	"syscall"
     8  	"time"
     9  
    10  	"github.com/Cloud-Foundations/Dominator/lib/filter"
    11  )
    12  
    13  const (
    14  	timeFormat  string = "02 Jan 2006 15:04:05 MST"
    15  	symlinkMode        = syscall.S_IFLNK | syscall.S_IRWXU | syscall.S_IRWXG |
    16  		syscall.S_IRWXO
    17  )
    18  
    19  func (fs *FileSystem) list(w io.Writer, listSelector ListSelector,
    20  	filter *filter.Filter) error {
    21  	numLinksTable := buildNumLinksTable(fs)
    22  	return fs.DirectoryInode.list(w, "/", numLinksTable, 1, listSelector,
    23  		filter)
    24  }
    25  
    26  func buildNumLinksTable(fs *FileSystem) NumLinksTable {
    27  	numLinksTable := make(NumLinksTable)
    28  	fs.DirectoryInode.scanDirectory(fs, numLinksTable)
    29  	return numLinksTable
    30  }
    31  
    32  func (inode *DirectoryInode) scanDirectory(fs *FileSystem,
    33  	numLinksTable NumLinksTable) {
    34  	for _, dirent := range inode.EntryList {
    35  		numLinksTable[dirent.InodeNumber]++
    36  		if inode, ok := dirent.Inode().(*DirectoryInode); ok {
    37  			inode.scanDirectory(fs, numLinksTable)
    38  		}
    39  	}
    40  }
    41  
    42  func (inode *DirectoryInode) list(w io.Writer, name string,
    43  	numLinksTable NumLinksTable, numLinks int,
    44  	listSelector ListSelector, filter *filter.Filter) error {
    45  	if err := listUntilName(w, inode.Mode, numLinks, inode.Uid, inode.Gid,
    46  		0, -1, -1, name, true, listSelector); err != nil {
    47  		return err
    48  	}
    49  	for _, dirent := range inode.EntryList {
    50  		pathname := path.Join(name, dirent.Name)
    51  		if filter != nil && filter.Match(pathname) {
    52  			continue
    53  		}
    54  		err := dirent.inode.List(w, pathname, numLinksTable,
    55  			numLinksTable[dirent.InodeNumber], listSelector, filter)
    56  		if err != nil {
    57  			return err
    58  		}
    59  	}
    60  	return nil
    61  }
    62  
    63  func (inode *RegularInode) list(w io.Writer, name string,
    64  	numLinksTable NumLinksTable, numLinks int,
    65  	listSelector ListSelector) error {
    66  	if err := listUntilName(w, inode.Mode, numLinks, inode.Uid, inode.Gid,
    67  		inode.Size, inode.MtimeSeconds, inode.MtimeNanoSeconds, name, false,
    68  		listSelector); err != nil {
    69  		return err
    70  	}
    71  	var err error
    72  	if inode.Size > 0 && listSelector&ListSelectSkipData == 0 {
    73  		_, err = fmt.Fprintf(w, " %x\n", inode.Hash)
    74  	} else {
    75  		_, err = io.WriteString(w, "\n")
    76  	}
    77  	return err
    78  }
    79  
    80  func (inode *ComputedRegularInode) list(w io.Writer, name string,
    81  	numLinksTable NumLinksTable, numLinks int,
    82  	listSelector ListSelector) error {
    83  	if err := listUntilName(w, inode.Mode, numLinks, inode.Uid, inode.Gid,
    84  		0, -1, -1, name, false, listSelector); err != nil {
    85  		return err
    86  	}
    87  	var err error
    88  	if listSelector&ListSelectSkipData == 0 {
    89  		_, err = fmt.Fprintf(w, " <- %s\n", inode.Source)
    90  	} else {
    91  		_, err = io.WriteString(w, "\n")
    92  	}
    93  	return err
    94  }
    95  
    96  func (inode *SymlinkInode) list(w io.Writer, name string,
    97  	numLinksTable NumLinksTable, numLinks int,
    98  	listSelector ListSelector) error {
    99  	if err := listUntilName(w, symlinkMode, numLinks, inode.Uid, inode.Gid,
   100  		0, -1, -1, name, false, listSelector); err != nil {
   101  		return err
   102  	}
   103  	var err error
   104  	if listSelector&ListSelectSkipData == 0 {
   105  		_, err = fmt.Fprintf(w, " -> %s\n", inode.Symlink)
   106  	} else {
   107  		_, err = io.WriteString(w, "\n")
   108  	}
   109  	return err
   110  }
   111  
   112  func (inode *SpecialInode) list(w io.Writer, name string,
   113  	numLinksTable NumLinksTable, numLinks int,
   114  	listSelector ListSelector) error {
   115  	return listUntilName(w, inode.Mode, numLinks, inode.Uid, inode.Gid,
   116  		inode.Rdev, inode.MtimeSeconds, inode.MtimeNanoSeconds, name, true,
   117  		listSelector)
   118  }
   119  
   120  func listUntilName(w io.Writer, mode FileMode, numLinks int, uid uint32,
   121  	gid uint32, data uint64, seconds int64, nanoSeconds int32, name string,
   122  	newline bool, listSelector ListSelector) error {
   123  	if listSelector&ListSelectSkipMode == 0 {
   124  		if _, err := io.WriteString(w, mode.String()+" "); err != nil {
   125  			return err
   126  		}
   127  	}
   128  	if listSelector&ListSelectSkipNumLinks == 0 {
   129  		if _, err := fmt.Fprintf(w, "%3d ", numLinks); err != nil {
   130  			return err
   131  		}
   132  	}
   133  	if listSelector&ListSelectSkipUid == 0 {
   134  		if _, err := fmt.Fprintf(w, "%5d ", uid); err != nil {
   135  			return err
   136  		}
   137  	}
   138  	if listSelector&ListSelectSkipGid == 0 {
   139  		if _, err := fmt.Fprintf(w, "%5d ", gid); err != nil {
   140  			return err
   141  		}
   142  	}
   143  	if listSelector&ListSelectSkipSizeDevnum == 0 {
   144  		var err error
   145  		switch mode & syscall.S_IFMT {
   146  		case syscall.S_IFREG:
   147  			if data == 0 && seconds < 0 && nanoSeconds < 0 {
   148  				_, err = fmt.Fprintf(w, "%10s ", "computed")
   149  			} else {
   150  				_, err = fmt.Fprintf(w, "%10d ", data)
   151  			}
   152  		case syscall.S_IFBLK, syscall.S_IFCHR:
   153  			_, err = fmt.Fprintf(w, "%#10x ", data)
   154  		default:
   155  			_, err = fmt.Fprintf(w, "%11s", "")
   156  		}
   157  		if err != nil {
   158  			return err
   159  		}
   160  	}
   161  	if listSelector&ListSelectSkipMtime == 0 {
   162  		var err error
   163  		if seconds == -1 && nanoSeconds == -1 {
   164  			_, err = fmt.Fprintf(w, "%25s", "")
   165  		} else {
   166  			t := time.Unix(seconds, int64(nanoSeconds))
   167  			_, err = io.WriteString(w, t.Format(timeFormat)+" ")
   168  		}
   169  		if err != nil {
   170  			return err
   171  		}
   172  	}
   173  	if listSelector&ListSelectSkipName == 0 {
   174  		if _, err := io.WriteString(w, name); err != nil {
   175  			return err
   176  		}
   177  	}
   178  	if newline {
   179  		_, err := io.WriteString(w, "\n")
   180  		return err
   181  	}
   182  	return nil
   183  }
   184  
   185  func (mode FileMode) string() string {
   186  	var buf [10]byte
   187  	w := 1
   188  	const rwx = "rwxrwxrwx"
   189  	for i, c := range rwx {
   190  		if mode&(1<<uint(9-1-i)) != 0 {
   191  			buf[w] = byte(c)
   192  		} else {
   193  			buf[w] = '-'
   194  		}
   195  		w++
   196  	}
   197  	switch mode & syscall.S_IFMT {
   198  	case syscall.S_IFSOCK:
   199  		buf[0] = 's'
   200  	case syscall.S_IFLNK:
   201  		buf[0] = 'l'
   202  	case syscall.S_IFREG:
   203  		buf[0] = '-'
   204  	case syscall.S_IFBLK:
   205  		buf[0] = 'b'
   206  	case syscall.S_IFDIR:
   207  		buf[0] = 'd'
   208  	case syscall.S_IFCHR:
   209  		buf[0] = 'c'
   210  	case syscall.S_IFIFO:
   211  		buf[0] = 'p'
   212  	default:
   213  		buf[0] = '?'
   214  	}
   215  	if mode&syscall.S_ISUID != 0 {
   216  		if mode&syscall.S_IXUSR == 0 {
   217  			buf[3] = 'S'
   218  		} else {
   219  			buf[3] = 's'
   220  		}
   221  	}
   222  	if mode&syscall.S_ISGID != 0 {
   223  		if mode&syscall.S_IXGRP == 0 {
   224  			buf[6] = 'S'
   225  		} else {
   226  			buf[6] = 's'
   227  		}
   228  	}
   229  	if mode&syscall.S_ISVTX != 0 {
   230  		if mode&syscall.S_IXOTH == 0 {
   231  			buf[9] = 'T'
   232  		} else {
   233  			buf[9] = 't'
   234  		}
   235  	}
   236  	return string(buf[:])
   237  }