root/maint/gnulib/lib/supersede.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


   1 /* Open a file, without destroying an old file with the same name.
   2 
   3    Copyright (C) 2020-2021 Free Software Foundation, Inc.
   4 
   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.
   9 
  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.
  14 
  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/>.  */
  17 
  18 /* Written by Bruno Haible, 2020.  */
  19 
  20 #ifndef _GL_SUPERSEDE_H
  21 #define _GL_SUPERSEDE_H
  22 
  23 #include <stdbool.h>
  24 #include <stdio.h>
  25 #include <sys/types.h>
  26 
  27 #ifdef __cplusplus
  28 extern "C" {
  29 #endif
  30 
  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).
  42 
  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.
  46 
  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).  */
  52 
  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
  56 {
  57   char *final_rename_temp;
  58   char *final_rename_dest;
  59 };
  60 
  61 /* =================== open() and close() with supersede =================== */
  62 
  63 /* The typical code idiom is like this:
  64 
  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)
  70        {
  71          ... write the file's contents ...
  72          if (successful)
  73            {
  74              if (close_supersede (fd, &action) < 0)
  75                error (...);
  76            }
  77          else
  78            {
  79              // Abort the operation.
  80              close (fd);
  81              close_supersede (-1, &action);
  82            }
  83        }
  84   */
  85 
  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);
  98 
  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);
 104 
 105 /* ================== fopen() and fclose() with supersede ================== */
 106 
 107 /* The typical code idiom is like this:
 108 
 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)
 115        {
 116          ... write the file's contents ...
 117          if (successful)
 118            {
 119              if (fclose_supersede (stream, &action) < 0)
 120                error (...);
 121            }
 122          else
 123            {
 124              // Abort the operation.
 125              fclose (stream);
 126              fclose_supersede (NULL, &action);
 127            }
 128        }
 129   */
 130 
 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);
 139 
 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);
 145 
 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);
 152 
 153 #ifdef __cplusplus
 154 }
 155 #endif
 156 
 157 #endif /* _GL_SUPERSEDE_H */

/* [previous][next][first][last][top][bottom][index][help] */