| 106 | } |
| 107 | |
| 108 | func (e *Encoder) Write(indexPath string) error { |
| 109 | var entries []fileEntry |
| 110 | var setHashInput []byte |
| 111 | for i, k := range e.filePaths { |
| 112 | data := e.fileData[i] |
| 113 | var status fileEntryStatus |
| 114 | status.setSavedInVolumeSet(true) |
| 115 | hash := md5.Sum(data) |
| 116 | entry := fileEntry{ |
| 117 | header: fileEntryHeader{ |
| 118 | Status: status, |
| 119 | FileBytes: uint64(len(data)), |
| 120 | Hash: hash, |
| 121 | SixteenKHash: sixteenKHash(data), |
| 122 | }, |
| 123 | filename: filepath.Base(k), |
| 124 | } |
| 125 | entries = append(entries, entry) |
| 126 | setHashInput = append(setHashInput, hash[:]...) |
| 127 | } |
| 128 | |
| 129 | vTemplate := volume{ |
| 130 | header: header{ |
| 131 | ID: expectedID, |
| 132 | VersionNumber: makeVersionNumber(expectedVersion), |
| 133 | SetHash: md5.Sum(setHashInput), |
| 134 | }, |
| 135 | entries: entries, |
| 136 | } |
| 137 | |
| 138 | indexVolume := vTemplate |
| 139 | indexVolume.header.VolumeNumber = 0 |
| 140 | indexVolumeBytes, err := writeVolume(indexVolume) |
| 141 | if err != nil { |
| 142 | return err |
| 143 | } |
| 144 | |
| 145 | // TODO: Sanity-check indexPath. |
| 146 | ext := path.Ext(indexPath) |
| 147 | base := indexPath[:len(indexPath)-len(ext)] |
| 148 | |
| 149 | realIndexPath := base + ".par" |
| 150 | err = e.fileIO.WriteFile(realIndexPath, indexVolumeBytes) |
| 151 | e.delegate.OnVolumeFileWrite(0, len(e.parityData), realIndexPath, len(indexVolume.data), len(indexVolumeBytes), err) |
| 152 | if err != nil { |
| 153 | return err |
| 154 | } |
| 155 | |
| 156 | for i, parityShard := range e.parityData { |
| 157 | vol := vTemplate |
| 158 | vol.header.VolumeNumber = uint64(i + 1) |
| 159 | vol.data = parityShard |
| 160 | volBytes, err := writeVolume(vol) |
| 161 | if err != nil { |
| 162 | return err |
| 163 | } |
| 164 | |
| 165 | // TODO: Handle more than 99 parity files. |