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 }