github.com/damirazo/docker@v1.9.0/daemon/graphdriver/fsdiff.go (about) 1 // +build daemon 2 3 package graphdriver 4 5 import ( 6 "time" 7 8 "github.com/Sirupsen/logrus" 9 10 "github.com/docker/docker/pkg/archive" 11 "github.com/docker/docker/pkg/chrootarchive" 12 "github.com/docker/docker/pkg/idtools" 13 "github.com/docker/docker/pkg/ioutils" 14 ) 15 16 // NaiveDiffDriver takes a ProtoDriver and adds the 17 // capability of the Diffing methods which it may or may not 18 // support on its own. See the comment on the exported 19 // NewNaiveDiffDriver function below. 20 // Notably, the AUFS driver doesn't need to be wrapped like this. 21 type NaiveDiffDriver struct { 22 ProtoDriver 23 uidMaps []idtools.IDMap 24 gidMaps []idtools.IDMap 25 } 26 27 // NewNaiveDiffDriver returns a fully functional driver that wraps the 28 // given ProtoDriver and adds the capability of the following methods which 29 // it may or may not support on its own: 30 // Diff(id, parent string) (archive.Archive, error) 31 // Changes(id, parent string) ([]archive.Change, error) 32 // ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) 33 // DiffSize(id, parent string) (size int64, err error) 34 func NewNaiveDiffDriver(driver ProtoDriver, uidMaps, gidMaps []idtools.IDMap) Driver { 35 return &NaiveDiffDriver{ProtoDriver: driver, 36 uidMaps: uidMaps, 37 gidMaps: gidMaps} 38 } 39 40 // Diff produces an archive of the changes between the specified 41 // layer and its parent layer which may be "". 42 func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { 43 driver := gdw.ProtoDriver 44 45 layerFs, err := driver.Get(id, "") 46 if err != nil { 47 return nil, err 48 } 49 50 defer func() { 51 if err != nil { 52 driver.Put(id) 53 } 54 }() 55 56 if parent == "" { 57 archive, err := archive.Tar(layerFs, archive.Uncompressed) 58 if err != nil { 59 return nil, err 60 } 61 return ioutils.NewReadCloserWrapper(archive, func() error { 62 err := archive.Close() 63 driver.Put(id) 64 return err 65 }), nil 66 } 67 68 parentFs, err := driver.Get(parent, "") 69 if err != nil { 70 return nil, err 71 } 72 defer driver.Put(parent) 73 74 changes, err := archive.ChangesDirs(layerFs, parentFs) 75 if err != nil { 76 return nil, err 77 } 78 79 archive, err := archive.ExportChanges(layerFs, changes, gdw.uidMaps, gdw.gidMaps) 80 if err != nil { 81 return nil, err 82 } 83 84 return ioutils.NewReadCloserWrapper(archive, func() error { 85 err := archive.Close() 86 driver.Put(id) 87 return err 88 }), nil 89 } 90 91 // Changes produces a list of changes between the specified layer 92 // and its parent layer. If parent is "", then all changes will be ADD changes. 93 func (gdw *NaiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) { 94 driver := gdw.ProtoDriver 95 96 layerFs, err := driver.Get(id, "") 97 if err != nil { 98 return nil, err 99 } 100 defer driver.Put(id) 101 102 parentFs := "" 103 104 if parent != "" { 105 parentFs, err = driver.Get(parent, "") 106 if err != nil { 107 return nil, err 108 } 109 defer driver.Put(parent) 110 } 111 112 return archive.ChangesDirs(layerFs, parentFs) 113 } 114 115 // ApplyDiff extracts the changeset from the given diff into the 116 // layer with the specified id and parent, returning the size of the 117 // new layer in bytes. 118 func (gdw *NaiveDiffDriver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) { 119 driver := gdw.ProtoDriver 120 121 // Mount the root filesystem so we can apply the diff/layer. 122 layerFs, err := driver.Get(id, "") 123 if err != nil { 124 return 125 } 126 defer driver.Put(id) 127 128 options := &archive.TarOptions{UIDMaps: gdw.uidMaps, 129 GIDMaps: gdw.gidMaps} 130 start := time.Now().UTC() 131 logrus.Debugf("Start untar layer") 132 if size, err = chrootarchive.ApplyUncompressedLayer(layerFs, diff, options); err != nil { 133 return 134 } 135 logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) 136 137 return 138 } 139 140 // DiffSize calculates the changes between the specified layer 141 // and its parent and returns the size in bytes of the changes 142 // relative to its base filesystem directory. 143 func (gdw *NaiveDiffDriver) DiffSize(id, parent string) (size int64, err error) { 144 driver := gdw.ProtoDriver 145 146 changes, err := gdw.Changes(id, parent) 147 if err != nil { 148 return 149 } 150 151 layerFs, err := driver.Get(id, "") 152 if err != nil { 153 return 154 } 155 defer driver.Put(id) 156 157 return archive.ChangesSize(layerFs, changes), nil 158 }