object.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. package filesystem
  2. import (
  3. "io"
  4. "os"
  5. "time"
  6. "gopkg.in/src-d/go-git.v4/plumbing"
  7. "gopkg.in/src-d/go-git.v4/plumbing/cache"
  8. "gopkg.in/src-d/go-git.v4/plumbing/format/idxfile"
  9. "gopkg.in/src-d/go-git.v4/plumbing/format/objfile"
  10. "gopkg.in/src-d/go-git.v4/plumbing/format/packfile"
  11. "gopkg.in/src-d/go-git.v4/plumbing/storer"
  12. "gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit"
  13. "gopkg.in/src-d/go-git.v4/utils/ioutil"
  14. "gopkg.in/src-d/go-billy.v4"
  15. )
  16. type ObjectStorage struct {
  17. options Options
  18. // objectCache is an object cache uses to cache delta's bases and also recently
  19. // loaded loose objects
  20. objectCache cache.Object
  21. dir *dotgit.DotGit
  22. index map[plumbing.Hash]idxfile.Index
  23. }
  24. // NewObjectStorage creates a new ObjectStorage with the given .git directory and cache.
  25. func NewObjectStorage(dir *dotgit.DotGit, objectCache cache.Object) *ObjectStorage {
  26. return NewObjectStorageWithOptions(dir, objectCache, Options{})
  27. }
  28. // NewObjectStorageWithOptions creates a new ObjectStorage with the given .git directory, cache and extra options
  29. func NewObjectStorageWithOptions(dir *dotgit.DotGit, objectCache cache.Object, ops Options) *ObjectStorage {
  30. return &ObjectStorage{
  31. options: ops,
  32. objectCache: objectCache,
  33. dir: dir,
  34. }
  35. }
  36. func (s *ObjectStorage) requireIndex() error {
  37. if s.index != nil {
  38. return nil
  39. }
  40. s.index = make(map[plumbing.Hash]idxfile.Index)
  41. packs, err := s.dir.ObjectPacks()
  42. if err != nil {
  43. return err
  44. }
  45. for _, h := range packs {
  46. if err := s.loadIdxFile(h); err != nil {
  47. return err
  48. }
  49. }
  50. return nil
  51. }
  52. // Reindex indexes again all packfiles. Useful if git changed packfiles externally
  53. func (s *ObjectStorage) Reindex() {
  54. s.index = nil
  55. }
  56. func (s *ObjectStorage) loadIdxFile(h plumbing.Hash) (err error) {
  57. f, err := s.dir.ObjectPackIdx(h)
  58. if err != nil {
  59. return err
  60. }
  61. defer ioutil.CheckClose(f, &err)
  62. idxf := idxfile.NewMemoryIndex()
  63. d := idxfile.NewDecoder(f)
  64. if err = d.Decode(idxf); err != nil {
  65. return err
  66. }
  67. s.index[h] = idxf
  68. return err
  69. }
  70. func (s *ObjectStorage) NewEncodedObject() plumbing.EncodedObject {
  71. return &plumbing.MemoryObject{}
  72. }
  73. func (s *ObjectStorage) PackfileWriter() (io.WriteCloser, error) {
  74. if err := s.requireIndex(); err != nil {
  75. return nil, err
  76. }
  77. w, err := s.dir.NewObjectPack()
  78. if err != nil {
  79. return nil, err
  80. }
  81. w.Notify = func(h plumbing.Hash, writer *idxfile.Writer) {
  82. index, err := writer.Index()
  83. if err == nil {
  84. s.index[h] = index
  85. }
  86. }
  87. return w, nil
  88. }
  89. // SetEncodedObject adds a new object to the storage.
  90. func (s *ObjectStorage) SetEncodedObject(o plumbing.EncodedObject) (h plumbing.Hash, err error) {
  91. if o.Type() == plumbing.OFSDeltaObject || o.Type() == plumbing.REFDeltaObject {
  92. return plumbing.ZeroHash, plumbing.ErrInvalidType
  93. }
  94. ow, err := s.dir.NewObject()
  95. if err != nil {
  96. return plumbing.ZeroHash, err
  97. }
  98. defer ioutil.CheckClose(ow, &err)
  99. or, err := o.Reader()
  100. if err != nil {
  101. return plumbing.ZeroHash, err
  102. }
  103. defer ioutil.CheckClose(or, &err)
  104. if err = ow.WriteHeader(o.Type(), o.Size()); err != nil {
  105. return plumbing.ZeroHash, err
  106. }
  107. if _, err = io.Copy(ow, or); err != nil {
  108. return plumbing.ZeroHash, err
  109. }
  110. return o.Hash(), err
  111. }
  112. // HasEncodedObject returns nil if the object exists, without actually
  113. // reading the object data from storage.
  114. func (s *ObjectStorage) HasEncodedObject(h plumbing.Hash) (err error) {
  115. // Check unpacked objects
  116. f, err := s.dir.Object(h)
  117. if err != nil {
  118. if !os.IsNotExist(err) {
  119. return err
  120. }
  121. // Fall through to check packed objects.
  122. } else {
  123. defer ioutil.CheckClose(f, &err)
  124. return nil
  125. }
  126. // Check packed objects.
  127. if err := s.requireIndex(); err != nil {
  128. return err
  129. }
  130. _, _, offset := s.findObjectInPackfile(h)
  131. if offset == -1 {
  132. return plumbing.ErrObjectNotFound
  133. }
  134. return nil
  135. }
  136. func (s *ObjectStorage) encodedObjectSizeFromUnpacked(h plumbing.Hash) (
  137. size int64, err error) {
  138. f, err := s.dir.Object(h)
  139. if err != nil {
  140. if os.IsNotExist(err) {
  141. return 0, plumbing.ErrObjectNotFound
  142. }
  143. return 0, err
  144. }
  145. r, err := objfile.NewReader(f)
  146. if err != nil {
  147. return 0, err
  148. }
  149. defer ioutil.CheckClose(r, &err)
  150. _, size, err = r.Header()
  151. return size, err
  152. }
  153. func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
  154. size int64, err error) {
  155. if err := s.requireIndex(); err != nil {
  156. return 0, err
  157. }
  158. pack, _, offset := s.findObjectInPackfile(h)
  159. if offset == -1 {
  160. return 0, plumbing.ErrObjectNotFound
  161. }
  162. f, err := s.dir.ObjectPack(pack)
  163. if err != nil {
  164. return 0, err
  165. }
  166. defer ioutil.CheckClose(f, &err)
  167. idx := s.index[pack]
  168. hash, err := idx.FindHash(offset)
  169. if err == nil {
  170. obj, ok := s.objectCache.Get(hash)
  171. if ok {
  172. return obj.Size(), nil
  173. }
  174. } else if err != nil && err != plumbing.ErrObjectNotFound {
  175. return 0, err
  176. }
  177. var p *packfile.Packfile
  178. if s.objectCache != nil {
  179. p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.objectCache)
  180. } else {
  181. p = packfile.NewPackfile(idx, s.dir.Fs(), f)
  182. }
  183. return p.GetSizeByOffset(offset)
  184. }
  185. // EncodedObjectSize returns the plaintext size of the given object,
  186. // without actually reading the full object data from storage.
  187. func (s *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (
  188. size int64, err error) {
  189. size, err = s.encodedObjectSizeFromUnpacked(h)
  190. if err != nil && err != plumbing.ErrObjectNotFound {
  191. return 0, err
  192. } else if err == nil {
  193. return size, nil
  194. }
  195. return s.encodedObjectSizeFromPackfile(h)
  196. }
  197. // EncodedObject returns the object with the given hash, by searching for it in
  198. // the packfile and the git object directories.
  199. func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) {
  200. var obj plumbing.EncodedObject
  201. var err error
  202. if s.index != nil {
  203. obj, err = s.getFromPackfile(h, false)
  204. if err == plumbing.ErrObjectNotFound {
  205. obj, err = s.getFromUnpacked(h)
  206. }
  207. } else {
  208. obj, err = s.getFromUnpacked(h)
  209. if err == plumbing.ErrObjectNotFound {
  210. obj, err = s.getFromPackfile(h, false)
  211. }
  212. }
  213. // If the error is still object not found, check if it's a shared object
  214. // repository.
  215. if err == plumbing.ErrObjectNotFound {
  216. dotgits, e := s.dir.Alternates()
  217. if e == nil {
  218. // Create a new object storage with the DotGit(s) and check for the
  219. // required hash object. Skip when not found.
  220. for _, dg := range dotgits {
  221. o := NewObjectStorage(dg, s.objectCache)
  222. enobj, enerr := o.EncodedObject(t, h)
  223. if enerr != nil {
  224. continue
  225. }
  226. return enobj, nil
  227. }
  228. }
  229. }
  230. if err != nil {
  231. return nil, err
  232. }
  233. if plumbing.AnyObject != t && obj.Type() != t {
  234. return nil, plumbing.ErrObjectNotFound
  235. }
  236. return obj, nil
  237. }
  238. // DeltaObject returns the object with the given hash, by searching for
  239. // it in the packfile and the git object directories.
  240. func (s *ObjectStorage) DeltaObject(t plumbing.ObjectType,
  241. h plumbing.Hash) (plumbing.EncodedObject, error) {
  242. obj, err := s.getFromUnpacked(h)
  243. if err == plumbing.ErrObjectNotFound {
  244. obj, err = s.getFromPackfile(h, true)
  245. }
  246. if err != nil {
  247. return nil, err
  248. }
  249. if plumbing.AnyObject != t && obj.Type() != t {
  250. return nil, plumbing.ErrObjectNotFound
  251. }
  252. return obj, nil
  253. }
  254. func (s *ObjectStorage) getFromUnpacked(h plumbing.Hash) (obj plumbing.EncodedObject, err error) {
  255. f, err := s.dir.Object(h)
  256. if err != nil {
  257. if os.IsNotExist(err) {
  258. return nil, plumbing.ErrObjectNotFound
  259. }
  260. return nil, err
  261. }
  262. defer ioutil.CheckClose(f, &err)
  263. if cacheObj, found := s.objectCache.Get(h); found {
  264. return cacheObj, nil
  265. }
  266. obj = s.NewEncodedObject()
  267. r, err := objfile.NewReader(f)
  268. if err != nil {
  269. return nil, err
  270. }
  271. defer ioutil.CheckClose(r, &err)
  272. t, size, err := r.Header()
  273. if err != nil {
  274. return nil, err
  275. }
  276. obj.SetType(t)
  277. obj.SetSize(size)
  278. w, err := obj.Writer()
  279. if err != nil {
  280. return nil, err
  281. }
  282. s.objectCache.Put(obj)
  283. _, err = io.Copy(w, r)
  284. return obj, err
  285. }
  286. // Get returns the object with the given hash, by searching for it in
  287. // the packfile.
  288. func (s *ObjectStorage) getFromPackfile(h plumbing.Hash, canBeDelta bool) (
  289. plumbing.EncodedObject, error) {
  290. if err := s.requireIndex(); err != nil {
  291. return nil, err
  292. }
  293. pack, hash, offset := s.findObjectInPackfile(h)
  294. if offset == -1 {
  295. return nil, plumbing.ErrObjectNotFound
  296. }
  297. f, err := s.dir.ObjectPack(pack)
  298. if err != nil {
  299. return nil, err
  300. }
  301. if !s.options.KeepDescriptors {
  302. defer ioutil.CheckClose(f, &err)
  303. }
  304. idx := s.index[pack]
  305. if canBeDelta {
  306. return s.decodeDeltaObjectAt(f, idx, offset, hash)
  307. }
  308. return s.decodeObjectAt(f, idx, offset)
  309. }
  310. func (s *ObjectStorage) decodeObjectAt(
  311. f billy.File,
  312. idx idxfile.Index,
  313. offset int64,
  314. ) (plumbing.EncodedObject, error) {
  315. hash, err := idx.FindHash(offset)
  316. if err == nil {
  317. obj, ok := s.objectCache.Get(hash)
  318. if ok {
  319. return obj, nil
  320. }
  321. }
  322. if err != nil && err != plumbing.ErrObjectNotFound {
  323. return nil, err
  324. }
  325. var p *packfile.Packfile
  326. if s.objectCache != nil {
  327. p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.objectCache)
  328. } else {
  329. p = packfile.NewPackfile(idx, s.dir.Fs(), f)
  330. }
  331. return p.GetByOffset(offset)
  332. }
  333. func (s *ObjectStorage) decodeDeltaObjectAt(
  334. f billy.File,
  335. idx idxfile.Index,
  336. offset int64,
  337. hash plumbing.Hash,
  338. ) (plumbing.EncodedObject, error) {
  339. if _, err := f.Seek(0, io.SeekStart); err != nil {
  340. return nil, err
  341. }
  342. p := packfile.NewScanner(f)
  343. header, err := p.SeekObjectHeader(offset)
  344. if err != nil {
  345. return nil, err
  346. }
  347. var (
  348. base plumbing.Hash
  349. )
  350. switch header.Type {
  351. case plumbing.REFDeltaObject:
  352. base = header.Reference
  353. case plumbing.OFSDeltaObject:
  354. base, err = idx.FindHash(header.OffsetReference)
  355. if err != nil {
  356. return nil, err
  357. }
  358. default:
  359. return s.decodeObjectAt(f, idx, offset)
  360. }
  361. obj := &plumbing.MemoryObject{}
  362. obj.SetType(header.Type)
  363. w, err := obj.Writer()
  364. if err != nil {
  365. return nil, err
  366. }
  367. if _, _, err := p.NextObject(w); err != nil {
  368. return nil, err
  369. }
  370. return newDeltaObject(obj, hash, base, header.Length), nil
  371. }
  372. func (s *ObjectStorage) findObjectInPackfile(h plumbing.Hash) (plumbing.Hash, plumbing.Hash, int64) {
  373. for packfile, index := range s.index {
  374. offset, err := index.FindOffset(h)
  375. if err == nil {
  376. return packfile, h, offset
  377. }
  378. }
  379. return plumbing.ZeroHash, plumbing.ZeroHash, -1
  380. }
  381. // IterEncodedObjects returns an iterator for all the objects in the packfile
  382. // with the given type.
  383. func (s *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.EncodedObjectIter, error) {
  384. objects, err := s.dir.Objects()
  385. if err != nil {
  386. return nil, err
  387. }
  388. seen := make(map[plumbing.Hash]struct{})
  389. var iters []storer.EncodedObjectIter
  390. if len(objects) != 0 {
  391. iters = append(iters, &objectsIter{s: s, t: t, h: objects})
  392. seen = hashListAsMap(objects)
  393. }
  394. packi, err := s.buildPackfileIters(t, seen)
  395. if err != nil {
  396. return nil, err
  397. }
  398. iters = append(iters, packi)
  399. return storer.NewMultiEncodedObjectIter(iters), nil
  400. }
  401. func (s *ObjectStorage) buildPackfileIters(
  402. t plumbing.ObjectType,
  403. seen map[plumbing.Hash]struct{},
  404. ) (storer.EncodedObjectIter, error) {
  405. if err := s.requireIndex(); err != nil {
  406. return nil, err
  407. }
  408. packs, err := s.dir.ObjectPacks()
  409. if err != nil {
  410. return nil, err
  411. }
  412. return &lazyPackfilesIter{
  413. hashes: packs,
  414. open: func(h plumbing.Hash) (storer.EncodedObjectIter, error) {
  415. pack, err := s.dir.ObjectPack(h)
  416. if err != nil {
  417. return nil, err
  418. }
  419. return newPackfileIter(
  420. s.dir.Fs(), pack, t, seen, s.index[h],
  421. s.objectCache, s.options.KeepDescriptors,
  422. )
  423. },
  424. }, nil
  425. }
  426. // Close closes all opened files.
  427. func (s *ObjectStorage) Close() error {
  428. return s.dir.Close()
  429. }
  430. type lazyPackfilesIter struct {
  431. hashes []plumbing.Hash
  432. open func(h plumbing.Hash) (storer.EncodedObjectIter, error)
  433. cur storer.EncodedObjectIter
  434. }
  435. func (it *lazyPackfilesIter) Next() (plumbing.EncodedObject, error) {
  436. for {
  437. if it.cur == nil {
  438. if len(it.hashes) == 0 {
  439. return nil, io.EOF
  440. }
  441. h := it.hashes[0]
  442. it.hashes = it.hashes[1:]
  443. sub, err := it.open(h)
  444. if err == io.EOF {
  445. continue
  446. } else if err != nil {
  447. return nil, err
  448. }
  449. it.cur = sub
  450. }
  451. ob, err := it.cur.Next()
  452. if err == io.EOF {
  453. it.cur.Close()
  454. it.cur = nil
  455. continue
  456. } else if err != nil {
  457. return nil, err
  458. }
  459. return ob, nil
  460. }
  461. }
  462. func (it *lazyPackfilesIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  463. return storer.ForEachIterator(it, cb)
  464. }
  465. func (it *lazyPackfilesIter) Close() {
  466. if it.cur != nil {
  467. it.cur.Close()
  468. it.cur = nil
  469. }
  470. it.hashes = nil
  471. }
  472. type packfileIter struct {
  473. pack billy.File
  474. iter storer.EncodedObjectIter
  475. seen map[plumbing.Hash]struct{}
  476. // tells whether the pack file should be left open after iteration or not
  477. keepPack bool
  478. }
  479. // NewPackfileIter returns a new EncodedObjectIter for the provided packfile
  480. // and object type. Packfile and index file will be closed after they're
  481. // used. If keepPack is true the packfile won't be closed after the iteration
  482. // finished.
  483. func NewPackfileIter(
  484. fs billy.Filesystem,
  485. f billy.File,
  486. idxFile billy.File,
  487. t plumbing.ObjectType,
  488. keepPack bool,
  489. ) (storer.EncodedObjectIter, error) {
  490. idx := idxfile.NewMemoryIndex()
  491. if err := idxfile.NewDecoder(idxFile).Decode(idx); err != nil {
  492. return nil, err
  493. }
  494. if err := idxFile.Close(); err != nil {
  495. return nil, err
  496. }
  497. seen := make(map[plumbing.Hash]struct{})
  498. return newPackfileIter(fs, f, t, seen, idx, nil, keepPack)
  499. }
  500. func newPackfileIter(
  501. fs billy.Filesystem,
  502. f billy.File,
  503. t plumbing.ObjectType,
  504. seen map[plumbing.Hash]struct{},
  505. index idxfile.Index,
  506. cache cache.Object,
  507. keepPack bool,
  508. ) (storer.EncodedObjectIter, error) {
  509. var p *packfile.Packfile
  510. if cache != nil {
  511. p = packfile.NewPackfileWithCache(index, fs, f, cache)
  512. } else {
  513. p = packfile.NewPackfile(index, fs, f)
  514. }
  515. iter, err := p.GetByType(t)
  516. if err != nil {
  517. return nil, err
  518. }
  519. return &packfileIter{
  520. pack: f,
  521. iter: iter,
  522. seen: seen,
  523. keepPack: keepPack,
  524. }, nil
  525. }
  526. func (iter *packfileIter) Next() (plumbing.EncodedObject, error) {
  527. for {
  528. obj, err := iter.iter.Next()
  529. if err != nil {
  530. return nil, err
  531. }
  532. if _, ok := iter.seen[obj.Hash()]; ok {
  533. continue
  534. }
  535. return obj, nil
  536. }
  537. }
  538. func (iter *packfileIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  539. for {
  540. o, err := iter.Next()
  541. if err != nil {
  542. if err == io.EOF {
  543. iter.Close()
  544. return nil
  545. }
  546. return err
  547. }
  548. if err := cb(o); err != nil {
  549. return err
  550. }
  551. }
  552. }
  553. func (iter *packfileIter) Close() {
  554. iter.iter.Close()
  555. if !iter.keepPack {
  556. _ = iter.pack.Close()
  557. }
  558. }
  559. type objectsIter struct {
  560. s *ObjectStorage
  561. t plumbing.ObjectType
  562. h []plumbing.Hash
  563. }
  564. func (iter *objectsIter) Next() (plumbing.EncodedObject, error) {
  565. if len(iter.h) == 0 {
  566. return nil, io.EOF
  567. }
  568. obj, err := iter.s.getFromUnpacked(iter.h[0])
  569. iter.h = iter.h[1:]
  570. if err != nil {
  571. return nil, err
  572. }
  573. if iter.t != plumbing.AnyObject && iter.t != obj.Type() {
  574. return iter.Next()
  575. }
  576. return obj, err
  577. }
  578. func (iter *objectsIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  579. for {
  580. o, err := iter.Next()
  581. if err != nil {
  582. if err == io.EOF {
  583. return nil
  584. }
  585. return err
  586. }
  587. if err := cb(o); err != nil {
  588. return err
  589. }
  590. }
  591. }
  592. func (iter *objectsIter) Close() {
  593. iter.h = []plumbing.Hash{}
  594. }
  595. func hashListAsMap(l []plumbing.Hash) map[plumbing.Hash]struct{} {
  596. m := make(map[plumbing.Hash]struct{}, len(l))
  597. for _, h := range l {
  598. m[h] = struct{}{}
  599. }
  600. return m
  601. }
  602. func (s *ObjectStorage) ForEachObjectHash(fun func(plumbing.Hash) error) error {
  603. err := s.dir.ForEachObjectHash(fun)
  604. if err == storer.ErrStop {
  605. return nil
  606. }
  607. return err
  608. }
  609. func (s *ObjectStorage) LooseObjectTime(hash plumbing.Hash) (time.Time, error) {
  610. fi, err := s.dir.ObjectStat(hash)
  611. if err != nil {
  612. return time.Time{}, err
  613. }
  614. return fi.ModTime(), nil
  615. }
  616. func (s *ObjectStorage) DeleteLooseObject(hash plumbing.Hash) error {
  617. return s.dir.ObjectDelete(hash)
  618. }
  619. func (s *ObjectStorage) ObjectPacks() ([]plumbing.Hash, error) {
  620. return s.dir.ObjectPacks()
  621. }
  622. func (s *ObjectStorage) DeleteOldObjectPackAndIndex(h plumbing.Hash, t time.Time) error {
  623. return s.dir.DeleteOldObjectPackAndIndex(h, t)
  624. }