summaryrefslogtreecommitdiff
path: root/libpod/container_internal_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/container_internal_linux.go')
-rw-r--r--libpod/container_internal_linux.go98
1 files changed, 85 insertions, 13 deletions
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 1b0570998..6ec06943f 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -593,22 +593,68 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) (err error)
// Get root file-system changes included in the checkpoint archive
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
+ deleteFilesList := filepath.Join(c.bundlePath(), "deleted.files")
if !ignoreRootfs {
- rootfsDiffFile, err := os.Create(rootfsDiffPath)
- if err != nil {
- return errors.Wrapf(err, "error creating root file-system diff file %q", rootfsDiffPath)
- }
- tarStream, err := c.runtime.GetDiffTarStream("", c.ID())
+ // To correctly track deleted files, let's go through the output of 'podman diff'
+ tarFiles, err := c.runtime.GetDiff("", c.ID())
if err != nil {
return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath)
}
- _, err = io.Copy(rootfsDiffFile, tarStream)
- if err != nil {
- return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath)
+ var rootfsIncludeFiles []string
+ var deletedFiles []string
+
+ for _, file := range tarFiles {
+ if file.Kind == archive.ChangeAdd {
+ rootfsIncludeFiles = append(rootfsIncludeFiles, file.Path)
+ continue
+ }
+ if file.Kind == archive.ChangeDelete {
+ deletedFiles = append(deletedFiles, file.Path)
+ continue
+ }
+ fileName, err := os.Stat(file.Path)
+ if err != nil {
+ continue
+ }
+ if !fileName.IsDir() && file.Kind == archive.ChangeModify {
+ rootfsIncludeFiles = append(rootfsIncludeFiles, file.Path)
+ continue
+ }
+ }
+
+ if len(rootfsIncludeFiles) > 0 {
+ rootfsTar, err := archive.TarWithOptions(c.state.Mountpoint, &archive.TarOptions{
+ Compression: archive.Uncompressed,
+ IncludeSourceDir: true,
+ IncludeFiles: rootfsIncludeFiles,
+ })
+ if err != nil {
+ return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath)
+ }
+ rootfsDiffFile, err := os.Create(rootfsDiffPath)
+ if err != nil {
+ return errors.Wrapf(err, "error creating root file-system diff file %q", rootfsDiffPath)
+ }
+ defer rootfsDiffFile.Close()
+ _, err = io.Copy(rootfsDiffFile, rootfsTar)
+ if err != nil {
+ return err
+ }
+
+ includeFiles = append(includeFiles, "rootfs-diff.tar")
+ }
+
+ if len(deletedFiles) > 0 {
+ formatJSON, err := json.MarshalIndent(deletedFiles, "", " ")
+ if err != nil {
+ return errors.Wrapf(err, "error creating delete files list file %q", deleteFilesList)
+ }
+ if err := ioutil.WriteFile(deleteFilesList, formatJSON, 0600); err != nil {
+ return errors.Wrapf(err, "error creating delete files list file %q", deleteFilesList)
+ }
+
+ includeFiles = append(includeFiles, "deleted.files")
}
- tarStream.Close()
- rootfsDiffFile.Close()
- includeFiles = append(includeFiles, "rootfs-diff.tar")
}
input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{
@@ -637,6 +683,7 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) (err error)
}
os.Remove(rootfsDiffPath)
+ os.Remove(deleteFilesList)
return nil
}
@@ -941,10 +988,35 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if err != nil {
return errors.Wrapf(err, "Failed to open root file-system diff file %s", rootfsDiffPath)
}
+ defer rootfsDiffFile.Close()
if err := c.runtime.ApplyDiffTarStream(c.ID(), rootfsDiffFile); err != nil {
return errors.Wrapf(err, "Failed to apply root file-system diff file %s", rootfsDiffPath)
}
- rootfsDiffFile.Close()
+ }
+ deletedFilesPath := filepath.Join(c.bundlePath(), "deleted.files")
+ if _, err := os.Stat(deletedFilesPath); err == nil {
+ deletedFilesFile, err := os.Open(deletedFilesPath)
+ if err != nil {
+ return errors.Wrapf(err, "Failed to open deleted files file %s", deletedFilesPath)
+ }
+ defer deletedFilesFile.Close()
+
+ var deletedFiles []string
+ deletedFilesJSON, err := ioutil.ReadAll(deletedFilesFile)
+ if err != nil {
+ return errors.Wrapf(err, "Failed to read deleted files file %s", deletedFilesPath)
+ }
+ if err := json.Unmarshal(deletedFilesJSON, &deletedFiles); err != nil {
+ return errors.Wrapf(err, "Failed to read deleted files file %s", deletedFilesPath)
+ }
+ for _, deleteFile := range deletedFiles {
+ // Using RemoveAll as deletedFiles, which is generated from 'podman diff'
+ // lists completely deleted directories as a single entry: 'D /root'.
+ err = os.RemoveAll(filepath.Join(c.state.Mountpoint, deleteFile))
+ if err != nil {
+ return errors.Wrapf(err, "Failed to delete file %s from container %s during restore", deletedFilesPath, c.ID())
+ }
+ }
}
}
@@ -965,7 +1037,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if err != nil {
logrus.Debugf("Non-fatal: removal of checkpoint directory (%s) failed: %v", c.CheckpointPath(), err)
}
- cleanup := [...]string{"restore.log", "dump.log", "stats-dump", "stats-restore", "network.status", "rootfs-diff.tar"}
+ cleanup := [...]string{"restore.log", "dump.log", "stats-dump", "stats-restore", "network.status", "rootfs-diff.tar", "deleted.files"}
for _, del := range cleanup {
file := filepath.Join(c.bundlePath(), del)
err = os.Remove(file)