123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- package sizer
- import (
- "errors"
- "os"
- "path/filepath"
- "sync"
- )
- const (
- // FileType is a const representing a file
- FileType = iota
- // DirType is a const representing a directory
- DirType = iota
- // SymLinkType is a const representing a symbolic link
- SymLinkType = iota
- // HardLinkType is a const representing a hard link
- HardLinkType = iota
- // CharDevType is a const representing a char device
- CharDevType = iota
- // NamedPipeType is a const representing a named pipe
- NamedPipeType = iota
- // SocketType is a const representing a socket, both unix and network
- SocketType = iota
- )
- // INode is an entry in the filesystem. It can be:
- // - a file
- // - a directory
- // - a symbolic link
- // - a hard link
- // - a char device/named pipe/socket
- // It takes a Kind (as above described), a Size and a Path
- type INode struct {
- Kind int
- Size int64
- Path string
- Children *INodeList
- }
- // INodeList is a simple *INode slice with a Mutex to allow safe
- // concurrent write.
- type INodeList struct {
- Elements []*INode
- safe sync.Mutex
- }
- type StatusReport struct {
- path string
- size int64
- err error
- }
- // Append appends safely an inode to the INodeList.
- func (il *INodeList) Append(node *INode) {
- il.safe.Lock()
- il.Elements = append(il.Elements, node)
- il.safe.Unlock()
- }
- // INodeChan is a channel global to the sizer package that is used
- // to funnel the retrieved sizes and infos on the inodes.
- var INodeChan chan *INode
- // ErrNotIdenfiedType is the error returned when the a classifier does not
- // recognize the INode type.
- var ErrNotIdenfiedType = errors.New("inode not identified")
- // NewINode returns a new *INode with kind, size and path
- func NewINode(kind int, size int64, path string) *INode {
- var children INodeList
- abspath, _ := filepath.Abs(path)
- var newINode = INode{
- Kind: kind,
- Size: size,
- Path: abspath,
- Children: &children,
- }
- return &newINode
- }
- // Name returns the name of the file at the INode.
- func (i *INode) Name() string {
- _, name := filepath.Split(i.Path)
- return name
- }
- // IdentifyType classifies a file-like object in one of the FileType.
- func IdentifyType(path string) (int, int64, error) {
- f, err := os.Lstat(path)
- if err != nil {
- return -1, 0, err
- }
- switch mode := f.Mode(); {
- case mode.IsDir():
- return DirType, f.Size(), nil
- case mode.IsRegular():
- return FileType, f.Size(), nil
- }
- return -1, 0, ErrNotIdenfiedType
- }
- func ls(path string) ([]string, error) {
- var content []string
- f, err := os.Open(path)
- if err != nil {
- return []string{}, err
- }
- files, err := f.Readdir(-1)
- if err != nil {
- return []string{}, err
- }
- for _, fi := range files {
- content = append(content, filepath.Join(path, fi.Name()))
- }
- return content, nil
- }
- func INodeFromPath(path string) (*INode, error) {
- kind, _, err := IdentifyType(path)
- if err != nil {
- return nil, err
- }
- i := NewINode(kind, 0, path)
- return i, nil
- }
- func (i *INode) size(wg *sync.WaitGroup) {
- //Console.Debugln(i.Path)
- i.Children.safe.Lock()
- defer i.Children.safe.Unlock()
- var wgIn sync.WaitGroup
- for _, child := range i.Children.Elements {
- wg.Add(1)
- go child.walk(&wgIn)
- }
- wgIn.Wait()
- for _, child := range i.Children.Elements {
- i.Size += child.Size
- wg.Done()
- }
- }
- func (i *INode) walk(wg *sync.WaitGroup) {
- children, err := ls(i.Path)
- if err != nil {
- Console.Println(err)
- wg.Done()
- return
- }
- for _, child := range children {
- //Console.Debugln("Parent:", i.Path, "- Child:", child)
- kind, size, err := IdentifyType(child)
- if err != nil {
- Console.Println(child, ":", err)
- }
- childINode := NewINode(kind, size, child)
- i.Children.Append(childINode)
- switch {
- case kind == DirType:
- //Console.Debugln("Size on dir:", child)
- wg.Add(1)
- childINode.size(wg)
- case kind == FileType:
- Console.Debugln("Filesize:", child, "-", size)
- childINode.Size = size
- default:
- //Console.Debugln("Unknown:", child)
- childINode.Size = 0
- }
- }
- wg.Done()
- }
- func (i *INode) Sizer() {
- var wg sync.WaitGroup
- wg.Add(1)
- i.walk(&wg)
- wg.Wait()
- Console.Println(i.Size)
- }
|