summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-09-23 00:19:54 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-09-23 00:19:54 -0700
commit08e99752e3d29f69dd661aaba3b7809a117264d9 (patch)
tree5494c258d64f71e094ac2969bcef3e06bf88eaf6
parent2df419cdb5295b405a98d24f0226cb42bfbf37d2 (diff)
downloadtxr-08e99752e3d29f69dd661aaba3b7809a117264d9.tar.gz
txr-08e99752e3d29f69dd661aaba3b7809a117264d9.tar.bz2
txr-08e99752e3d29f69dd661aaba3b7809a117264d9.zip
New T mode for open-file.
The T mode uses O_TMPFILE to create an unlinkd temporary file. * stream.h (struct stdio_mode): New flag, tmpfile. (stdio_mode_init_blank, stdio_mode_init_r, stdio_mode_init_rpb): Updated to cover new bitfield member. * stream.c (w_open_mode): If tmpfile flag is on, add O_TMPFILE. (do_parse_mode): Recognize "T" mode selector and set all appropriate mode bits. If we are not on a platform that has O_TMPFILE, set the maformed flag. * txr.1: Documented.
-rw-r--r--stream.c13
-rw-r--r--stream.h7
-rw-r--r--txr.154
3 files changed, 70 insertions, 4 deletions
diff --git a/stream.c b/stream.c
index 6e733735..5ea9330f 100644
--- a/stream.c
+++ b/stream.c
@@ -1132,6 +1132,9 @@ int w_open_mode(const wchar_t *wname, const struct stdio_mode m)
if3(m.create, if3(!m.notrunc, O_TRUNC, 0) | O_CREAT, 0) |
if3(m.append, O_APPEND, 0) |
if3(m.excl, O_EXCL, 0) |
+#if O_TMPFILE
+ if3(m.tmpfile, O_TMPFILE, 0) |
+#endif
if3(m.nonblock, O_NONBLOCK, 0));
char *stkname = coerce(char *, alloca(nsiz));
int fd;
@@ -1464,6 +1467,16 @@ static struct stdio_mode do_parse_mode(val mode_str, struct stdio_mode m_dfl,
m.create = 1;
m.notrunc = 1;
break;
+ case 'T':
+ ms++;
+#if O_TMPFILE
+ m.read = 1;
+ m.write = 1;
+ m.tmpfile = 1;
+#else
+ m.malformed = 1;
+#endif
+ break;
default:
break;
}
diff --git a/stream.h b/stream.h
index 1396bb87..6c5b9981 100644
--- a/stream.h
+++ b/stream.h
@@ -118,13 +118,14 @@ struct stdio_mode {
unsigned linebuf : 1;
unsigned gzip : 1;
unsigned gzlevel : 4;
+ unsigned tmpfile : 1;
int buforder : 5;
int redir[STDIO_MODE_NREDIRS][2];
};
-#define stdio_mode_init_blank { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } }
-#define stdio_mode_init_r { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } }
-#define stdio_mode_init_rpb { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } }
+#define stdio_mode_init_blank { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } }
+#define stdio_mode_init_r { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } }
+#define stdio_mode_init_rpb { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } }
#define std_input (deref(lookup_var_l(nil, stdin_s)))
#define std_output (deref(lookup_var_l(nil, stdout_s)))
diff --git a/txr.1 b/txr.1
index 27843e6b..15c7218c 100644
--- a/txr.1
+++ b/txr.1
@@ -61837,7 +61837,7 @@ Note that it permits no whitespace characters:
.mono
.mets < mode-string := [ < mode ] [ < options ]
.mets < mode := { < selector [ + ] | + }
-.mets < selector := { r | w | a | m }
+.mets < selector := { r | w | a | m | T }
.mets < options := { b | x | l | u | i | n | < digit |
.mets \ \ \ \ \ \ \ \ \ \ \ \ \ \ <> z[ digit ] | < redirection }
.mets < digit := { 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 }
@@ -61898,6 +61898,17 @@ are appended.
The file is opened for reading and writing. If it doesn't exist,
it is created. The read position is at the beginning of the file,
but writes are appended to the end regardless of the position.
+.coIP T
+This selector may be used on operating systems which support the
+.code O_TMPFILE
+mode of the
+.code open
+POSIX C library function. The
+.meta path
+must specify a directory to which the calling process has write permission. An
+anonymous, unlinked file will be created in the filesystem which holds that
+directory, open for reading and writing. See additional notes at the
+end of this section.
.RE
.IP
The meanings of the option characters are:
@@ -62001,6 +62012,47 @@ function; the syntax performs I/O redirections in the child process
created by that function, and is described in that function's
documentation.
.RE
+.IP
+The
+.code O_TMPFILE
+flag on which the
+.str T
+mode selector depends was introduced by the Linux kernel, and is likely only
+supported on Linux systems. It is not supported on all filesystem types.
+
+The
+.code T
+mode offers a way to create temporary files in a robust way in any file system
+which supports the mechanism. There is no concern about choosing a unique
+file name, since the file doesn't have one.
+The file is guaranteed to disappear if the process is terminated in any manner.
+In contrast, traditional temporary files which are initially named a name and
+then unlinked may remain if the process is abruptly terminated before it is
+able to call
+.codn unlink .
+
+On Linux, it is possible to link a file created with
+.str T
+into the filesystem, according to the following pattern:
+
+.verb
+ ;; atomically create file called "name" with content "hello"
+
+ (let* ((stream (open-file "." "T"))
+ (fd (fileno stream)))
+ (put-string "hello\en" stream)
+ (flush-stream stream)
+ (rlink `/proc/self/fd/@fd` "name"))
+.brev
+
+The atomic creation of a file can be simulated by the familiar pattern of
+writing to a visible temporary file and then renaming. However, the above
+pattern eliminates the risk that a temporary file will be left behind if the
+procedure is interrupted for any reason before reaching the
+.code rlink
+call. Any reason includes process termination that
+cannot be intercepted and handled, and operating
+system failure or power loss.
.coNP Function @ open-tail
.synb