github.com/afein/docker@v1.8.2/daemon/graphdriver/windows/windows.go (about) 1 //+build windows 2 3 package windows 4 5 import ( 6 "fmt" 7 "os" 8 "path/filepath" 9 "sync" 10 "time" 11 12 "github.com/Sirupsen/logrus" 13 "github.com/docker/docker/daemon/graphdriver" 14 "github.com/docker/docker/pkg/archive" 15 "github.com/docker/docker/pkg/chrootarchive" 16 "github.com/docker/docker/pkg/ioutils" 17 "github.com/microsoft/hcsshim" 18 ) 19 20 func init() { 21 graphdriver.Register("windowsfilter", InitFilter) 22 graphdriver.Register("windowsdiff", InitDiff) 23 } 24 25 const ( 26 diffDriver = iota 27 filterDriver 28 ) 29 30 type WindowsGraphDriver struct { 31 info hcsshim.DriverInfo 32 sync.Mutex // Protects concurrent modification to active 33 active map[string]int 34 } 35 36 // New returns a new Windows storage filter driver. 37 func InitFilter(home string, options []string) (graphdriver.Driver, error) { 38 logrus.Debugf("WindowsGraphDriver InitFilter at %s", home) 39 d := &WindowsGraphDriver{ 40 info: hcsshim.DriverInfo{ 41 HomeDir: home, 42 Flavour: filterDriver, 43 }, 44 active: make(map[string]int), 45 } 46 return d, nil 47 } 48 49 // New returns a new Windows differencing disk driver. 50 func InitDiff(home string, options []string) (graphdriver.Driver, error) { 51 logrus.Debugf("WindowsGraphDriver InitDiff at %s", home) 52 d := &WindowsGraphDriver{ 53 info: hcsshim.DriverInfo{ 54 HomeDir: home, 55 Flavour: diffDriver, 56 }, 57 active: make(map[string]int), 58 } 59 return d, nil 60 } 61 62 func (d *WindowsGraphDriver) Info() hcsshim.DriverInfo { 63 return d.info 64 } 65 66 func (d *WindowsGraphDriver) String() string { 67 switch d.info.Flavour { 68 case diffDriver: 69 return "windowsdiff" 70 case filterDriver: 71 return "windowsfilter" 72 default: 73 return "Unknown driver flavour" 74 } 75 } 76 77 func (d *WindowsGraphDriver) Status() [][2]string { 78 return [][2]string{ 79 {"Windows", ""}, 80 } 81 } 82 83 // Exists returns true if the given id is registered with 84 // this driver 85 func (d *WindowsGraphDriver) Exists(id string) bool { 86 result, err := hcsshim.LayerExists(d.info, id) 87 if err != nil { 88 return false 89 } 90 return result 91 } 92 93 func (d *WindowsGraphDriver) Create(id, parent string) error { 94 return hcsshim.CreateLayer(d.info, id, parent) 95 } 96 97 func (d *WindowsGraphDriver) dir(id string) string { 98 return filepath.Join(d.info.HomeDir, filepath.Base(id)) 99 } 100 101 // Remove unmounts and removes the dir information 102 func (d *WindowsGraphDriver) Remove(id string) error { 103 return hcsshim.DestroyLayer(d.info, id) 104 } 105 106 // Get returns the rootfs path for the id. This will mount the dir at it's given path 107 func (d *WindowsGraphDriver) Get(id, mountLabel string) (string, error) { 108 var dir string 109 110 d.Lock() 111 defer d.Unlock() 112 113 if d.active[id] == 0 { 114 if err := hcsshim.ActivateLayer(d.info, id); err != nil { 115 return "", err 116 } 117 } 118 119 mountPath, err := hcsshim.GetLayerMountPath(d.info, id) 120 if err != nil { 121 return "", err 122 } 123 124 // If the layer has a mount path, use that. Otherwise, use the 125 // folder path. 126 if mountPath != "" { 127 dir = mountPath 128 } else { 129 dir = d.dir(id) 130 } 131 132 d.active[id]++ 133 134 return dir, nil 135 } 136 137 func (d *WindowsGraphDriver) Put(id string) error { 138 logrus.Debugf("WindowsGraphDriver Put() id %s", id) 139 140 d.Lock() 141 defer d.Unlock() 142 143 if d.active[id] > 1 { 144 d.active[id]-- 145 } else if d.active[id] == 1 { 146 if err := hcsshim.DeactivateLayer(d.info, id); err != nil { 147 return err 148 } 149 delete(d.active, id) 150 } 151 152 return nil 153 } 154 155 func (d *WindowsGraphDriver) Cleanup() error { 156 return nil 157 } 158 159 // Diff produces an archive of the changes between the specified 160 // layer and its parent layer which may be "". 161 func (d *WindowsGraphDriver) Diff(id, parent string) (arch archive.Archive, err error) { 162 return nil, fmt.Errorf("The Windows graphdriver does not support Diff()") 163 } 164 165 // Changes produces a list of changes between the specified layer 166 // and its parent layer. If parent is "", then all changes will be ADD changes. 167 func (d *WindowsGraphDriver) Changes(id, parent string) ([]archive.Change, error) { 168 return nil, fmt.Errorf("The Windows graphdriver does not support Changes()") 169 } 170 171 // ApplyDiff extracts the changeset from the given diff into the 172 // layer with the specified id and parent, returning the size of the 173 // new layer in bytes. 174 func (d *WindowsGraphDriver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) { 175 start := time.Now().UTC() 176 logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer") 177 178 destination := d.dir(id) 179 if d.info.Flavour == diffDriver { 180 destination = filepath.Dir(destination) 181 } 182 183 if size, err = chrootarchive.ApplyLayer(destination, diff); err != nil { 184 return 185 } 186 logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) 187 188 return 189 } 190 191 // DiffSize calculates the changes between the specified layer 192 // and its parent and returns the size in bytes of the changes 193 // relative to its base filesystem directory. 194 func (d *WindowsGraphDriver) DiffSize(id, parent string) (size int64, err error) { 195 changes, err := d.Changes(id, parent) 196 if err != nil { 197 return 198 } 199 200 layerFs, err := d.Get(id, "") 201 if err != nil { 202 return 203 } 204 defer d.Put(id) 205 206 return archive.ChangesSize(layerFs, changes), nil 207 } 208 209 func (d *WindowsGraphDriver) CopyDiff(sourceId, id string, parentLayerPaths []string) error { 210 d.Lock() 211 defer d.Unlock() 212 213 if d.info.Flavour == filterDriver && d.active[sourceId] == 0 { 214 if err := hcsshim.ActivateLayer(d.info, sourceId); err != nil { 215 return err 216 } 217 defer func() { 218 err := hcsshim.DeactivateLayer(d.info, sourceId) 219 if err != nil { 220 logrus.Warnf("Failed to Deactivate %s: %s", sourceId, err) 221 } 222 }() 223 } 224 225 return hcsshim.CopyLayer(d.info, sourceId, id, parentLayerPaths) 226 } 227 228 func (d *WindowsGraphDriver) LayerIdsToPaths(ids []string) []string { 229 var paths []string 230 for _, id := range ids { 231 path, err := d.Get(id, "") 232 if err != nil { 233 logrus.Debug("LayerIdsToPaths: Error getting mount path for id", id, ":", err.Error()) 234 return nil 235 } 236 if d.Put(id) != nil { 237 logrus.Debug("LayerIdsToPaths: Error putting mount path for id", id, ":", err.Error()) 238 return nil 239 } 240 paths = append(paths, path) 241 } 242 return paths 243 } 244 245 func (d *WindowsGraphDriver) GetMetadata(id string) (map[string]string, error) { 246 return nil, nil 247 } 248 249 func (d *WindowsGraphDriver) Export(id string, parentLayerPaths []string) (arch archive.Archive, err error) { 250 layerFs, err := d.Get(id, "") 251 if err != nil { 252 return 253 } 254 defer func() { 255 if err != nil { 256 d.Put(id) 257 } 258 }() 259 260 tempFolder := layerFs + "-temp" 261 if err = os.MkdirAll(tempFolder, 0755); err != nil { 262 logrus.Errorf("Could not create %s %s", tempFolder, err) 263 return 264 } 265 defer func() { 266 if err != nil { 267 if err2 := os.RemoveAll(tempFolder); err2 != nil { 268 logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) 269 } 270 } 271 }() 272 273 if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { 274 return 275 } 276 277 archive, err := archive.Tar(tempFolder, archive.Uncompressed) 278 if err != nil { 279 return 280 } 281 return ioutils.NewReadCloserWrapper(archive, func() error { 282 err := archive.Close() 283 d.Put(id) 284 if err2 := os.RemoveAll(tempFolder); err2 != nil { 285 logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) 286 } 287 return err 288 }), nil 289 290 } 291 292 func (d *WindowsGraphDriver) Import(id string, layerData archive.ArchiveReader, parentLayerPaths []string) (size int64, err error) { 293 layerFs, err := d.Get(id, "") 294 if err != nil { 295 return 296 } 297 defer func() { 298 if err != nil { 299 d.Put(id) 300 } 301 }() 302 303 tempFolder := layerFs + "-temp" 304 if err = os.MkdirAll(tempFolder, 0755); err != nil { 305 logrus.Errorf("Could not create %s %s", tempFolder, err) 306 return 307 } 308 defer func() { 309 if err2 := os.RemoveAll(tempFolder); err2 != nil { 310 logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) 311 } 312 }() 313 314 start := time.Now().UTC() 315 logrus.Debugf("Start untar layer") 316 if size, err = chrootarchive.ApplyLayer(tempFolder, layerData); err != nil { 317 return 318 } 319 logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) 320 321 if err = hcsshim.ImportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { 322 return 323 } 324 325 return 326 }