github.com/OpenFlowLabs/storage@v1.12.13/drivers/chown.go (about) 1 package graphdriver 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "os" 8 "path/filepath" 9 10 "github.com/containers/storage/pkg/idtools" 11 "github.com/containers/storage/pkg/reexec" 12 ) 13 14 const ( 15 chownByMapsCmd = "storage-chown-by-maps" 16 ) 17 18 func init() { 19 reexec.Register(chownByMapsCmd, chownByMapsMain) 20 } 21 22 func chownByMapsMain() { 23 if len(os.Args) < 2 { 24 fmt.Fprintf(os.Stderr, "requires mapping configuration on stdin and directory path") 25 os.Exit(1) 26 } 27 // Read and decode our configuration. 28 discreteMaps := [4][]idtools.IDMap{} 29 config := bytes.Buffer{} 30 if _, err := config.ReadFrom(os.Stdin); err != nil { 31 fmt.Fprintf(os.Stderr, "error reading configuration: %v", err) 32 os.Exit(1) 33 } 34 if err := json.Unmarshal(config.Bytes(), &discreteMaps); err != nil { 35 fmt.Fprintf(os.Stderr, "error decoding configuration: %v", err) 36 os.Exit(1) 37 } 38 // Try to chroot. This may not be possible, and on some systems that 39 // means we just Chdir() to the directory, so from here on we should be 40 // using relative paths. 41 if err := chrootOrChdir(os.Args[1]); err != nil { 42 fmt.Fprintf(os.Stderr, "error chrooting to %q: %v", os.Args[1], err) 43 os.Exit(1) 44 } 45 // Build the mapping objects. 46 toContainer := idtools.NewIDMappingsFromMaps(discreteMaps[0], discreteMaps[1]) 47 if len(toContainer.UIDs()) == 0 && len(toContainer.GIDs()) == 0 { 48 toContainer = nil 49 } 50 toHost := idtools.NewIDMappingsFromMaps(discreteMaps[2], discreteMaps[3]) 51 if len(toHost.UIDs()) == 0 && len(toHost.GIDs()) == 0 { 52 toHost = nil 53 } 54 chown := func(path string, info os.FileInfo, err error) error { 55 if err != nil { 56 return fmt.Errorf("error walking to %q: %v", path, err) 57 } 58 if path == "." { 59 return nil 60 } 61 return platformLChown(path, info, toHost, toContainer) 62 } 63 if err := filepath.Walk(".", chown); err != nil { 64 fmt.Fprintf(os.Stderr, "error during chown: %v", err) 65 os.Exit(1) 66 } 67 os.Exit(0) 68 } 69 70 // ChownPathByMaps walks the filesystem tree, changing the ownership 71 // information using the toContainer and toHost mappings, using them to replace 72 // on-disk owner UIDs and GIDs which are "host" values in the first map with 73 // UIDs and GIDs for "host" values from the second map which correspond to the 74 // same "container" IDs. 75 func ChownPathByMaps(path string, toContainer, toHost *idtools.IDMappings) error { 76 if toContainer == nil { 77 toContainer = &idtools.IDMappings{} 78 } 79 if toHost == nil { 80 toHost = &idtools.IDMappings{} 81 } 82 83 config, err := json.Marshal([4][]idtools.IDMap{toContainer.UIDs(), toContainer.GIDs(), toHost.UIDs(), toHost.GIDs()}) 84 if err != nil { 85 return err 86 } 87 cmd := reexec.Command(chownByMapsCmd, path) 88 cmd.Stdin = bytes.NewReader(config) 89 output, err := cmd.CombinedOutput() 90 if len(output) > 0 && err != nil { 91 return fmt.Errorf("%v: %s", err, string(output)) 92 } 93 if err != nil { 94 return err 95 } 96 if len(output) > 0 { 97 return fmt.Errorf("%s", string(output)) 98 } 99 100 return nil 101 } 102 103 type naiveLayerIDMapUpdater struct { 104 ProtoDriver 105 } 106 107 // NewNaiveLayerIDMapUpdater wraps the ProtoDriver in a LayerIDMapUpdater that 108 // uses ChownPathByMaps to update the ownerships in a layer's filesystem tree. 109 func NewNaiveLayerIDMapUpdater(driver ProtoDriver) LayerIDMapUpdater { 110 return &naiveLayerIDMapUpdater{ProtoDriver: driver} 111 } 112 113 // UpdateLayerIDMap walks the layer's filesystem tree, changing the ownership 114 // information using the toContainer and toHost mappings, using them to replace 115 // on-disk owner UIDs and GIDs which are "host" values in the first map with 116 // UIDs and GIDs for "host" values from the second map which correspond to the 117 // same "container" IDs. 118 func (n *naiveLayerIDMapUpdater) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error { 119 driver := n.ProtoDriver 120 options := MountOpts{ 121 MountLabel: mountLabel, 122 } 123 layerFs, err := driver.Get(id, options) 124 if err != nil { 125 return err 126 } 127 defer func() { 128 driver.Put(id) 129 }() 130 131 return ChownPathByMaps(layerFs, toContainer, toHost) 132 } 133 134 // SupportsShifting tells whether the driver support shifting of the UIDs/GIDs in an userNS 135 func (n *naiveLayerIDMapUpdater) SupportsShifting() bool { 136 return false 137 }