GNU bug report logs - #55937
[PATCH] touch: create parent directories if needed

Previous Next

Package: coreutils;

Reported by: Alan Rosenthal <alan.rosenthal <at> gmail.com>

Date: Mon, 13 Jun 2022 04:33:01 UTC

Severity: normal

Tags: patch

To reply to this bug, email your comments to 55937 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-coreutils <at> gnu.org:
bug#55937; Package coreutils. (Mon, 13 Jun 2022 04:33:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to Alan Rosenthal <alan.rosenthal <at> gmail.com>:
New bug report received and forwarded. Copy sent to bug-coreutils <at> gnu.org. (Mon, 13 Jun 2022 04:33:01 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Alan Rosenthal <alan.rosenthal <at> gmail.com>
To: bug-coreutils <at> gnu.org
Subject: [PATCH] touch: create parent directories if needed
Date: Sun, 12 Jun 2022 22:05:40 -0400
[Message part 1 (text/plain, inline)]
`touch a/b/c/d/e` will now be the same as running `mkdir -p a/b/c/d &&
touch a/b/c/d/e`.
Added an option --no-create-dirs to not create any directories.
---
 src/touch.c | 39 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/src/touch.c b/src/touch.c
index 21c247d0b..9034e8797 100644
--- a/src/touch.c
+++ b/src/touch.c
@@ -28,10 +28,12 @@
 #include "die.h"
 #include "error.h"
 #include "fd-reopen.h"
+#include "mkancesdirs.h"
 #include "parse-datetime.h"
 #include "posixtm.h"
 #include "posixver.h"
 #include "quote.h"
+#include "savewd.h"
 #include "stat-time.h"
 #include "utimens.h"

@@ -55,6 +57,9 @@ static int change_times;
 /* (-c) If true, don't create if not already there.  */
 static bool no_create;

+/* (-c) If true, don't create directories if not already there.  */
+static bool no_create_dirs;
+
 /* (-r) If true, use times from a reference file.  */
 static bool use_ref;

@@ -88,6 +93,7 @@ static struct option const longopts[] =
   {"date", required_argument, NULL, 'd'},
   {"reference", required_argument, NULL, 'r'},
   {"no-dereference", no_argument, NULL, 'h'},
+  {"no_create_dirs", no_argument, NULL, 'i'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -116,6 +122,14 @@ get_reldate (struct timespec *result,
     die (EXIT_FAILURE, 0, _("invalid date format %s"), quote (flex_date));
 }

+/* Create directory, called by mkancesdirs(). */
+
+static int
+make_dir(char const * file, char const * component, void * arg)
+{
+  return mkdir(component, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+}
+
 /* Update the time of file FILE according to the options given.
    Return true if successful.  */

@@ -130,6 +144,25 @@ touch (char const *file)
     fd = STDOUT_FILENO;
   else if (! (no_create || no_dereference))
     {
+      if (! no_create_dirs)
+        {
+          struct savewd wd;
+          savewd_init(&wd);
+          ptrdiff_t ret = mkancesdirs((char*) file, &wd, make_dir, NULL);
+          if (ret == -1)
+            {
+              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
+              return false;
+            }
+          int r = savewd_restore(&wd, 0);
+          if (r < 0)
+            {
+              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
+              return false;
+            }
+          savewd_finish(&wd);
+        }
+
       /* Try to open FILE, creating it if necessary.  */
       fd = fd_reopen (STDIN_FILENO, file,
                       O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
MODE_RW_UGO);
@@ -276,7 +309,7 @@ main (int argc, char **argv)
   change_times = 0;
   no_create = use_ref = false;

-  while ((c = getopt_long (argc, argv, "acd:fhmr:t:", longopts, NULL)) !=
-1)
+  while ((c = getopt_long (argc, argv, "acd:fhimr:t:", longopts, NULL)) !=
-1)
     {
       switch (c)
         {
@@ -299,6 +332,10 @@ main (int argc, char **argv)
           no_dereference = true;
           break;

+        case 'i':
+          no_create_dirs = true;
+          break;
+
         case 'm':
           change_times |= CH_MTIME;
           break;
-- 
2.20.1
[Message part 2 (text/html, inline)]

Information forwarded to bug-coreutils <at> gnu.org:
bug#55937; Package coreutils. (Mon, 13 Jun 2022 11:54:01 GMT) Full text and rfc822 format available.

Message #8 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Alan Rosenthal <alan.rosenthal <at> gmail.com>
To: bug-coreutils <at> gnu.org
Subject: Re: [PATCH] touch: create parent directories if needed
Date: Mon, 13 Jun 2022 07:52:47 -0400
[Message part 1 (text/plain, inline)]
`touch a/b/c/d/e` will now be the same as running `mkdir -p a/b/c/d &&
touch a/b/c/d/e`.
Added an option --no-create-dirs to not create any directories.
---
 src/touch.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/src/touch.c b/src/touch.c
index 21c247d0b..557530f79 100644
--- a/src/touch.c
+++ b/src/touch.c
@@ -28,10 +28,12 @@
 #include "die.h"
 #include "error.h"
 #include "fd-reopen.h"
+#include "mkancesdirs.h"
 #include "parse-datetime.h"
 #include "posixtm.h"
 #include "posixver.h"
 #include "quote.h"
+#include "savewd.h"
 #include "stat-time.h"
 #include "utimens.h"

@@ -55,6 +57,9 @@ static int change_times;
 /* (-c) If true, don't create if not already there.  */
 static bool no_create;

+/* (-c) If true, don't create directories if not already there.  */
+static bool no_create_dirs;
+
 /* (-r) If true, use times from a reference file.  */
 static bool use_ref;

@@ -88,6 +93,7 @@ static struct option const longopts[] =
   {"date", required_argument, NULL, 'd'},
   {"reference", required_argument, NULL, 'r'},
   {"no-dereference", no_argument, NULL, 'h'},
+  {"no-create-dirs", no_argument, NULL, 'i'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -116,6 +122,14 @@ get_reldate (struct timespec *result,
     die (EXIT_FAILURE, 0, _("invalid date format %s"), quote (flex_date));
 }

+/* Create directory, called by mkancesdirs(). */
+
+static int
+make_dir(char const * file, char const * component, void * arg)
+{
+  return mkdir(component, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+}
+
 /* Update the time of file FILE according to the options given.
    Return true if successful.  */

@@ -130,6 +144,25 @@ touch (char const *file)
     fd = STDOUT_FILENO;
   else if (! (no_create || no_dereference))
     {
+      if (! no_create_dirs)
+        {
+          struct savewd wd;
+          savewd_init(&wd);
+          ptrdiff_t ret = mkancesdirs((char*) file, &wd, make_dir, NULL);
+          if (ret == -1)
+            {
+              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
+              return false;
+            }
+          int r = savewd_restore(&wd, 0);
+          if (r < 0)
+            {
+              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
+              return false;
+            }
+          savewd_finish(&wd);
+        }
+
       /* Try to open FILE, creating it if necessary.  */
       fd = fd_reopen (STDIN_FILENO, file,
                       O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
MODE_RW_UGO);
@@ -234,6 +267,7 @@ change the times of the file associated with standard
output.\n\
   -f                     (ignored)\n\
 "), stdout);
       fputs (_("\
+  -i, --no-create-dirs   do not create any required parent directories\n\
   -h, --no-dereference   affect each symbolic link instead of any
referenced\n\
                          file (useful only on systems that can change
the\n\
                          timestamps of a symlink)\n\
@@ -276,7 +310,7 @@ main (int argc, char **argv)
   change_times = 0;
   no_create = use_ref = false;

-  while ((c = getopt_long (argc, argv, "acd:fhmr:t:", longopts, NULL)) !=
-1)
+  while ((c = getopt_long (argc, argv, "acd:fhimr:t:", longopts, NULL)) !=
-1)
     {
       switch (c)
         {
@@ -299,6 +333,10 @@ main (int argc, char **argv)
           no_dereference = true;
           break;

+        case 'i':
+          no_create_dirs = true;
+          break;
+
         case 'm':
           change_times |= CH_MTIME;
           break;
-- 
2.20.1

On Sun, Jun 12, 2022 at 10:05 PM Alan Rosenthal <alan.rosenthal <at> gmail.com>
wrote:

> `touch a/b/c/d/e` will now be the same as running `mkdir -p a/b/c/d &&
> touch a/b/c/d/e`.
> Added an option --no-create-dirs to not create any directories.
> ---
>  src/touch.c | 39 ++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 38 insertions(+), 1 deletion(-)
>
> diff --git a/src/touch.c b/src/touch.c
> index 21c247d0b..9034e8797 100644
> --- a/src/touch.c
> +++ b/src/touch.c
> @@ -28,10 +28,12 @@
>  #include "die.h"
>  #include "error.h"
>  #include "fd-reopen.h"
> +#include "mkancesdirs.h"
>  #include "parse-datetime.h"
>  #include "posixtm.h"
>  #include "posixver.h"
>  #include "quote.h"
> +#include "savewd.h"
>  #include "stat-time.h"
>  #include "utimens.h"
>
> @@ -55,6 +57,9 @@ static int change_times;
>  /* (-c) If true, don't create if not already there.  */
>  static bool no_create;
>
> +/* (-c) If true, don't create directories if not already there.  */
> +static bool no_create_dirs;
> +
>  /* (-r) If true, use times from a reference file.  */
>  static bool use_ref;
>
> @@ -88,6 +93,7 @@ static struct option const longopts[] =
>    {"date", required_argument, NULL, 'd'},
>    {"reference", required_argument, NULL, 'r'},
>    {"no-dereference", no_argument, NULL, 'h'},
> +  {"no_create_dirs", no_argument, NULL, 'i'},
>    {GETOPT_HELP_OPTION_DECL},
>    {GETOPT_VERSION_OPTION_DECL},
>    {NULL, 0, NULL, 0}
> @@ -116,6 +122,14 @@ get_reldate (struct timespec *result,
>      die (EXIT_FAILURE, 0, _("invalid date format %s"), quote (flex_date));
>  }
>
> +/* Create directory, called by mkancesdirs(). */
> +
> +static int
> +make_dir(char const * file, char const * component, void * arg)
> +{
> +  return mkdir(component, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH |
> S_IXOTH);
> +}
> +
>  /* Update the time of file FILE according to the options given.
>     Return true if successful.  */
>
> @@ -130,6 +144,25 @@ touch (char const *file)
>      fd = STDOUT_FILENO;
>    else if (! (no_create || no_dereference))
>      {
> +      if (! no_create_dirs)
> +        {
> +          struct savewd wd;
> +          savewd_init(&wd);
> +          ptrdiff_t ret = mkancesdirs((char*) file, &wd, make_dir, NULL);
> +          if (ret == -1)
> +            {
> +              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
> +              return false;
> +            }
> +          int r = savewd_restore(&wd, 0);
> +          if (r < 0)
> +            {
> +              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
> +              return false;
> +            }
> +          savewd_finish(&wd);
> +        }
> +
>        /* Try to open FILE, creating it if necessary.  */
>        fd = fd_reopen (STDIN_FILENO, file,
>                        O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
> MODE_RW_UGO);
> @@ -276,7 +309,7 @@ main (int argc, char **argv)
>    change_times = 0;
>    no_create = use_ref = false;
>
> -  while ((c = getopt_long (argc, argv, "acd:fhmr:t:", longopts, NULL)) !=
> -1)
> +  while ((c = getopt_long (argc, argv, "acd:fhimr:t:", longopts, NULL))
> != -1)
>      {
>        switch (c)
>          {
> @@ -299,6 +332,10 @@ main (int argc, char **argv)
>            no_dereference = true;
>            break;
>
> +        case 'i':
> +          no_create_dirs = true;
> +          break;
> +
>          case 'm':
>            change_times |= CH_MTIME;
>            break;
> --
> 2.20.1
>
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-coreutils <at> gnu.org:
bug#55937; Package coreutils. (Mon, 13 Jun 2022 14:20:01 GMT) Full text and rfc822 format available.

Message #11 received at 55937 <at> debbugs.gnu.org (full text, mbox):

From: David Hilton <david.hilton.p <at> gmail.com>
To: 55937 <at> debbugs.gnu.org
Subject: RE: bug#55937: [PATCH] touch: create parent directories if needed
Date: Mon, 13 Jun 2022 06:55:31 -0600
[Message part 1 (text/plain, inline)]
I don't like this as the default behavior. If this feature is added, it
should be optional, and enabled with -p, like mkdir.

David
[Message part 2 (text/html, inline)]

Information forwarded to bug-coreutils <at> gnu.org:
bug#55937; Package coreutils. (Wed, 15 Jun 2022 00:22:01 GMT) Full text and rfc822 format available.

Message #14 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Alan Rosenthal <alan.rosenthal <at> gmail.com>
To: bug-coreutils <at> gnu.org
Subject: Re: [PATCH] touch: create parent directories if needed
Date: Tue, 14 Jun 2022 20:20:40 -0400
[Message part 1 (text/plain, inline)]
`touch -p a/b/c/d/e` will now be the same as running:
`mkdir -p a/b/c/d && touch a/b/c/d/e`.

Added an option -p/--create-dirs to create any required directories.
Default behavior remains the same.
---
 src/touch.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/src/touch.c b/src/touch.c
index 21c247d0b..543f92b41 100644
--- a/src/touch.c
+++ b/src/touch.c
@@ -28,10 +28,12 @@
 #include "die.h"
 #include "error.h"
 #include "fd-reopen.h"
+#include "mkancesdirs.h"
 #include "parse-datetime.h"
 #include "posixtm.h"
 #include "posixver.h"
 #include "quote.h"
+#include "savewd.h"
 #include "stat-time.h"
 #include "utimens.h"

@@ -55,6 +57,9 @@ static int change_times;
 /* (-c) If true, don't create if not already there.  */
 static bool no_create;

+/* (-p) If true, create directories if not already there.  */
+static bool create_dirs;
+
 /* (-r) If true, use times from a reference file.  */
 static bool use_ref;

@@ -88,6 +93,7 @@ static struct option const longopts[] =
   {"date", required_argument, NULL, 'd'},
   {"reference", required_argument, NULL, 'r'},
   {"no-dereference", no_argument, NULL, 'h'},
+  {"create-dirs", no_argument, NULL, 'p'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -116,6 +122,14 @@ get_reldate (struct timespec *result,
     die (EXIT_FAILURE, 0, _("invalid date format %s"), quote (flex_date));
 }

+/* Create directory, called by mkancesdirs(). */
+
+static int
+make_dir(char const * file, char const * component, void * arg)
+{
+  return mkdir(component, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+}
+
 /* Update the time of file FILE according to the options given.
    Return true if successful.  */

@@ -130,6 +144,25 @@ touch (char const *file)
     fd = STDOUT_FILENO;
   else if (! (no_create || no_dereference))
     {
+      if (create_dirs)
+        {
+          struct savewd wd;
+          savewd_init(&wd);
+          ptrdiff_t ret = mkancesdirs((char*) file, &wd, make_dir, NULL);
+          if (ret == -1)
+            {
+              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
+              return false;
+            }
+          int r = savewd_restore(&wd, 0);
+          if (r < 0)
+            {
+              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
+              return false;
+            }
+          savewd_finish(&wd);
+        }
+
       /* Try to open FILE, creating it if necessary.  */
       fd = fd_reopen (STDIN_FILENO, file,
                       O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
MODE_RW_UGO);
@@ -240,6 +273,7 @@ change the times of the file associated with standard
output.\n\
   -m                     change only the modification time\n\
 "), stdout);
       fputs (_("\
+  -p, --create-dirs      create any required parent directories\n\
   -r, --reference=FILE   use this file's times instead of current time\n\
   -t STAMP               use [[CC]YY]MMDDhhmm[.ss] instead of current
time\n\
       --time=WORD        change the specified time:\n\
@@ -276,7 +310,7 @@ main (int argc, char **argv)
   change_times = 0;
   no_create = use_ref = false;

-  while ((c = getopt_long (argc, argv, "acd:fhmr:t:", longopts, NULL)) !=
-1)
+  while ((c = getopt_long (argc, argv, "acd:fhmpr:t:", longopts, NULL)) !=
-1)
     {
       switch (c)
         {
@@ -303,6 +337,10 @@ main (int argc, char **argv)
           change_times |= CH_MTIME;
           break;

+        case 'p':
+          create_dirs = true;
+          break;
+
         case 'r':
           use_ref = true;
           ref_file = optarg;
-- 
2.20.1


On Mon, Jun 13, 2022 at 7:52 AM Alan Rosenthal <alan.rosenthal <at> gmail.com>
wrote:

> `touch a/b/c/d/e` will now be the same as running `mkdir -p a/b/c/d &&
> touch a/b/c/d/e`.
> Added an option --no-create-dirs to not create any directories.
> ---
>  src/touch.c | 40 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 39 insertions(+), 1 deletion(-)
>
> diff --git a/src/touch.c b/src/touch.c
> index 21c247d0b..557530f79 100644
> --- a/src/touch.c
> +++ b/src/touch.c
> @@ -28,10 +28,12 @@
>  #include "die.h"
>  #include "error.h"
>  #include "fd-reopen.h"
> +#include "mkancesdirs.h"
>  #include "parse-datetime.h"
>  #include "posixtm.h"
>  #include "posixver.h"
>  #include "quote.h"
> +#include "savewd.h"
>  #include "stat-time.h"
>  #include "utimens.h"
>
> @@ -55,6 +57,9 @@ static int change_times;
>  /* (-c) If true, don't create if not already there.  */
>  static bool no_create;
>
> +/* (-c) If true, don't create directories if not already there.  */
> +static bool no_create_dirs;
> +
>  /* (-r) If true, use times from a reference file.  */
>  static bool use_ref;
>
> @@ -88,6 +93,7 @@ static struct option const longopts[] =
>    {"date", required_argument, NULL, 'd'},
>    {"reference", required_argument, NULL, 'r'},
>    {"no-dereference", no_argument, NULL, 'h'},
> +  {"no-create-dirs", no_argument, NULL, 'i'},
>    {GETOPT_HELP_OPTION_DECL},
>    {GETOPT_VERSION_OPTION_DECL},
>    {NULL, 0, NULL, 0}
> @@ -116,6 +122,14 @@ get_reldate (struct timespec *result,
>      die (EXIT_FAILURE, 0, _("invalid date format %s"), quote (flex_date));
>  }
>
> +/* Create directory, called by mkancesdirs(). */
> +
> +static int
> +make_dir(char const * file, char const * component, void * arg)
> +{
> +  return mkdir(component, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH |
> S_IXOTH);
> +}
> +
>  /* Update the time of file FILE according to the options given.
>     Return true if successful.  */
>
> @@ -130,6 +144,25 @@ touch (char const *file)
>      fd = STDOUT_FILENO;
>    else if (! (no_create || no_dereference))
>      {
> +      if (! no_create_dirs)
> +        {
> +          struct savewd wd;
> +          savewd_init(&wd);
> +          ptrdiff_t ret = mkancesdirs((char*) file, &wd, make_dir, NULL);
> +          if (ret == -1)
> +            {
> +              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
> +              return false;
> +            }
> +          int r = savewd_restore(&wd, 0);
> +          if (r < 0)
> +            {
> +              error (0, open_errno, _("cannot mkdir %s"), quoteaf (file));
> +              return false;
> +            }
> +          savewd_finish(&wd);
> +        }
> +
>        /* Try to open FILE, creating it if necessary.  */
>        fd = fd_reopen (STDIN_FILENO, file,
>                        O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
> MODE_RW_UGO);
> @@ -234,6 +267,7 @@ change the times of the file associated with standard
> output.\n\
>    -f                     (ignored)\n\
>  "), stdout);
>        fputs (_("\
> +  -i, --no-create-dirs   do not create any required parent directories\n\
>    -h, --no-dereference   affect each symbolic link instead of any
> referenced\n\
>                           file (useful only on systems that can change
> the\n\
>                           timestamps of a symlink)\n\
> @@ -276,7 +310,7 @@ main (int argc, char **argv)
>    change_times = 0;
>    no_create = use_ref = false;
>
> -  while ((c = getopt_long (argc, argv, "acd:fhmr:t:", longopts, NULL)) !=
> -1)
> +  while ((c = getopt_long (argc, argv, "acd:fhimr:t:", longopts, NULL))
> != -1)
>      {
>        switch (c)
>          {
> @@ -299,6 +333,10 @@ main (int argc, char **argv)
>            no_dereference = true;
>            break;
>
> +        case 'i':
> +          no_create_dirs = true;
> +          break;
> +
>          case 'm':
>            change_times |= CH_MTIME;
>            break;
> --
> 2.20.1
>
> On Sun, Jun 12, 2022 at 10:05 PM Alan Rosenthal <alan.rosenthal <at> gmail.com>
> wrote:
>
>> `touch a/b/c/d/e` will now be the same as running `mkdir -p a/b/c/d &&
>> touch a/b/c/d/e`.
>> Added an option --no-create-dirs to not create any directories.
>> ---
>>  src/touch.c | 39 ++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 38 insertions(+), 1 deletion(-)
>>
>> diff --git a/src/touch.c b/src/touch.c
>> index 21c247d0b..9034e8797 100644
>> --- a/src/touch.c
>> +++ b/src/touch.c
>> @@ -28,10 +28,12 @@
>>  #include "die.h"
>>  #include "error.h"
>>  #include "fd-reopen.h"
>> +#include "mkancesdirs.h"
>>  #include "parse-datetime.h"
>>  #include "posixtm.h"
>>  #include "posixver.h"
>>  #include "quote.h"
>> +#include "savewd.h"
>>  #include "stat-time.h"
>>  #include "utimens.h"
>>
>> @@ -55,6 +57,9 @@ static int change_times;
>>  /* (-c) If true, don't create if not already there.  */
>>  static bool no_create;
>>
>> +/* (-c) If true, don't create directories if not already there.  */
>> +static bool no_create_dirs;
>> +
>>  /* (-r) If true, use times from a reference file.  */
>>  static bool use_ref;
>>
>> @@ -88,6 +93,7 @@ static struct option const longopts[] =
>>    {"date", required_argument, NULL, 'd'},
>>    {"reference", required_argument, NULL, 'r'},
>>    {"no-dereference", no_argument, NULL, 'h'},
>> +  {"no_create_dirs", no_argument, NULL, 'i'},
>>    {GETOPT_HELP_OPTION_DECL},
>>    {GETOPT_VERSION_OPTION_DECL},
>>    {NULL, 0, NULL, 0}
>> @@ -116,6 +122,14 @@ get_reldate (struct timespec *result,
>>      die (EXIT_FAILURE, 0, _("invalid date format %s"), quote
>> (flex_date));
>>  }
>>
>> +/* Create directory, called by mkancesdirs(). */
>> +
>> +static int
>> +make_dir(char const * file, char const * component, void * arg)
>> +{
>> +  return mkdir(component, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH |
>> S_IXOTH);
>> +}
>> +
>>  /* Update the time of file FILE according to the options given.
>>     Return true if successful.  */
>>
>> @@ -130,6 +144,25 @@ touch (char const *file)
>>      fd = STDOUT_FILENO;
>>    else if (! (no_create || no_dereference))
>>      {
>> +      if (! no_create_dirs)
>> +        {
>> +          struct savewd wd;
>> +          savewd_init(&wd);
>> +          ptrdiff_t ret = mkancesdirs((char*) file, &wd, make_dir, NULL);
>> +          if (ret == -1)
>> +            {
>> +              error (0, open_errno, _("cannot mkdir %s"), quoteaf
>> (file));
>> +              return false;
>> +            }
>> +          int r = savewd_restore(&wd, 0);
>> +          if (r < 0)
>> +            {
>> +              error (0, open_errno, _("cannot mkdir %s"), quoteaf
>> (file));
>> +              return false;
>> +            }
>> +          savewd_finish(&wd);
>> +        }
>> +
>>        /* Try to open FILE, creating it if necessary.  */
>>        fd = fd_reopen (STDIN_FILENO, file,
>>                        O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
>> MODE_RW_UGO);
>> @@ -276,7 +309,7 @@ main (int argc, char **argv)
>>    change_times = 0;
>>    no_create = use_ref = false;
>>
>> -  while ((c = getopt_long (argc, argv, "acd:fhmr:t:", longopts, NULL))
>> != -1)
>> +  while ((c = getopt_long (argc, argv, "acd:fhimr:t:", longopts, NULL))
>> != -1)
>>      {
>>        switch (c)
>>          {
>> @@ -299,6 +332,10 @@ main (int argc, char **argv)
>>            no_dereference = true;
>>            break;
>>
>> +        case 'i':
>> +          no_create_dirs = true;
>> +          break;
>> +
>>          case 'm':
>>            change_times |= CH_MTIME;
>>            break;
>> --
>> 2.20.1
>>
>>
[Message part 2 (text/html, inline)]

Information forwarded to bug-coreutils <at> gnu.org:
bug#55937; Package coreutils. (Wed, 15 Jun 2022 02:38:01 GMT) Full text and rfc822 format available.

Message #17 received at 55937 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Alan Rosenthal <alan.rosenthal <at> gmail.com>
Cc: 55937 <at> debbugs.gnu.org
Subject: Re: bug#55937: [PATCH] touch: create parent directories if needed
Date: Tue, 14 Jun 2022 21:37:36 -0500
On 6/14/22 19:20, Alan Rosenthal wrote:
> `touch -p a/b/c/d/e` will now be the same as running:
> `mkdir -p a/b/c/d && touch a/b/c/d/e`.

I don't see how this useful enough to merit a change, since one can 
achieve the effect of the proposed "touch -p" with the already-existing 
"mkdir -p" followed by plain "touch". mkdir -p already exists and should 
work everywhere that's POSIX-compatible. We don't need -p for other 
commands that create files (e.g., cp, mv, ln); what's special about 'touch'?





Information forwarded to bug-coreutils <at> gnu.org:
bug#55937; Package coreutils. (Wed, 15 Jun 2022 20:33:02 GMT) Full text and rfc822 format available.

Message #20 received at 55937 <at> debbugs.gnu.org (full text, mbox):

From: Alan Rosenthal <alan.rosenthal <at> gmail.com>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: 55937 <at> debbugs.gnu.org
Subject: Re: bug#55937: [PATCH] touch: create parent directories if needed
Date: Wed, 15 Jun 2022 16:31:47 -0400
[Message part 1 (text/plain, inline)]
Thanks for taking the time to review my patch.

I agree with you that this change is not strictly required. It's more of a
nice to have / ergonomic improvement to the existing touch interface.

There are several StackOverflow posts that ask for this very feature:
https://unix.stackexchange.com/q/63098 &
https://unix.stackexchange.com/q/305844

Below is the help text for touch:
> Update the access and modification times of each FILE to the current time.
> A FILE argument that does not exist is created empty, unless -c or -h is
supplied.

I was surprised to learn there was no existing flag that would allow
directory creation when a file and its directories do not exist. Currently
if directories do not exist, the command fails. I would go as far to argue
that creating a file also implies creating any required directories, since
directories must exist before we can create said file.

I also agree with David Hilton's recommendation that we should not change
the default behavior of touch, like in my first patch, but rather add an
opt-in flag for this behavior.

Thank you for reading my reply and I look forward to your future feedback.

On Tue, Jun 14, 2022 at 10:37 PM Paul Eggert <eggert <at> cs.ucla.edu> wrote:

> On 6/14/22 19:20, Alan Rosenthal wrote:
> > `touch -p a/b/c/d/e` will now be the same as running:
> > `mkdir -p a/b/c/d && touch a/b/c/d/e`.
>
> I don't see how this useful enough to merit a change, since one can
> achieve the effect of the proposed "touch -p" with the already-existing
> "mkdir -p" followed by plain "touch". mkdir -p already exists and should
> work everywhere that's POSIX-compatible. We don't need -p for other
> commands that create files (e.g., cp, mv, ln); what's special about
> 'touch'?
>
>
[Message part 2 (text/html, inline)]

This bug report was last modified 3 years and 8 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.