[CRIU] [PATCH v4 5/6] files-reg: Recreate deleted parent directories during restore of ghost file
Kirill Tkhai
ktkhai at virtuozzo.com
Mon Jan 25 08:40:14 PST 2016
This patch makes ghost files to restore with the right path.
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
files-reg.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 92 insertions(+), 5 deletions(-)
diff --git a/files-reg.c b/files-reg.c
index b6c348a..dbe5e37 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -1217,13 +1217,90 @@ static int linkat_hard(int odir, char *opath, int ndir, char *npath, uid_t owner
return ret;
}
+/* Prints parent and returns place where last delimiter was */
+static char *sprintf_parent_dir(char *dst, const char *path)
+{
+ char *p;
+
+ strcpy(dst, path);
+
+ p = strrchr(dst, '/');
+ if (!p) {
+ pr_err("Path %s has no parent dir", path);
+ return NULL;
+ }
+ *p = '\0';
+
+ return p;
+}
+
+static void rm_parent_dirs(int mntns_root, char *path, int count)
+{
+ char pdir[PATH_MAX], *p;
+
+ if (!count || !sprintf_parent_dir(pdir, path))
+ return;
+
+ while (count--) {
+ if (unlinkat(mntns_root, pdir, AT_REMOVEDIR))
+ pr_perror("Can't remove %s AT %d", pdir, mntns_root);
+ else
+ pr_debug("Unlinked parent dir: %s AT %d\n", pdir, mntns_root);
+
+ p = strrchr(pdir, '/');
+ if (p)
+ *p = '\0';
+ }
+}
+
+/* Construct parent dir name and mkdir parent/grandparents if they're not exist */
+static int make_parent_dirs_if_need(int mntns_root, char *path)
+{
+ char pdir[PATH_MAX], *p;
+ int err, count = 0;
+ struct stat st;
+
+ sprintf_parent_dir(pdir, path);
+
+ if (fstatat(mntns_root, pdir, &st, AT_EMPTY_PATH) == 0)
+ return 0;
+ if (errno != ENOENT) {
+ pr_perror("Can't stat %s", pdir);
+ return -1;
+ }
+
+ p = pdir;
+ do {
+ p = strchr(p, '/');
+ if (p)
+ *p = '\0';
+
+ err = mkdirat(mntns_root, pdir, 0777);
+ if (err && errno != EEXIST) {
+ pr_perror("Can't create dir: %s AT %d", pdir, mntns_root);
+ goto cleanup;
+ } else if (!err) {
+ pr_debug("Created parent dir: %s AT %d\n", pdir, mntns_root);
+ count++;
+ }
+
+ if (p)
+ *p++ = '/';
+ } while (p);
+
+ return count;
+cleanup:
+ rm_parent_dirs(mntns_root, pdir, count);
+ return -1;
+}
+
/*
* This routine properly resolves d's path handling ghost/link-remaps.
* The open_cb is a routine that does actual open, it differs for
* files, directories, fifos, etc.
*/
-static int rfi_remap(struct reg_file_info *rfi)
+static int rfi_remap(struct reg_file_info *rfi, int *level)
{
struct mount_info *mi, *rmi, *tmi;
char _path[PATH_MAX], *path = _path;
@@ -1269,14 +1346,23 @@ static int rfi_remap(struct reg_file_info *rfi)
mntns_root = mntns_get_root_fd(tmi->nsid);
out_root:
- return linkat_hard(mntns_root, rpath, mntns_root, path, rfi->remap->owner);
+ *level = make_parent_dirs_if_need(mntns_root, path);
+ if (*level < 0)
+ return -1;
+
+ if (linkat_hard(mntns_root, rpath, mntns_root, path, rfi->remap->owner) < 0) {
+ rm_parent_dirs(mntns_root, path, *level);
+ return -1;
+ }
+
+ return 0;
}
int open_path(struct file_desc *d,
int(*open_cb)(int mntns_root, struct reg_file_info *, void *), void *arg)
{
+ int tmp, mntns_root, level;
struct reg_file_info *rfi;
- int tmp, mntns_root;
char *orig_path = NULL;
if (inherited_fd(d, &tmp))
@@ -1292,7 +1378,7 @@ int open_path(struct file_desc *d,
*/
orig_path = rfi->path;
rfi->path = rfi->remap->rpath;
- } else if (rfi_remap(rfi) < 0) {
+ } else if (rfi_remap(rfi, &level) < 0) {
static char tmp_path[PATH_MAX];
if (errno != EEXIST) {
@@ -1316,7 +1402,7 @@ int open_path(struct file_desc *d,
snprintf(tmp_path, sizeof(tmp_path), "%s.cr_link", orig_path);
pr_debug("Fake %s -> %s link\n", rfi->path, rfi->remap->rpath);
- if (rfi_remap(rfi) < 0) {
+ if (rfi_remap(rfi, &level) < 0) {
pr_perror("Can't create even fake link!");
return -1;
}
@@ -1356,6 +1442,7 @@ int open_path(struct file_desc *d,
if (rfi->remap) {
if (!rfi->remap->is_dir) {
unlinkat(mntns_root, rfi->path, 0);
+ rm_parent_dirs(mntns_root, rfi->path, level);
}
BUG_ON(!rfi->remap->users);
More information about the CRIU
mailing list