From f6e36bf361c587e0dbb2f0c71f5d22a7cf7f4f42 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 29 May 2009 11:20:29 +0100 Subject: [PATCH] Fix mkdir-p if directory exists (RHBZ#503133). --- capitests/tests.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++- daemon/dir.c | 11 +++ src/generator.ml | 9 ++- 3 files changed, 224 insertions(+), 2 deletions(-) diff --git a/capitests/tests.c b/capitests/tests.c index 3b29642..959d09b 100644 --- a/capitests/tests.c +++ b/capitests/tests.c @@ -12805,6 +12805,198 @@ static int test_mkdir_p_2 (void) return 0; } +static int test_mkdir_p_3_skip (void) +{ + const char *str; + + str = getenv ("SKIP_TEST_MKDIR_P_3"); + if (str && strcmp (str, "1") == 0) return 1; + str = getenv ("SKIP_TEST_MKDIR_P"); + if (str && strcmp (str, "1") == 0) return 1; + return 0; +} + +static int test_mkdir_p_3 (void) +{ + if (test_mkdir_p_3_skip ()) { + printf ("%s skipped (reason: SKIP_TEST_* variable set)\n", "test_mkdir_p_3"); + return 0; + } + + /* InitBasicFS for test_mkdir_p_3: create ext2 on /dev/sda1 */ + { + char device[] = "/dev/sda"; + device[5] = devchar; + int r; + suppress_error = 0; + r = guestfs_blockdev_setrw (g, device); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda"; + device[5] = devchar; + char lines_0[] = ","; + char *lines[] = { + lines_0, + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, device, 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char fstype[] = "ext2"; + char device[] = "/dev/sda1"; + device[5] = devchar; + int r; + suppress_error = 0; + r = guestfs_mkfs (g, fstype, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + device[5] = devchar; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + /* TestRun for mkdir_p (3) */ + { + char path[] = "/new"; + int r; + suppress_error = 0; + r = guestfs_mkdir (g, path); + if (r == -1) + return -1; + } + { + char path[] = "/new"; + int r; + suppress_error = 0; + r = guestfs_mkdir_p (g, path); + if (r == -1) + return -1; + } + return 0; +} + +static int test_mkdir_p_4_skip (void) +{ + const char *str; + + str = getenv ("SKIP_TEST_MKDIR_P_4"); + if (str && strcmp (str, "1") == 0) return 1; + str = getenv ("SKIP_TEST_MKDIR_P"); + if (str && strcmp (str, "1") == 0) return 1; + return 0; +} + +static int test_mkdir_p_4 (void) +{ + if (test_mkdir_p_4_skip ()) { + printf ("%s skipped (reason: SKIP_TEST_* variable set)\n", "test_mkdir_p_4"); + return 0; + } + + /* InitBasicFS for test_mkdir_p_4: create ext2 on /dev/sda1 */ + { + char device[] = "/dev/sda"; + device[5] = devchar; + int r; + suppress_error = 0; + r = guestfs_blockdev_setrw (g, device); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda"; + device[5] = devchar; + char lines_0[] = ","; + char *lines[] = { + lines_0, + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, device, 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char fstype[] = "ext2"; + char device[] = "/dev/sda1"; + device[5] = devchar; + int r; + suppress_error = 0; + r = guestfs_mkfs (g, fstype, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + device[5] = devchar; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + /* TestLastFail for mkdir_p (4) */ + { + char path[] = "/new"; + int r; + suppress_error = 0; + r = guestfs_touch (g, path); + if (r == -1) + return -1; + } + { + char path[] = "/new"; + int r; + suppress_error = 1; + r = guestfs_mkdir_p (g, path); + if (r != -1) + return -1; + } + return 0; +} + static int test_mkdir_0_skip (void) { const char *str; @@ -15843,7 +16035,7 @@ int main (int argc, char *argv[]) free (devs[i]); free (devs); - nr_tests = 140; + nr_tests = 142; test_num++; printf ("%3d/%3d test_find_0\n", test_num, nr_tests); @@ -16536,6 +16728,18 @@ int main (int argc, char *argv[]) failed++; } test_num++; + printf ("%3d/%3d test_mkdir_p_3\n", test_num, nr_tests); + if (test_mkdir_p_3 () == -1) { + printf ("test_mkdir_p_3 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_mkdir_p_4\n", test_num, nr_tests); + if (test_mkdir_p_4 () == -1) { + printf ("test_mkdir_p_4 FAILED\n"); + failed++; + } + test_num++; printf ("%3d/%3d test_mkdir_0\n", test_num, nr_tests); if (test_mkdir_0 () == -1) { printf ("test_mkdir_0 FAILED\n"); diff --git a/daemon/dir.c b/daemon/dir.c index f706466..3df6233 100644 --- a/daemon/dir.c +++ b/daemon/dir.c @@ -117,10 +117,21 @@ recursive_mkdir (const char *path) int loop = 0; int r; char *ppath, *p; + struct stat buf; again: r = mkdir (path, 0777); if (r == -1) { + if (errno == EEXIST) { /* Something exists here, might not be a dir. */ + r = lstat (path, &buf); + if (r == -1) return -1; + if (!S_ISDIR (buf.st_mode)) { + errno = ENOTDIR; + return -1; + } + return 0; /* OK - directory exists here already. */ + } + if (!loop && errno == ENOENT) { loop = 1; /* Stops it looping forever. */ diff --git a/src/generator.ml b/src/generator.ml index f30d779..9f01904 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -1002,7 +1002,14 @@ Create a directory named C."); ["is_dir"; "/new/foo"]]; InitBasicFS, Always, TestOutputTrue [["mkdir_p"; "/new/foo/bar"]; - ["is_dir"; "/new"]]], + ["is_dir"; "/new"]]; + (* Regression tests for RHBZ#503133: *) + InitBasicFS, Always, TestRun + [["mkdir"; "/new"]; + ["mkdir_p"; "/new"]]; + InitBasicFS, Always, TestLastFail + [["touch"; "/new"]; + ["mkdir_p"; "/new"]]], "create a directory and parents", "\ Create a directory named C, creating any parent directories -- 1.8.3.1