@@ -48,8 +48,7 @@ import (
4848var untar = chrootarchive .UntarUncompressed
4949
5050const (
51- defaultPerms = os .FileMode (0o555 )
52- mountProgramFlagFile = ".has-mount-program"
51+ defaultPerms = os .FileMode (0o555 )
5352)
5453
5554// This backend uses the overlay union filesystem for containers
@@ -79,24 +78,32 @@ const (
7978// syscall. A hard upper limit of 500 lower layers is enforced to ensure
8079// that mounts do not fail due to length.
8180
82- const (
83- linkDir = "l"
84- stagingDir = "staging"
85- tempDirName = "tempdirs"
86- lowerFile = "lower"
81+ const ( // Paths within the driver’s home directory
82+ mountProgramFlagFile = ".has-mount-program"
83+ linkDir = "l"
84+ stagingDir = "staging"
85+ tempDirName = "tempdirs"
86+ )
87+
88+ const ( // Paths within a per-layer directory
89+ lowerFile = "lower"
8790 // lowerLayersFile references lower layers directly by layer ID
8891 // instead of going through the l/ symlinks. The code appends
8992 // "/diff" itself when consuming entries. It is preferred over
9093 // lowerFile when present. The old lowerFile is still written
9194 // for backward compatibility with older tools.
9295 lowerLayersFile = "lower-layers"
93- maxDepth = 500
94-
95- stagingLockFile = "staging.lock"
96+ )
9697
98+ const ( // Keys within DriverWithDifferOutput.Artifacts
9799 tocArtifact = "toc"
98100 fsVerityDigestsArtifact = "fs-verity-digests"
101+ )
102+
103+ const stagingLockFile = "staging.lock"
99104
105+ const (
106+ maxDepth = 500
100107 // idLength represents the number of random characters
101108 // which can be used to create the unique link identifier
102109 // for every layer. If this value is too long then the
@@ -1145,42 +1152,22 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl
11451152 return idtools .MkdirAndChown (path .Join (dir , "empty" ), 0o700 , forcedSt .IDs )
11461153 }
11471154
1148- lower , err := d .getLower (parent )
1155+ lower , err := d .getLowerForParent (parent )
11491156 if err != nil {
11501157 return err
11511158 }
1152- if lower != "" {
1153- if err := os .WriteFile (path .Join (dir , lowerFile ), []byte (lower ), 0o666 ); err != nil {
1154- return err
1155- }
1159+ if err := os .WriteFile (path .Join (dir , lowerFile ), []byte (lower ), 0o666 ); err != nil {
1160+ return err
11561161 }
11571162
11581163 // Write a lower-layers file referencing layers by ID instead of
11591164 // l/ symlink references. The reading side appends "/diff" itself.
1160- parentDir := d .dir (parent )
1161- layerLower := parent
1162- parentLower , err := os .ReadFile (path .Join (parentDir , lowerLayersFile ))
1163- if err == nil {
1164- layerLower += ":" + string (parentLower )
1165- } else if ! errors .Is (err , unix .ENOENT ) {
1165+ parentLowerLayerIDs , err := d .getLowerLayerIDs (parent )
1166+ if err != nil {
11661167 return err
1167- } else {
1168- // Parent has no lower-layers file. Convert old-format lower
1169- // entries (l/ symlinks) to layer IDs.
1170- oldLower , err := os .ReadFile (path .Join (parentDir , lowerFile ))
1171- if err == nil {
1172- for _ , s := range strings .Split (string (oldLower ), ":" ) {
1173- target , err := os .Readlink (d .dir (s ))
1174- if err != nil {
1175- return fmt .Errorf ("reading symlink for lower %q: %w" , s , err )
1176- }
1177- layerLower += ":" + filepath .Base (filepath .Dir (target ))
1178- }
1179- } else if ! errors .Is (err , unix .ENOENT ) {
1180- return err
1181- }
11821168 }
1183- if err := os .WriteFile (path .Join (dir , lowerLayersFile ), []byte (layerLower ), 0o666 ); err != nil {
1169+ layerLowerLayerIDs := strings .Join (append ([]string {parent }, parentLowerLayerIDs ... ), ":" )
1170+ if err := os .WriteFile (path .Join (dir , lowerLayersFile ), []byte (layerLowerLayerIDs ), 0o666 ); err != nil {
11841171 return err
11851172 }
11861173
@@ -1231,28 +1218,6 @@ func (d *Driver) parseStorageOpt(opts *graphdriver.CreateOpts, readOnly bool) (q
12311218 return res , nil
12321219}
12331220
1234- func (d * Driver ) getLower (parent string ) (string , error ) {
1235- parentDir := d .dir (parent )
1236-
1237- // Ensure parent exists
1238- if err := fileutils .Lexists (parentDir ); err != nil {
1239- return "" , err
1240- }
1241-
1242- parentLink , err := os .ReadFile (path .Join (parentDir , "link" ))
1243- if err != nil {
1244- return "" , err
1245- }
1246- lowers := []string {path .Join (linkDir , string (parentLink ))}
1247-
1248- parentLower , err := os .ReadFile (path .Join (parentDir , lowerFile ))
1249- if err == nil {
1250- parentLowers := strings .SplitSeq (string (parentLower ), ":" )
1251- lowers = slices .AppendSeq (lowers , parentLowers )
1252- }
1253- return strings .Join (lowers , ":" ), nil
1254- }
1255-
12561221func (d * Driver ) dir (id string ) string {
12571222 p , _ , _ := d .dir2 (id , false )
12581223 return p
@@ -1294,36 +1259,98 @@ func (d *Driver) dir2(id string, useImageStore bool) (string, string, bool) {
12941259 return newpath , homedir , false
12951260}
12961261
1297- func (d * Driver ) getLowerDirs (id string ) ([]string , error ) {
1298- var lowersArray []string
1299- dir := d .dir (id )
1300- lowers , err := os .ReadFile (path .Join (dir , lowerLayersFile ))
1262+ // getLowerForParent returns the contents of lowerFile for a child layer of parent.
1263+ //
1264+ // This should only be used to construct a lowerFile for compatibility;
1265+ // new code should rely on lowerLayersFile instead.
1266+ func (d * Driver ) getLowerForParent (parent string ) (string , error ) {
1267+ parentDir := d .dir (parent )
1268+
1269+ // Ensure parent exists
1270+ if err := fileutils .Lexists (parentDir ); err != nil {
1271+ return "" , err
1272+ }
1273+
1274+ parentLink , err := os .ReadFile (path .Join (parentDir , "link" ))
13011275 if err != nil {
1302- if ! errors .Is (err , unix .ENOENT ) {
1303- return nil , err
1304- }
1305- lowers , err = os .ReadFile (path .Join (dir , lowerFile ))
1276+ return "" , err
13061277 }
1278+ lowers := []string {path .Join (linkDir , string (parentLink ))}
1279+
1280+ parentLower , err := os .ReadFile (path .Join (parentDir , lowerFile ))
13071281 if err == nil {
1308- for s := range strings .SplitSeq (string (lowers ), ":" ) {
1309- lower := d .dir (s )
1310- lp , err := os .Readlink (lower )
1282+ parentLowers := strings .SplitSeq (string (parentLower ), ":" )
1283+ lowers = slices .AppendSeq (lowers , parentLowers )
1284+ }
1285+ return strings .Join (lowers , ":" ), nil
1286+ }
1287+
1288+ // getLowerLayerIDs returns a list of lower layer IDs for a layer id;
1289+ // typically the contents of lowerLayersFile, falling back to lowerFile.
1290+ // If the layer has neither of the files, returns an empty list without reporting an error.
1291+ func (d * Driver ) getLowerLayerIDs (id string ) ([]string , error ) {
1292+ dir := d .dir (id )
1293+ lowerLayers , err := os .ReadFile (path .Join (dir , lowerLayersFile ))
1294+ switch {
1295+ case err == nil :
1296+ return strings .Split (string (lowerLayers ), ":" ), nil
1297+
1298+ case errors .Is (err , fs .ErrNotExist ):
1299+ lowers , err := os .ReadFile (path .Join (dir , lowerFile ))
1300+ if err != nil {
1301+ if errors .Is (err , fs .ErrNotExist ) {
1302+ return nil , nil
1303+ }
1304+ return nil , err
1305+ }
1306+ var res []string
1307+ for relLowerLink := range strings .SplitSeq (string (lowers ), ":" ) {
1308+ lowerLink := d .dir (relLowerLink ) // This is an invalid use of dir() (the input is supposed to be a layer ID) but pre-existing
1309+ lp , err := os .Readlink (lowerLink )
13111310 if err != nil {
1312- if errors .Is (err , syscall .EINVAL ) {
1313- // Not a symlink: layer ID, append /diff.
1314- lowersArray = append (lowersArray , path .Join (lower , "diff" ))
1315- continue
1316- }
13171311 return nil , err
13181312 }
1319- lowersArray = append (lowersArray , path .Clean (d .dir (path .Join ("link" , lp ))))
1313+ lowerID := filepath .Base (filepath .Dir (lp ))
1314+ res = append (res , lowerID )
13201315 }
1321- } else if ! errors .Is (err , fs .ErrNotExist ) {
1316+ return res , nil
1317+
1318+ default :
13221319 return nil , err
13231320 }
1321+ }
1322+
1323+ // getLowerDirs returns a list of lower directories for a layer id;
1324+ // the directories may be symbolic links (do not call redirectDiffIfAdditionalLayer).
1325+ func (d * Driver ) getLowerDirs (id string ) ([]string , error ) {
1326+ lowerLayerIDs , err := d .getLowerLayerIDs (id )
1327+ if err != nil {
1328+ return nil , err
1329+ }
1330+ lowersArray := make ([]string , 0 , len (lowerLayerIDs ))
1331+ for _ , lowerID := range lowerLayerIDs {
1332+ lowerDir := d .dir (lowerID )
1333+ lowersArray = append (lowersArray , path .Join (lowerDir , "diff" ))
1334+ }
13241335 return lowersArray , nil
13251336}
13261337
1338+ // getLowerDiffPaths returns a list of lower diff paths for a layer id;
1339+ // the paths have redirectDiffIfAdditionalLayer applied.
1340+ func (d * Driver ) getLowerDiffPaths (id string ) ([]string , error ) {
1341+ layers , err := d .getLowerDirs (id )
1342+ if err != nil {
1343+ return nil , err
1344+ }
1345+ for i , l := range layers {
1346+ layers [i ], err = redirectDiffIfAdditionalLayer (l , false )
1347+ if err != nil {
1348+ return nil , err
1349+ }
1350+ }
1351+ return layers , nil
1352+ }
1353+
13271354func (d * Driver ) optsAppendMappings (opts string , uidMaps , gidMaps []idtools.IDMap ) string {
13281355 if uidMaps != nil {
13291356 var uids , gids bytes.Buffer
@@ -1520,18 +1547,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
15201547 readWrite = false
15211548 }
15221549
1523- lowers , err := os . ReadFile ( path . Join ( dir , lowerLayersFile ) )
1550+ lowerLayerIDs , err := d . getLowerLayerIDs ( id )
15241551 if err != nil {
1525- if ! errors .Is (err , unix .ENOENT ) {
1526- return "" , err
1527- }
1528- lowers , err = os .ReadFile (path .Join (dir , lowerFile ))
1529- if err != nil && ! os .IsNotExist (err ) {
1530- return "" , err
1531- }
1552+ return "" , err
15321553 }
1533- splitLowers := strings .Split (string (lowers ), ":" )
1534- if len (splitLowers ) > maxDepth {
1554+ if len (lowerLayerIDs ) > maxDepth {
15351555 return "" , errors .New ("max depth exceeded" )
15361556 }
15371557
@@ -1621,46 +1641,17 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
16211641
16221642 // For each lower, resolve its path, and append it and any additional diffN
16231643 // directories to the lowers list.
1624- for i , l := range splitLowers {
1625- if l == "" {
1626- continue
1644+ for i , lowerID := range lowerLayerIDs {
1645+ lower := filepath .Join (d .dir (lowerID ), "diff" )
1646+ st , err := os .Stat (lower )
1647+ if err != nil {
1648+ return "" , fmt .Errorf ("can't stat (or find?) lower layer %q: %w" , lower , err )
16271649 }
1628-
1629- lower := ""
1630- newpath := path .Join (d .home , l )
1631- if st , err := os .Stat (newpath ); err != nil {
1632- for _ , p := range d .getAllImageStores () {
1633- lower = path .Join (p , d .name , l )
1634- if st2 , err2 := os .Stat (lower ); err2 == nil {
1635- if ! permsKnown {
1636- perms = st2 .Mode ()
1637- permsKnown = true
1638- }
1639- break
1640- }
1641- lower = ""
1642- }
1643- if lower == "" {
1644- return "" , fmt .Errorf ("can't stat lower layer %q: %w" , newpath , err )
1645- }
1646- } else {
1647- if ! permsKnown {
1648- perms = st .Mode ()
1649- permsKnown = true
1650- }
1651- lower = newpath
1650+ if ! permsKnown {
1651+ perms = st .Mode ()
1652+ permsKnown = true
16521653 }
16531654
1654- linkContent , err := os .Readlink (lower )
1655- if err != nil {
1656- if ! errors .Is (err , syscall .EINVAL ) {
1657- return "" , err
1658- }
1659- // Not a symlink: layer ID from lower-layers, append /diff.
1660- lower = path .Join (lower , "diff" )
1661- linkContent = lower
1662- }
1663- lowerID := filepath .Base (filepath .Dir (linkContent ))
16641655 composefsMount , err := maybeAddComposefsMount (lowerID , i + 1 , readWrite )
16651656 if err != nil {
16661657 return "" , err
@@ -2030,23 +2021,15 @@ func (d *Driver) ListLayers() ([]string, error) {
20302021
20312022// isParent returns if the passed in parent is the direct parent of the passed in layer
20322023func (d * Driver ) isParent (id , parent string ) bool {
2033- lowers , err := d .getLowerDirs (id )
2024+ lowerLayerIDs , err := d .getLowerLayerIDs (id )
20342025 if err != nil {
20352026 return false
20362027 }
2037- if parent == "" && len (lowers ) > 0 {
2038- return false
2039- }
2040-
2041- parentDir := d .dir (parent )
2042- var ld string
2043- if len (lowers ) > 0 {
2044- ld = filepath .Dir (lowers [0 ])
2045- }
2046- if ld == "" && parent == "" {
2047- return true
2028+ actualParent := ""
2029+ if len (lowerLayerIDs ) > 0 {
2030+ actualParent = lowerLayerIDs [0 ]
20482031 }
2049- return ld == parentDir
2032+ return parent == actualParent
20502033}
20512034
20522035func (d * Driver ) getWhiteoutFormat () archive.WhiteoutFormat {
@@ -2430,20 +2413,6 @@ func (d *Driver) getDiffPath(id string) (string, error) {
24302413 return redirectDiffIfAdditionalLayer (path .Join (dir , "diff" ), false )
24312414}
24322415
2433- func (d * Driver ) getLowerDiffPaths (id string ) ([]string , error ) {
2434- layers , err := d .getLowerDirs (id )
2435- if err != nil {
2436- return nil , err
2437- }
2438- for i , l := range layers {
2439- layers [i ], err = redirectDiffIfAdditionalLayer (l , false )
2440- if err != nil {
2441- return nil , err
2442- }
2443- }
2444- return layers , nil
2445- }
2446-
24472416// DiffSize calculates the changes between the specified id
24482417// and its parent and returns the size in bytes of the changes
24492418// relative to its base filesystem directory.
0 commit comments