github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/ipnsfs/dir.go (about) 1 package ipnsfs 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "sync" 8 9 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 10 11 dag "github.com/ipfs/go-ipfs/merkledag" 12 ft "github.com/ipfs/go-ipfs/unixfs" 13 ufspb "github.com/ipfs/go-ipfs/unixfs/pb" 14 ) 15 16 var ErrNotYetImplemented = errors.New("not yet implemented") 17 var ErrInvalidChild = errors.New("invalid child node") 18 19 type Directory struct { 20 fs *Filesystem 21 parent childCloser 22 23 childDirs map[string]*Directory 24 files map[string]*File 25 26 lock sync.Mutex 27 node *dag.Node 28 ctx context.Context 29 30 name string 31 } 32 33 func NewDirectory(ctx context.Context, name string, node *dag.Node, parent childCloser, fs *Filesystem) *Directory { 34 return &Directory{ 35 ctx: ctx, 36 fs: fs, 37 name: name, 38 node: node, 39 parent: parent, 40 childDirs: make(map[string]*Directory), 41 files: make(map[string]*File), 42 } 43 } 44 45 // closeChild updates the child by the given name to the dag node 'nd' 46 // and changes its own dag node, then propogates the changes upward 47 func (d *Directory) closeChild(name string, nd *dag.Node) error { 48 _, err := d.fs.dserv.Add(nd) 49 if err != nil { 50 return err 51 } 52 53 d.lock.Lock() 54 defer d.lock.Unlock() 55 err = d.node.RemoveNodeLink(name) 56 if err != nil && err != dag.ErrNotFound { 57 return err 58 } 59 60 err = d.node.AddNodeLinkClean(name, nd) 61 if err != nil { 62 return err 63 } 64 65 return d.parent.closeChild(d.name, d.node) 66 } 67 68 func (d *Directory) Type() NodeType { 69 return TDir 70 } 71 72 // childFile returns a file under this directory by the given name if it exists 73 func (d *Directory) childFile(name string) (*File, error) { 74 fi, ok := d.files[name] 75 if ok { 76 return fi, nil 77 } 78 79 nd, err := d.childFromDag(name) 80 if err != nil { 81 return nil, err 82 } 83 i, err := ft.FromBytes(nd.Data) 84 if err != nil { 85 return nil, err 86 } 87 88 switch i.GetType() { 89 case ufspb.Data_Directory: 90 return nil, ErrIsDirectory 91 case ufspb.Data_File: 92 nfi, err := NewFile(name, nd, d, d.fs) 93 if err != nil { 94 return nil, err 95 } 96 d.files[name] = nfi 97 return nfi, nil 98 case ufspb.Data_Metadata: 99 return nil, ErrNotYetImplemented 100 default: 101 return nil, ErrInvalidChild 102 } 103 } 104 105 // childDir returns a directory under this directory by the given name if it 106 // exists. 107 func (d *Directory) childDir(name string) (*Directory, error) { 108 dir, ok := d.childDirs[name] 109 if ok { 110 return dir, nil 111 } 112 113 nd, err := d.childFromDag(name) 114 if err != nil { 115 return nil, err 116 } 117 118 i, err := ft.FromBytes(nd.Data) 119 if err != nil { 120 return nil, err 121 } 122 123 switch i.GetType() { 124 case ufspb.Data_Directory: 125 ndir := NewDirectory(d.ctx, name, nd, d, d.fs) 126 d.childDirs[name] = ndir 127 return ndir, nil 128 case ufspb.Data_File: 129 return nil, fmt.Errorf("%s is not a directory", name) 130 case ufspb.Data_Metadata: 131 return nil, ErrNotYetImplemented 132 default: 133 return nil, ErrInvalidChild 134 } 135 } 136 137 // childFromDag searches through this directories dag node for a child link 138 // with the given name 139 func (d *Directory) childFromDag(name string) (*dag.Node, error) { 140 for _, lnk := range d.node.Links { 141 if lnk.Name == name { 142 return lnk.GetNode(d.ctx, d.fs.dserv) 143 } 144 } 145 146 return nil, os.ErrNotExist 147 } 148 149 // Child returns the child of this directory by the given name 150 func (d *Directory) Child(name string) (FSNode, error) { 151 d.lock.Lock() 152 defer d.lock.Unlock() 153 return d.childUnsync(name) 154 } 155 156 // childUnsync returns the child under this directory by the given name 157 // without locking, useful for operations which already hold a lock 158 func (d *Directory) childUnsync(name string) (FSNode, error) { 159 dir, err := d.childDir(name) 160 if err == nil { 161 return dir, nil 162 } 163 fi, err := d.childFile(name) 164 if err == nil { 165 return fi, nil 166 } 167 168 return nil, os.ErrNotExist 169 } 170 171 func (d *Directory) List() []string { 172 d.lock.Lock() 173 defer d.lock.Unlock() 174 175 var out []string 176 for _, lnk := range d.node.Links { 177 out = append(out, lnk.Name) 178 } 179 return out 180 } 181 182 func (d *Directory) Mkdir(name string) (*Directory, error) { 183 d.lock.Lock() 184 defer d.lock.Unlock() 185 186 _, err := d.childDir(name) 187 if err == nil { 188 return nil, os.ErrExist 189 } 190 _, err = d.childFile(name) 191 if err == nil { 192 return nil, os.ErrExist 193 } 194 195 ndir := &dag.Node{Data: ft.FolderPBData()} 196 err = d.node.AddNodeLinkClean(name, ndir) 197 if err != nil { 198 return nil, err 199 } 200 201 err = d.parent.closeChild(d.name, d.node) 202 if err != nil { 203 return nil, err 204 } 205 206 return d.childDir(name) 207 } 208 209 func (d *Directory) Unlink(name string) error { 210 d.lock.Lock() 211 defer d.lock.Unlock() 212 213 delete(d.childDirs, name) 214 delete(d.files, name) 215 216 err := d.node.RemoveNodeLink(name) 217 if err != nil { 218 return err 219 } 220 221 return d.parent.closeChild(d.name, d.node) 222 } 223 224 // AddChild adds the node 'nd' under this directory giving it the name 'name' 225 func (d *Directory) AddChild(name string, nd *dag.Node) error { 226 d.Lock() 227 defer d.Unlock() 228 pbn, err := ft.FromBytes(nd.Data) 229 if err != nil { 230 return err 231 } 232 233 _, err = d.childUnsync(name) 234 if err == nil { 235 return errors.New("directory already has entry by that name") 236 } 237 238 err = d.node.AddNodeLinkClean(name, nd) 239 if err != nil { 240 return err 241 } 242 243 switch pbn.GetType() { 244 case ft.TDirectory: 245 d.childDirs[name] = NewDirectory(d.ctx, name, nd, d, d.fs) 246 case ft.TFile, ft.TMetadata, ft.TRaw: 247 nfi, err := NewFile(name, nd, d, d.fs) 248 if err != nil { 249 return err 250 } 251 d.files[name] = nfi 252 default: 253 return ErrInvalidChild 254 } 255 return d.parent.closeChild(d.name, d.node) 256 } 257 258 func (d *Directory) GetNode() (*dag.Node, error) { 259 return d.node, nil 260 } 261 262 func (d *Directory) Lock() { 263 d.lock.Lock() 264 } 265 266 func (d *Directory) Unlock() { 267 d.lock.Unlock() 268 }