You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
6.6 KiB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
  1. package storage
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "os"
  7. "code.google.com/p/weed-fs/go/util"
  8. )
  9. const (
  10. FlagGzip = 0x01
  11. FlagHasName = 0x02
  12. FlagHasMime = 0x04
  13. )
  14. func (n *Needle) DiskSize() uint32 {
  15. padding := NeedlePaddingSize - ((NeedleHeaderSize + n.Size + NeedleChecksumSize) % NeedlePaddingSize)
  16. return NeedleHeaderSize + n.Size + padding + NeedleChecksumSize
  17. }
  18. func (n *Needle) Append(w io.Writer, version Version) (size uint32, err error) {
  19. if s, ok := w.(io.Seeker); ok {
  20. if end, e := s.Seek(0, 1); e == nil {
  21. defer func(s io.Seeker, off int64) {
  22. if err != nil {
  23. if _, e = s.Seek(off, 0); e != nil {
  24. fmt.Printf("Failed to seek back to %d with error: %s\n", w, off, e)
  25. }
  26. }
  27. }(s, end)
  28. } else {
  29. err = fmt.Errorf("Cnnot Read Current Volume Position: %s", e)
  30. return
  31. }
  32. }
  33. switch version {
  34. case Version1:
  35. header := make([]byte, NeedleHeaderSize)
  36. util.Uint32toBytes(header[0:4], n.Cookie)
  37. util.Uint64toBytes(header[4:12], n.Id)
  38. n.Size = uint32(len(n.Data))
  39. size = n.Size
  40. util.Uint32toBytes(header[12:16], n.Size)
  41. if _, err = w.Write(header); err != nil {
  42. return
  43. }
  44. if _, err = w.Write(n.Data); err != nil {
  45. return
  46. }
  47. padding := NeedlePaddingSize - ((NeedleHeaderSize + n.Size + NeedleChecksumSize) % NeedlePaddingSize)
  48. util.Uint32toBytes(header[0:NeedleChecksumSize], n.Checksum.Value())
  49. _, err = w.Write(header[0 : NeedleChecksumSize+padding])
  50. return
  51. case Version2:
  52. header := make([]byte, NeedleHeaderSize)
  53. util.Uint32toBytes(header[0:4], n.Cookie)
  54. util.Uint64toBytes(header[4:12], n.Id)
  55. n.DataSize, n.NameSize, n.MimeSize = uint32(len(n.Data)), uint8(len(n.Name)), uint8(len(n.Mime))
  56. if n.DataSize > 0 {
  57. n.Size = 4 + n.DataSize + 1
  58. if n.HasName() {
  59. n.Size = n.Size + 1 + uint32(n.NameSize)
  60. }
  61. if n.HasMime() {
  62. n.Size = n.Size + 1 + uint32(n.MimeSize)
  63. }
  64. }
  65. size = n.DataSize
  66. util.Uint32toBytes(header[12:16], n.Size)
  67. if _, err = w.Write(header); err != nil {
  68. return
  69. }
  70. if n.DataSize > 0 {
  71. util.Uint32toBytes(header[0:4], n.DataSize)
  72. if _, err = w.Write(header[0:4]); err != nil {
  73. return
  74. }
  75. if _, err = w.Write(n.Data); err != nil {
  76. return
  77. }
  78. util.Uint8toBytes(header[0:1], n.Flags)
  79. if _, err = w.Write(header[0:1]); err != nil {
  80. return
  81. }
  82. }
  83. if n.HasName() {
  84. util.Uint8toBytes(header[0:1], n.NameSize)
  85. if _, err = w.Write(header[0:1]); err != nil {
  86. return
  87. }
  88. if _, err = w.Write(n.Name); err != nil {
  89. return
  90. }
  91. }
  92. if n.HasMime() {
  93. util.Uint8toBytes(header[0:1], n.MimeSize)
  94. if _, err = w.Write(header[0:1]); err != nil {
  95. return
  96. }
  97. if _, err = w.Write(n.Mime); err != nil {
  98. return
  99. }
  100. }
  101. padding := NeedlePaddingSize - ((NeedleHeaderSize + n.Size + NeedleChecksumSize) % NeedlePaddingSize)
  102. util.Uint32toBytes(header[0:NeedleChecksumSize], n.Checksum.Value())
  103. _, err = w.Write(header[0 : NeedleChecksumSize+padding])
  104. return n.DataSize, err
  105. }
  106. return 0, fmt.Errorf("Unsupported Version! (%d)", version)
  107. }
  108. func (n *Needle) Read(r io.Reader, size uint32, version Version) (ret int, err error) {
  109. switch version {
  110. case Version1:
  111. bytes := make([]byte, NeedleHeaderSize+size+NeedleChecksumSize)
  112. if ret, err = r.Read(bytes); err != nil {
  113. return
  114. }
  115. n.readNeedleHeader(bytes)
  116. n.Data = bytes[NeedleHeaderSize : NeedleHeaderSize+size]
  117. checksum := util.BytesToUint32(bytes[NeedleHeaderSize+size : NeedleHeaderSize+size+NeedleChecksumSize])
  118. if checksum != NewCRC(n.Data).Value() {
  119. return 0, errors.New("CRC error! Data On Disk Corrupted!")
  120. }
  121. return
  122. case Version2:
  123. if size == 0 {
  124. return 0, nil
  125. }
  126. bytes := make([]byte, NeedleHeaderSize+size+NeedleChecksumSize)
  127. if ret, err = r.Read(bytes); err != nil {
  128. return
  129. }
  130. if ret != int(NeedleHeaderSize+size+NeedleChecksumSize) {
  131. return 0, errors.New("File Entry Not Found!")
  132. }
  133. n.readNeedleHeader(bytes)
  134. if n.Size != size {
  135. return 0, fmt.Errorf("File Entry Not Found! Needle %d Memory %d", n.Size, size)
  136. }
  137. n.readNeedleDataVersion2(bytes[NeedleHeaderSize : NeedleHeaderSize+int(n.Size)])
  138. checksum := util.BytesToUint32(bytes[NeedleHeaderSize+n.Size : NeedleHeaderSize+n.Size+NeedleChecksumSize])
  139. if checksum != NewCRC(n.Data).Value() {
  140. return 0, errors.New("CRC error! Data On Disk Corrupted!")
  141. }
  142. return
  143. }
  144. return 0, fmt.Errorf("Unsupported Version! (%d)", version)
  145. }
  146. func (n *Needle) readNeedleHeader(bytes []byte) {
  147. n.Cookie = util.BytesToUint32(bytes[0:4])
  148. n.Id = util.BytesToUint64(bytes[4:12])
  149. n.Size = util.BytesToUint32(bytes[12:NeedleHeaderSize])
  150. }
  151. func (n *Needle) readNeedleDataVersion2(bytes []byte) {
  152. index, lenBytes := 0, len(bytes)
  153. if index < lenBytes {
  154. n.DataSize = util.BytesToUint32(bytes[index : index+4])
  155. index = index + 4
  156. n.Data = bytes[index : index+int(n.DataSize)]
  157. index = index + int(n.DataSize)
  158. n.Flags = bytes[index]
  159. index = index + 1
  160. }
  161. if index < lenBytes && n.HasName() {
  162. n.NameSize = uint8(bytes[index])
  163. index = index + 1
  164. n.Name = bytes[index : index+int(n.NameSize)]
  165. index = index + int(n.NameSize)
  166. }
  167. if index < lenBytes && n.HasMime() {
  168. n.MimeSize = uint8(bytes[index])
  169. index = index + 1
  170. n.Mime = bytes[index : index+int(n.MimeSize)]
  171. }
  172. }
  173. func ReadNeedleHeader(r *os.File, version Version) (n *Needle, bodyLength uint32, err error) {
  174. n = new(Needle)
  175. if version == Version1 || version == Version2 {
  176. bytes := make([]byte, NeedleHeaderSize)
  177. var count int
  178. count, err = r.Read(bytes)
  179. if count <= 0 || err != nil {
  180. return nil, 0, err
  181. }
  182. n.readNeedleHeader(bytes)
  183. padding := NeedlePaddingSize - ((n.Size + NeedleHeaderSize + NeedleChecksumSize) % NeedlePaddingSize)
  184. bodyLength = n.Size + NeedleChecksumSize + padding
  185. }
  186. return
  187. }
  188. //n should be a needle already read the header
  189. //the input stream will read until next file entry
  190. func (n *Needle) ReadNeedleBody(r *os.File, version Version, bodyLength uint32) (err error) {
  191. if bodyLength <= 0 {
  192. return nil
  193. }
  194. switch version {
  195. case Version1:
  196. bytes := make([]byte, bodyLength)
  197. if _, err = r.Read(bytes); err != nil {
  198. return
  199. }
  200. n.Data = bytes[:n.Size]
  201. n.Checksum = NewCRC(n.Data)
  202. case Version2:
  203. bytes := make([]byte, bodyLength)
  204. if _, err = r.Read(bytes); err != nil {
  205. return
  206. }
  207. n.readNeedleDataVersion2(bytes[0:n.Size])
  208. n.Checksum = NewCRC(n.Data)
  209. default:
  210. err = fmt.Errorf("Unsupported Version! (%d)", version)
  211. }
  212. return
  213. }
  214. func (n *Needle) IsGzipped() bool {
  215. return n.Flags&FlagGzip > 0
  216. }
  217. func (n *Needle) SetGzipped() {
  218. n.Flags = n.Flags | FlagGzip
  219. }
  220. func (n *Needle) HasName() bool {
  221. return n.Flags&FlagHasName > 0
  222. }
  223. func (n *Needle) SetHasName() {
  224. n.Flags = n.Flags | FlagHasName
  225. }
  226. func (n *Needle) HasMime() bool {
  227. return n.Flags&FlagHasMime > 0
  228. }
  229. func (n *Needle) SetHasMime() {
  230. n.Flags = n.Flags | FlagHasMime
  231. }