github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/unixfs/format.go (about) 1 // Package format implements a data format for files in the ipfs filesystem 2 // It is not the only format in ipfs, but it is the one that the filesystem assumes 3 package unixfs 4 5 import ( 6 "errors" 7 8 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" 9 pb "github.com/ipfs/go-ipfs/unixfs/pb" 10 ) 11 12 const ( 13 TRaw = pb.Data_Raw 14 TFile = pb.Data_File 15 TDirectory = pb.Data_Directory 16 TMetadata = pb.Data_Metadata 17 ) 18 19 var ErrMalformedFileFormat = errors.New("malformed data in file format") 20 var ErrInvalidDirLocation = errors.New("found directory node in unexpected place") 21 var ErrUnrecognizedType = errors.New("unrecognized node type") 22 23 func FromBytes(data []byte) (*pb.Data, error) { 24 pbdata := new(pb.Data) 25 err := proto.Unmarshal(data, pbdata) 26 if err != nil { 27 return nil, err 28 } 29 return pbdata, nil 30 } 31 32 func FilePBData(data []byte, totalsize uint64) []byte { 33 pbfile := new(pb.Data) 34 typ := pb.Data_File 35 pbfile.Type = &typ 36 pbfile.Data = data 37 pbfile.Filesize = proto.Uint64(totalsize) 38 39 data, err := proto.Marshal(pbfile) 40 if err != nil { 41 // This really shouldnt happen, i promise 42 // The only failure case for marshal is if required fields 43 // are not filled out, and they all are. If the proto object 44 // gets changed and nobody updates this function, the code 45 // should panic due to programmer error 46 panic(err) 47 } 48 return data 49 } 50 51 // Returns Bytes that represent a Directory 52 func FolderPBData() []byte { 53 pbfile := new(pb.Data) 54 typ := pb.Data_Directory 55 pbfile.Type = &typ 56 57 data, err := proto.Marshal(pbfile) 58 if err != nil { 59 //this really shouldnt happen, i promise 60 panic(err) 61 } 62 return data 63 } 64 65 func WrapData(b []byte) []byte { 66 pbdata := new(pb.Data) 67 typ := pb.Data_Raw 68 pbdata.Data = b 69 pbdata.Type = &typ 70 71 out, err := proto.Marshal(pbdata) 72 if err != nil { 73 // This shouldnt happen. seriously. 74 panic(err) 75 } 76 77 return out 78 } 79 80 func SymlinkData(path string) ([]byte, error) { 81 pbdata := new(pb.Data) 82 typ := pb.Data_Symlink 83 pbdata.Data = []byte(path) 84 pbdata.Type = &typ 85 86 out, err := proto.Marshal(pbdata) 87 if err != nil { 88 return nil, err 89 } 90 91 return out, nil 92 } 93 94 func UnwrapData(data []byte) ([]byte, error) { 95 pbdata := new(pb.Data) 96 err := proto.Unmarshal(data, pbdata) 97 if err != nil { 98 return nil, err 99 } 100 return pbdata.GetData(), nil 101 } 102 103 func DataSize(data []byte) (uint64, error) { 104 pbdata := new(pb.Data) 105 err := proto.Unmarshal(data, pbdata) 106 if err != nil { 107 return 0, err 108 } 109 110 switch pbdata.GetType() { 111 case pb.Data_Directory: 112 return 0, errors.New("Cant get data size of directory!") 113 case pb.Data_File: 114 return pbdata.GetFilesize(), nil 115 case pb.Data_Raw: 116 return uint64(len(pbdata.GetData())), nil 117 default: 118 return 0, errors.New("Unrecognized node data type!") 119 } 120 } 121 122 type FSNode struct { 123 Data []byte 124 125 // total data size for each child 126 blocksizes []uint64 127 128 // running sum of blocksizes 129 subtotal uint64 130 131 // node type of this node 132 Type pb.Data_DataType 133 } 134 135 func FSNodeFromBytes(b []byte) (*FSNode, error) { 136 pbn := new(pb.Data) 137 err := proto.Unmarshal(b, pbn) 138 if err != nil { 139 return nil, err 140 } 141 142 n := new(FSNode) 143 n.Data = pbn.Data 144 n.blocksizes = pbn.Blocksizes 145 n.subtotal = pbn.GetFilesize() - uint64(len(n.Data)) 146 n.Type = pbn.GetType() 147 return n, nil 148 } 149 150 // AddBlockSize adds the size of the next child block of this node 151 func (n *FSNode) AddBlockSize(s uint64) { 152 n.subtotal += s 153 n.blocksizes = append(n.blocksizes, s) 154 } 155 156 func (n *FSNode) RemoveBlockSize(i int) { 157 n.subtotal -= n.blocksizes[i] 158 n.blocksizes = append(n.blocksizes[:i], n.blocksizes[i+1:]...) 159 } 160 161 func (n *FSNode) GetBytes() ([]byte, error) { 162 pbn := new(pb.Data) 163 pbn.Type = &n.Type 164 pbn.Filesize = proto.Uint64(uint64(len(n.Data)) + n.subtotal) 165 pbn.Blocksizes = n.blocksizes 166 pbn.Data = n.Data 167 return proto.Marshal(pbn) 168 } 169 170 func (n *FSNode) FileSize() uint64 { 171 return uint64(len(n.Data)) + n.subtotal 172 } 173 174 func (n *FSNode) NumChildren() int { 175 return len(n.blocksizes) 176 } 177 178 type Metadata struct { 179 MimeType string 180 Size uint64 181 } 182 183 func MetadataFromBytes(b []byte) (*Metadata, error) { 184 pbd := new(pb.Data) 185 err := proto.Unmarshal(b, pbd) 186 if err != nil { 187 return nil, err 188 } 189 if pbd.GetType() != pb.Data_Metadata { 190 return nil, errors.New("incorrect node type") 191 } 192 193 pbm := new(pb.Metadata) 194 err = proto.Unmarshal(pbd.Data, pbm) 195 if err != nil { 196 return nil, err 197 } 198 md := new(Metadata) 199 md.MimeType = pbm.GetMimeType() 200 return md, nil 201 } 202 203 func (m *Metadata) Bytes() ([]byte, error) { 204 pbm := new(pb.Metadata) 205 pbm.MimeType = &m.MimeType 206 return proto.Marshal(pbm) 207 } 208 209 func BytesForMetadata(m *Metadata) ([]byte, error) { 210 pbd := new(pb.Data) 211 pbd.Filesize = proto.Uint64(m.Size) 212 typ := pb.Data_Metadata 213 pbd.Type = &typ 214 mdd, err := m.Bytes() 215 if err != nil { 216 return nil, err 217 } 218 219 pbd.Data = mdd 220 return proto.Marshal(pbd) 221 }