(root)/
gettext-0.22.4/
gettext-tools/
gnulib-lib/
supersede.h
       1  /* Open a file, without destroying an old file with the same name.
       2  
       3     Copyright (C) 2020-2023 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 <stdio.h>
      24  #include <sys/types.h>
      25  
      26  #ifdef __cplusplus
      27  extern "C" {
      28  #endif
      29  
      30  /* When writing a file, for some usages it is important that at any moment,
      31     a process that opens the file will see consistent data in the file.  This
      32     can be important in two situations:
      33       * If supersede_if_exists == true, then when the file already existed,
      34         it is important that a process that opens the file while the new file's
      35         contents is being written sees consistent data - namely the old file's
      36         data.
      37       * If supersede_if_does_not_exist == true, then when the file did not exist,
      38         it is important that a process that opens the file while the new file's
      39         contents is being written sees no file (as opposed to a file with
      40         truncated contents).
      41  
      42     In both situations, the effect is implemented by creating a temporary file,
      43     writing into that temporary file, and renaming the temporary file when the
      44     temporary file's contents is complete.
      45  
      46     Note that opening a file with superseding may fail when it would succeed
      47     without superseding (for example, for a writable file in an unwritable
      48     directory).  And also the other way around: Opening a file with superseding
      49     may succeed although it would fail without superseding (for example, for
      50     an unwritable file in a writable directory).  */
      51  
      52  /* This type holds everything that needs to needs to be remembered in order to
      53     execute the final rename action.  */
      54  struct supersede_final_action
      55  {
      56    char *final_rename_temp;
      57    char *final_rename_dest;
      58  };
      59  
      60  /* =================== open() and close() with supersede =================== */
      61  
      62  /* The typical code idiom is like this:
      63  
      64       struct supersede_final_action action;
      65       int fd = open_supersede (filename, O_RDWR, mode,
      66                                supersede_if_exists, supersede_if_does_not_exist,
      67                                &action);
      68       if (fd >= 0)
      69         {
      70           ... write the file's contents ...
      71           if (successful)
      72             {
      73               if (close_supersede (fd, &action) < 0)
      74                 error (...);
      75             }
      76           else
      77             {
      78               // Abort the operation.
      79               close (fd);
      80               close_supersede (-1, &action);
      81             }
      82         }
      83    */
      84  
      85  /* Opens a file (typically for writing) in superseding mode, depending on
      86     supersede_if_exists and supersede_if_does_not_exist.
      87     FLAGS should not contain O_CREAT nor O_EXCL.
      88     MODE is used when the file does not yet exist.  The umask of the process
      89     is considered, like in open(), i.e. the effective mode is
      90     (MODE & ~ getumask ()).
      91     Upon success, it fills in ACTION and returns a file descriptor.
      92     Upon failure, it returns -1 and sets errno.  */
      93  extern int open_supersede (const char *filename, int flags, mode_t mode,
      94                             bool supersede_if_exists,
      95                             bool supersede_if_does_not_exist,
      96                             struct supersede_final_action *action);
      97  
      98  /* Closes a file and executes the final rename action.
      99     FD must have been returned by open_supersede(), or -1 if you want to abort
     100     the operation.  */
     101  extern int close_supersede (int fd,
     102                              const struct supersede_final_action *action);
     103  
     104  /* ================== fopen() and fclose() with supersede ================== */
     105  
     106  /* The typical code idiom is like this:
     107  
     108       struct supersede_final_action action;
     109       FILE *stream =
     110         fopen_supersede (filename, O_RDWR, mode,
     111                          supersede_if_exists, supersede_if_does_not_exist,
     112                          &action);
     113       if (stream != NULL)
     114         {
     115           ... write the file's contents ...
     116           if (successful)
     117             {
     118               if (fclose_supersede (stream, &action) < 0)
     119                 error (...);
     120             }
     121           else
     122             {
     123               // Abort the operation.
     124               fclose (stream);
     125               fclose_supersede (NULL, &action);
     126             }
     127         }
     128    */
     129  
     130  /* Opens a file (typically for writing) in superseding mode, depending on
     131     supersede_if_exists and supersede_if_does_not_exist.
     132     Upon success, it fills in ACTION and returns a file stream.
     133     Upon failure, it returns NULL and sets errno.  */
     134  extern FILE *fopen_supersede (const char *filename, const char *mode,
     135                                bool supersede_if_exists,
     136                                bool supersede_if_does_not_exist,
     137                                struct supersede_final_action *action);
     138  
     139  /* Closes a file stream and executes the final rename action.
     140     STREAM must have been returned by fopen_supersede(), or NULL if you want to
     141     abort the operation.  */
     142  extern int fclose_supersede (FILE *stream,
     143                               const struct supersede_final_action *action);
     144  
     145  /* Closes a file stream, like with fwriteerror, and executes the final rename
     146     action.
     147     STREAM must have been returned by fopen_supersede(), or NULL if you want to
     148     abort the operation.  */
     149  extern int fwriteerror_supersede (FILE *stream,
     150                                    const struct supersede_final_action *action);
     151  
     152  #ifdef __cplusplus
     153  }
     154  #endif
     155  
     156  #endif /* _GL_SUPERSEDE_H */