findprog-in: Relicense under LGPLv2+.
[gnulib.git] / lib / supersede.h
blob111d15b8649d7f06634cb2b0d41db8b3c6e057b7
1 /* Open a file, without destroying an old file with the same name.
3 Copyright (C) 2020 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Bruno Haible, 2020. */
20 #ifndef _GL_SUPERSEDE_H
21 #define _GL_SUPERSEDE_H
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <sys/types.h>
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
31 /* When writing a file, for some usages it is important that at any moment,
32 a process that opens the file will see consistent data in the file. This
33 can be important in two situations:
34 * If supersede_if_exists == true, then when the file already existed,
35 it is important that a process that opens the file while the new file's
36 contents is being written sees consistent data - namely the old file's
37 data.
38 * If supersede_if_does_not_exist == true, then when the file did not exist,
39 it is important that a process that opens the file while the new file's
40 contents is being written sees no file (as opposed to a file with
41 truncated contents).
43 In both situations, the effect is implemented by creating a temporary file,
44 writing into that temporary file, and renaming the temporary file when the
45 temporary file's contents is complete.
47 Note that opening a file with superseding may fail when it would succeed
48 without superseding (for example, for a writable file in an unwritable
49 directory). And also the other way around: Opening a file with superseding
50 may succeed although it would fail without superseding (for example, for
51 an unwritable file in a writable directory). */
53 /* This type holds everything that needs to needs to be remembered in order to
54 execute the final rename action. */
55 struct supersede_final_action
57 char *final_rename_temp;
58 char *final_rename_dest;
61 /* =================== open() and close() with supersede =================== */
63 /* The typical code idiom is like this:
65 struct supersede_final_action action;
66 int fd = open_supersede (filename, O_RDWR, mode,
67 supersede_if_exists, supersede_if_does_not_exist,
68 &action);
69 if (fd >= 0)
71 ... write the file's contents ...
72 if (successful)
74 if (close_supersede (fd, &action) < 0)
75 error (...);
77 else
79 // Abort the operation.
80 close (fd);
81 close_supersede (-1, &action);
86 /* Opens a file (typically for writing) in superseding mode, depending on
87 supersede_if_exists and supersede_if_does_not_exist.
88 FLAGS should not contain O_CREAT nor O_EXCL.
89 MODE is used when the file does not yet exist. The umask of the process
90 is considered, like in open(), i.e. the effective mode is
91 (MODE & ~ getumask ()).
92 Upon success, it fills in ACTION and returns a file descriptor.
93 Upon failure, it returns -1 and sets errno. */
94 extern int open_supersede (const char *filename, int flags, mode_t mode,
95 bool supersede_if_exists,
96 bool supersede_if_does_not_exist,
97 struct supersede_final_action *action);
99 /* Closes a file and executes the final rename action.
100 FD must have been returned by open_supersede(), or -1 if you want to abort
101 the operation. */
102 extern int close_supersede (int fd,
103 const struct supersede_final_action *action);
105 /* ================== fopen() and fclose() with supersede ================== */
107 /* The typical code idiom is like this:
109 struct supersede_final_action action;
110 FILE *stream =
111 fopen_supersede (filename, O_RDWR, mode,
112 supersede_if_exists, supersede_if_does_not_exist,
113 &action);
114 if (stream != NULL)
116 ... write the file's contents ...
117 if (successful)
119 if (fclose_supersede (stream, &action) < 0)
120 error (...);
122 else
124 // Abort the operation.
125 fclose (stream);
126 fclose_supersede (NULL, &action);
131 /* Opens a file (typically for writing) in superseding mode, depending on
132 supersede_if_exists and supersede_if_does_not_exist.
133 Upon success, it fills in ACTION and returns a file stream.
134 Upon failure, it returns NULL and sets errno. */
135 extern FILE *fopen_supersede (const char *filename, const char *mode,
136 bool supersede_if_exists,
137 bool supersede_if_does_not_exist,
138 struct supersede_final_action *action);
140 /* Closes a file stream and executes the final rename action.
141 STREAM must have been returned by fopen_supersede(), or NULL if you want to
142 abort the operation. */
143 extern int fclose_supersede (FILE *stream,
144 const struct supersede_final_action *action);
146 /* Closes a file stream, like with fwriteerror, and executes the final rename
147 action.
148 STREAM must have been returned by fopen_supersede(), or NULL if you want to
149 abort the operation. */
150 extern int fwriteerror_supersede (FILE *stream,
151 const struct supersede_final_action *action);
153 #ifdef __cplusplus
155 #endif
157 #endif /* _GL_SUPERSEDE_H */