summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1999-04-02 02:55:10 +0000
committerJim Meyering <jim@meyering.net>1999-04-02 02:55:10 +0000
commit35aee6bf137f5c5f7b283d1cd11f960ce2df2264 (patch)
tree0fc7689292127037d69a6b75ddb2ed7d0369de8a /src
parentac03113efebc0b858ea30e71f265aa3b02d0dec8 (diff)
downloadcoreutils-35aee6bf137f5c5f7b283d1cd11f960ce2df2264.tar.xz
(open_maybe_create): New function.
(touch): Rewrite not to use `creat' and to eliminate a race condition that could make touch truncate a nonempty file. Report and suggestions from Andrew Tridgell.
Diffstat (limited to 'src')
-rw-r--r--src/touch.c101
1 files changed, 74 insertions, 27 deletions
diff --git a/src/touch.c b/src/touch.c
index 3b01ab30a..7cf1c1b3f 100644
--- a/src/touch.c
+++ b/src/touch.c
@@ -102,6 +102,43 @@ static int const time_masks[] =
CH_ATIME, CH_ATIME, CH_ATIME, CH_MTIME, CH_MTIME
};
+/* Open FILE, possibly creating it. Set *FILE_CREATED to nonzero if the
+ open creates it, or to zero if the open call opened an existing file.
+ Return the result of the open call. Be careful to avoid race conditions. */
+
+static int
+open_maybe_create (const char *file, int *file_created)
+{
+ int fd;
+
+ *file_created = 0;
+ while (1)
+ {
+ /* First, see if we can create a new FILE. */
+ fd = open (file, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ if (fd != -1)
+ *file_created = 1;
+
+ /* If the open succeeded or if it failed for any reason other
+ than the existence of FILE, then we're done. */
+ if (fd != -1 || errno != EEXIST)
+ break;
+
+ /* The first open failed because FILE already exists.
+ Now try to open it for writing. */
+ fd = open (file, O_WRONLY);
+
+ /* If the open succeeded or if it failed for any reason other
+ than the absence of FILE, then we're done. */
+ /* The 2nd open can fail if FILE was unlinked between the two
+ open calls. When that happens, just iterate. */
+ if (fd != -1 || errno != ENOENT)
+ break;
+ }
+
+ return fd;
+}
+
/* Update the time of file FILE according to the options given.
Return 0 if successful, 1 if an error occurs. */
@@ -111,42 +148,52 @@ touch (const char *file)
int status;
struct stat sbuf;
int fd;
+ int file_created;
- if (stat (file, &sbuf))
+ if (no_create)
{
- if (errno != ENOENT)
- {
- error (0, errno, "%s", file);
- return 1;
- }
- if (no_create)
- return 0;
- fd = creat (file, 0666);
- if (fd == -1)
+ /* Try to open an existing FILE. */
+ fd = open (file, O_WRONLY);
+ if (fd == -1 && errno == ENOENT)
{
- error (0, errno, "%s", file);
- return 1;
- }
- if (amtime_now)
- {
- if (close (fd) < 0)
- {
- error (0, errno, "%s", file);
- return 1;
- }
- return 0; /* We've done all we have to. */
- }
- if (fstat (fd, &sbuf))
- {
- error (0, errno, "%s", file);
- close (fd);
- return 1;
+ /* FILE doesn't exist. So we're done. */
+ return 0;
}
+ file_created = 0;
+ }
+ else
+ {
+ /* Try to open FILE, creating it if necessary. */
+ fd = open_maybe_create (file, &file_created);
+ }
+
+ if (fd == -1)
+ {
+ error (0, errno, "%s", file);
+ return 1;
+ }
+
+ if (file_created && amtime_now)
+ {
if (close (fd) < 0)
{
error (0, errno, "%s", file);
return 1;
}
+ return 0; /* We've done all we have to. */
+ }
+
+ if (fstat (fd, &sbuf))
+ {
+ error (0, errno, "%s", file);
+ close (fd);
+ return 1;
+ }
+
+ if (close (fd) < 0)
+ {
+ error (0, errno, "%s", file);
+ return 1;
}
if (amtime_now)