@@ -1378,6 +1378,19 @@ func (r *layerStore) pickStoreLocation(volatile, writeable bool) layerLocations
13781378 }
13791379}
13801380
1381+ func checkIdAndNameConflict (r * layerStore , id string , names []string ) error {
1382+ if _ , idInUse := r .byid [id ]; idInUse {
1383+ return ErrDuplicateID
1384+ }
1385+ names = dedupeStrings (names )
1386+ for _ , name := range names {
1387+ if _ , nameInUse := r .byname [name ]; nameInUse {
1388+ return ErrDuplicateName
1389+ }
1390+ }
1391+ return nil
1392+ }
1393+
13811394// Requires startWriting.
13821395func (r * layerStore ) create (id string , parentLayer * Layer , names []string , mountLabel string , options map [string ]string , moreOptions * LayerOptions , writeable bool , diff io.Reader , slo * stagedLayerOptions ) (layer * Layer , size int64 , err error ) {
13831396 if moreOptions == nil {
@@ -1400,14 +1413,9 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
14001413 _ , idInUse = r .byid [id ]
14011414 }
14021415 }
1403- if duplicateLayer , idInUse := r .byid [id ]; idInUse {
1404- return duplicateLayer , - 1 , ErrDuplicateID
1405- }
14061416 names = dedupeStrings (names )
1407- for _ , name := range names {
1408- if _ , nameInUse := r .byname [name ]; nameInUse {
1409- return nil , - 1 , ErrDuplicateName
1410- }
1417+ if err := checkIdAndNameConflict (r , id , names ); err != nil {
1418+ return nil , - 1 , err
14111419 }
14121420 parent := ""
14131421 if parentLayer != nil {
@@ -1448,9 +1456,6 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
14481456 selinux .ReserveLabel (mountLabel )
14491457 }
14501458
1451- // Before actually creating the layer, make a persistent record of it
1452- // with the incomplete flag set, so that future processes have a chance
1453- // to clean up after it.
14541459 layer = & Layer {
14551460 ID : id ,
14561461 Parent : parent ,
@@ -1474,6 +1479,45 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
14741479 }
14751480 layer .Flags [incompleteFlag ] = true
14761481
1482+ var (
1483+ cleanupFunctions []tempdir.CleanupTempDirFunc
1484+ applyDiffFunc func () error
1485+ applyDiffSize int64
1486+ )
1487+
1488+ applyDiffTemporaryDriver , ok := r .driver .(drivers.ApplyDiffStaging )
1489+ if ok && diff != nil {
1490+ // CRITICAL, this releases the lock so we can extract this unlocked
1491+ r .stopWriting ()
1492+
1493+ var applyDiffError error
1494+ cleanupFunctions , applyDiffFunc , applyDiffSize , applyDiffError = r .applyDiffUnlocked (applyDiffTemporaryDriver , layer , moreOptions , diff )
1495+ // We must try to cleanup regardless of if an error was returned or not.
1496+ defer func () {
1497+ if err := tempdir .CleanupTemporaryDirectories (cleanupFunctions ... ); err != nil {
1498+ logrus .Errorf ("Error cleaning up temporary directories: %v" , err )
1499+ }
1500+ }()
1501+ // Acquire the lock again, this releases the lock so we can extract this unlocked.
1502+ // This must be done before checking for the error from applyDiffUnlocked() so the caller doesn't try to unlock again.
1503+ // FIXME: if startWriting() fails we return unlocked and then the parent unlocks again causing a panic. We should try to avoid that case somehow.
1504+ if err := r .startWriting (); err != nil {
1505+ return nil , - 1 , fmt .Errorf ("re-acquire lock after applying layer diff: %w" , err )
1506+ }
1507+ if applyDiffError != nil {
1508+ return nil , - 1 , applyDiffError
1509+ }
1510+
1511+ if err := checkIdAndNameConflict (r , id , names ); err != nil {
1512+ logrus .Debugf ("Layer id %s or name from %v was created while staging the layer content unlocked, aborting layer creation" , id , names )
1513+ return nil , - 1 , err
1514+ }
1515+ }
1516+
1517+ // Before actually creating the layer, make a persistent record of it
1518+ // with the incomplete flag set, so that future processes have a chance
1519+ // to clean up after it.
1520+
14771521 r .layers = append (r .layers , layer )
14781522 // This can only fail if the ID is already missing, which shouldn’t
14791523 // happen — and in that case the index is already in the desired state
@@ -1568,7 +1612,13 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
15681612 }
15691613
15701614 size = - 1
1571- if diff != nil {
1615+ if applyDiffFunc != nil {
1616+ size = applyDiffSize
1617+ if err := applyDiffFunc (); err != nil {
1618+ cleanupFailureContext = "applying staged diff"
1619+ return nil , - 1 , err
1620+ }
1621+ } else if diff != nil {
15721622 if size , err = r .applyDiffWithOptions (layer , moreOptions , diff ); err != nil {
15731623 cleanupFailureContext = "applying layer diff"
15741624 return nil , - 1 , err
@@ -2404,6 +2454,66 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
24042454
24052455type diffApplyFunc func (id string , parent string , options drivers.ApplyDiffOpts , tsBytes * bytes.Buffer ) error
24062456
2457+ func (r * layerStore ) applyDiffUnlocked (dd drivers.ApplyDiffStaging , layer * Layer , layerOptions * LayerOptions , diff io.Reader ) ([]tempdir.CleanupTempDirFunc , func () error , int64 , error ) {
2458+ var (
2459+ size int64
2460+ cleanFunctions []tempdir.CleanupTempDirFunc
2461+ applyDiff func () error
2462+ )
2463+
2464+ f := func (id string , parent string , options drivers.ApplyDiffOpts , tsBytes * bytes.Buffer ) error {
2465+ var (
2466+ err error
2467+ cleanup tempdir.CleanupTempDirFunc
2468+ commit tempdir.CommitFunc
2469+ )
2470+ cleanup , commit , size , err = dd .StartStagingDiffToApply (layer .ID , layer .Parent , options )
2471+ cleanFunctions = append (cleanFunctions , cleanup )
2472+ if err != nil {
2473+ return err
2474+ }
2475+
2476+ td , err := tempdir .NewTempDir (filepath .Join (r .layerdir , tempDirPath ))
2477+ cleanFunctions = append (cleanFunctions , td .Cleanup )
2478+ if err != nil {
2479+ return err
2480+ }
2481+
2482+ sa , err := td .StageFileAddition (func (path string ) error {
2483+ return os .WriteFile (path , tsBytes .Bytes (), 0o600 )
2484+ })
2485+ cleanFunctions = append (cleanFunctions , td .Cleanup )
2486+ if err != nil {
2487+ return err
2488+ }
2489+
2490+ applyDiff = func () error {
2491+ err := dd .CommitStagedLayer (layer .ID , commit )
2492+ if err != nil {
2493+ return fmt .Errorf ("commit temporary layer: %w" , err )
2494+ }
2495+
2496+ if err := os .MkdirAll (filepath .Dir (r .tspath (layer .ID )), 0o700 ); err != nil {
2497+ return err
2498+ }
2499+
2500+ err = sa .Commit (r .tspath (layer .ID ))
2501+ if err != nil {
2502+ return fmt .Errorf ("commit tar split file: %w" , err )
2503+ }
2504+ return nil
2505+ }
2506+ return nil
2507+ }
2508+
2509+ err := r .applyDiffWithOptionsInner (layer , layerOptions , diff , f )
2510+ if err != nil {
2511+ return cleanFunctions , nil , 0 , err
2512+ }
2513+
2514+ return cleanFunctions , applyDiff , size , nil
2515+ }
2516+
24072517// Requires startWriting.
24082518func (r * layerStore ) applyDiffWithOptions (layer * Layer , layerOptions * LayerOptions , diff io.Reader ) (int64 , error ) {
24092519 var size int64
@@ -2422,7 +2532,12 @@ func (r *layerStore) applyDiffWithOptions(layer *Layer, layerOptions *LayerOptio
24222532 return nil
24232533 }
24242534
2425- return size , r .applyDiffWithOptionsInner (layer , layerOptions , diff , f )
2535+ err := r .applyDiffWithOptionsInner (layer , layerOptions , diff , f )
2536+ if err != nil {
2537+ return 0 , err
2538+ }
2539+
2540+ return size , r .saveFor (layer )
24262541}
24272542
24282543func (r * layerStore ) applyDiffWithOptionsInner (layer * Layer , layerOptions * LayerOptions , diff io.Reader , applyFunc diffApplyFunc ) (err error ) {
@@ -2545,9 +2660,7 @@ func (r *layerStore) applyDiffWithOptionsInner(layer *Layer, layerOptions *Layer
25452660 }
25462661 slices .Sort (layer .GIDs )
25472662
2548- err = r .saveFor (layer )
2549-
2550- return err
2663+ return nil
25512664}
25522665
25532666// Requires (startReading or?) startWriting.
0 commit comments