(root)/
tar-1.35/
gnu/
backupfile.c
       1  /* backupfile.c -- make Emacs style backup file names
       2  
       3     Copyright (C) 1990-2006, 2009-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 Paul Eggert and David MacKenzie.
      19     Some algorithms adapted from GNU Emacs.  */
      20  
      21  #include <config.h>
      22  
      23  #include "backup-internal.h"
      24  
      25  #include <dirent.h>
      26  #include <errno.h>
      27  #include <fcntl.h>
      28  #include <stdckdint.h>
      29  #include <stdint.h>
      30  #include <stdlib.h>
      31  #include <string.h>
      32  #include <unistd.h>
      33  
      34  #include "attribute.h"
      35  #include "basename-lgpl.h"
      36  #include "ialloc.h"
      37  #include "opendirat.h"
      38  #include "renameatu.h"
      39  
      40  #ifndef _D_EXACT_NAMLEN
      41  # define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name)
      42  #endif
      43  
      44  #if ! (HAVE_PATHCONF && defined _PC_NAME_MAX)
      45  # define pathconf(file, option) (errno = -1)
      46  # define fpathconf(fd, option) (errno = -1)
      47  #endif
      48  
      49  #ifndef _POSIX_NAME_MAX
      50  # define _POSIX_NAME_MAX 14
      51  #endif
      52  
      53  #if defined _XOPEN_NAME_MAX
      54  # define NAME_MAX_MINIMUM _XOPEN_NAME_MAX
      55  #else
      56  # define NAME_MAX_MINIMUM _POSIX_NAME_MAX
      57  #endif
      58  
      59  #ifndef HAVE_DOS_FILE_NAMES
      60  # define HAVE_DOS_FILE_NAMES 0
      61  #endif
      62  #ifndef HAVE_LONG_FILE_NAMES
      63  # define HAVE_LONG_FILE_NAMES 0
      64  #endif
      65  
      66  /* ISDIGIT differs from isdigit, as follows:
      67     - Its arg may be any int or unsigned int; it need not be an unsigned char
      68       or EOF.
      69     - It's typically faster.
      70     POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
      71     ISDIGIT unless it's important to use the locale's definition
      72     of "digit" even when the host does not conform to POSIX.  */
      73  #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
      74  
      75  /* The extension added to file names to produce a simple (as opposed
      76     to numbered) backup file name. */
      77  char const *simple_backup_suffix = NULL;
      78  
      79  /* Set SIMPLE_BACKUP_SUFFIX to S, or to a default specified by the
      80     environment if S is null.  If S or the environment does not specify
      81     a valid backup suffix, use "~".  */
      82  void
      83  set_simple_backup_suffix (char const *s)
      84  {
      85    if (!s)
      86      s = getenv ("SIMPLE_BACKUP_SUFFIX");
      87    simple_backup_suffix = s && *s && s == last_component (s) ? s : "~";
      88  }
      89  
      90  /* If FILE (which was of length FILELEN before an extension was
      91     appended to it) is too long, replace the extension with the single
      92     char E.  If the result is still too long, remove the char just
      93     before E.  Return true if the extension was OK already, false
      94     if it needed replacement.
      95  
      96     If DIR_FD is nonnegative, it is a file descriptor for FILE's parent.
      97     *BASE_MAX is either 0, or the cached result of a previous call for
      98     FILE's parent's _PC_NAME_MAX.  */
      99  
     100  static bool
     101  check_extension (char *file, idx_t filelen, char e,
     102                   int dir_fd, idx_t *base_max)
     103  {
     104    char *base = last_component (file);
     105    idx_t baselen = base_len (base);
     106    idx_t baselen_max = HAVE_LONG_FILE_NAMES ? 255 : NAME_MAX_MINIMUM;
     107  
     108    if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
     109      {
     110        /* The new base name is long enough to require a pathconf check.  */
     111        if (*base_max == 0)
     112          {
     113            long name_max;
     114            if (dir_fd < 0)
     115              {
     116                /* Temporarily modify the buffer into its parent
     117                   directory name, invoke pathconf on the directory, and
     118                   then restore the buffer.  */
     119                char tmp[sizeof "."];
     120                memcpy (tmp, base, sizeof ".");
     121                strcpy (base, ".");
     122                errno = 0;
     123                name_max = pathconf (file, _PC_NAME_MAX);
     124                name_max -= !errno;
     125                memcpy (base, tmp, sizeof ".");
     126              }
     127            else
     128              {
     129                errno = 0;
     130                name_max = fpathconf (dir_fd, _PC_NAME_MAX);
     131                name_max -= !errno;
     132              }
     133  
     134            *base_max = (0 <= name_max && name_max <= SIZE_MAX ? name_max
     135                         : name_max < -1 ? NAME_MAX_MINIMUM : SIZE_MAX);
     136          }
     137  
     138        baselen_max = *base_max;
     139      }
     140  
     141    if (HAVE_DOS_FILE_NAMES && baselen_max <= 12)
     142      {
     143        /* Live within DOS's 8.3 limit.  */
     144        char *dot = strchr (base, '.');
     145        if (!dot)
     146          baselen_max = 8;
     147        else
     148          {
     149            char const *second_dot = strchr (dot + 1, '.');
     150            baselen_max = (second_dot
     151                           ? second_dot - base
     152                           : dot + 1 - base + 3);
     153          }
     154      }
     155  
     156    if (baselen <= baselen_max)
     157      return true;
     158    else
     159      {
     160        baselen = file + filelen - base;
     161        if (baselen_max <= baselen)
     162          baselen = baselen_max - 1;
     163        base[baselen] = e;
     164        base[baselen + 1] = '\0';
     165        return false;
     166      }
     167  }
     168  
     169  /* Returned values for NUMBERED_BACKUP.  */
     170  
     171  enum numbered_backup_result
     172    {
     173      /* The new backup name is the same length as an existing backup
     174         name, so it's valid for that directory.  */
     175      BACKUP_IS_SAME_LENGTH,
     176  
     177      /* Some backup names already exist, but the returned name is longer
     178         than any of them, and its length should be checked.  */
     179      BACKUP_IS_LONGER,
     180  
     181      /* There are no existing backup names.  The new name's length
     182         should be checked.  */
     183      BACKUP_IS_NEW,
     184  
     185      /* Memory allocation failure.  */
     186      BACKUP_NOMEM
     187    };
     188  
     189  /* Relative to DIR_FD, *BUFFER contains a file name.
     190     Store into *BUFFER the next backup name for the named file,
     191     with a version number greater than all the
     192     existing numbered backups.  Reallocate *BUFFER as necessary; its
     193     initial allocated size is BUFFER_SIZE, which must be at least 5
     194     bytes longer than the file name to make room for the initially
     195     appended ".~1~".  FILELEN is the length of the original file name.
     196     (The original file name is not necessarily null-terminated;
     197     FILELEN does not count trailing slashes after a non-slash.)
     198     BASE_OFFSET is the offset of the basename in *BUFFER.
     199     The returned value indicates what kind of backup was found.  If an
     200     I/O or other read error occurs, use the highest backup number that
     201     was found.
     202  
     203     *DIRPP is the destination directory.  If *DIRPP is null, open the
     204     destination directory and store the resulting stream into *DIRPP
     205     and its file descriptor into *PNEW_FD without closing the stream.  */
     206  
     207  static enum numbered_backup_result
     208  numbered_backup (int dir_fd, char **buffer, idx_t buffer_size, idx_t filelen,
     209                   idx_t base_offset, DIR **dirpp, int *pnew_fd)
     210  {
     211    enum numbered_backup_result result = BACKUP_IS_NEW;
     212    DIR *dirp = *dirpp;
     213    char *buf = *buffer;
     214    idx_t versionlenmax = 1;
     215    idx_t baselen = filelen - base_offset;
     216  
     217    if (dirp)
     218      rewinddir (dirp);
     219    else
     220      {
     221        /* Temporarily modify the buffer into its parent directory name,
     222           open the directory, and then restore the buffer.  */
     223        char tmp[sizeof "."];
     224        char *base = buf + base_offset;
     225        memcpy (tmp, base, sizeof ".");
     226        strcpy (base, ".");
     227        dirp = opendirat (dir_fd, buf, 0, pnew_fd);
     228        if (!dirp && errno == ENOMEM)
     229          result = BACKUP_NOMEM;
     230        memcpy (base, tmp, sizeof ".");
     231        strcpy (base + baselen, ".~1~");
     232        if (!dirp)
     233          return result;
     234        *dirpp = dirp;
     235      }
     236  
     237    for (struct dirent *dp; (dp = readdir (dirp)) != NULL; )
     238      {
     239        if (_D_EXACT_NAMLEN (dp) < baselen + 4)
     240          continue;
     241  
     242        if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
     243          continue;
     244  
     245        char const *p = dp->d_name + baselen + 2;
     246  
     247        /* Check whether this file has a version number and if so,
     248           whether it is larger.  Use string operations rather than
     249           integer arithmetic, to avoid problems with integer overflow.  */
     250  
     251        if (! ('1' <= *p && *p <= '9'))
     252          continue;
     253        bool all_9s = (*p == '9');
     254        idx_t versionlen;
     255        for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
     256          all_9s &= (p[versionlen] == '9');
     257  
     258        if (! (p[versionlen] == '~' && !p[versionlen + 1]
     259               && (versionlenmax < versionlen
     260                   || (versionlenmax == versionlen
     261                       && memcmp (buf + filelen + 2, p, versionlen) <= 0))))
     262          continue;
     263  
     264        /* This entry has the largest version number seen so far.
     265           Append this highest numbered extension to the file name,
     266           prepending '0' to the number if it is all 9s.  */
     267  
     268        versionlenmax = all_9s + versionlen;
     269        result = (all_9s ? BACKUP_IS_LONGER : BACKUP_IS_SAME_LENGTH);
     270        idx_t new_buffer_size = filelen + 2 + versionlenmax + 2;
     271        if (buffer_size < new_buffer_size)
     272          {
     273            idx_t grown;
     274            if (! ckd_add (&grown, new_buffer_size, new_buffer_size >> 1))
     275              new_buffer_size = grown;
     276            char *new_buf = irealloc (buf, new_buffer_size);
     277            if (!new_buf)
     278              {
     279                *buffer = buf;
     280                return BACKUP_NOMEM;
     281              }
     282            buf = new_buf;
     283            buffer_size = new_buffer_size;
     284          }
     285        char *q = buf + filelen;
     286        *q++ = '.';
     287        *q++ = '~';
     288        *q = '0';
     289        q += all_9s;
     290        memcpy (q, p, versionlen + 2);
     291  
     292        /* Add 1 to the version number.  */
     293  
     294        q += versionlen;
     295        while (*--q == '9')
     296          *q = '0';
     297        ++*q;
     298      }
     299  
     300    *buffer = buf;
     301    return result;
     302  }
     303  
     304  /* Relative to DIR_FD, return the name of the new backup file for the
     305     existing file FILE, allocated with malloc.
     306     If RENAME, also rename FILE to the new name.
     307     On failure, return NULL and set errno.
     308     Do not call this function if backup_type == no_backups.  */
     309  
     310  char *
     311  backupfile_internal (int dir_fd, char const *file,
     312                       enum backup_type backup_type, bool rename)
     313  {
     314    idx_t base_offset = last_component (file) - file;
     315    idx_t filelen = base_offset + base_len (file + base_offset);
     316  
     317    if (! simple_backup_suffix)
     318      set_simple_backup_suffix (NULL);
     319  
     320    /* Allow room for simple or ".~N~" backups.  The guess must be at
     321       least sizeof ".~1~", but otherwise will be adjusted as needed.  */
     322    idx_t simple_backup_suffix_size = strlen (simple_backup_suffix) + 1;
     323    idx_t backup_suffix_size_guess = simple_backup_suffix_size;
     324    enum { GUESS = sizeof ".~12345~" };
     325    if (backup_suffix_size_guess < GUESS)
     326      backup_suffix_size_guess = GUESS;
     327  
     328    idx_t ssize = filelen + backup_suffix_size_guess + 1;
     329    char *s = imalloc (ssize);
     330    if (!s)
     331      return s;
     332  
     333    DIR *dirp = NULL;
     334    int sdir = -1;
     335    idx_t base_max = 0;
     336    while (true)
     337      {
     338        bool extended = true;
     339        memcpy (s, file, filelen);
     340  
     341        if (backup_type == simple_backups)
     342          memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size);
     343        else
     344          switch (numbered_backup (dir_fd, &s, ssize, filelen, base_offset,
     345                                   &dirp, &sdir))
     346            {
     347            case BACKUP_IS_SAME_LENGTH:
     348              break;
     349  
     350            case BACKUP_IS_NEW:
     351              if (backup_type == numbered_existing_backups)
     352                {
     353                  backup_type = simple_backups;
     354                  memcpy (s + filelen, simple_backup_suffix,
     355                          simple_backup_suffix_size);
     356                }
     357              FALLTHROUGH;
     358            case BACKUP_IS_LONGER:
     359              extended = check_extension (s, filelen, '~', sdir, &base_max);
     360              break;
     361  
     362            case BACKUP_NOMEM:
     363              if (dirp)
     364                closedir (dirp);
     365              free (s);
     366              errno = ENOMEM;
     367              return NULL;
     368            }
     369  
     370        if (! rename)
     371          break;
     372  
     373        dir_fd = sdir < 0 ? dir_fd : sdir;
     374        idx_t offset = sdir < 0 ? 0 : base_offset;
     375        unsigned flags = backup_type == simple_backups ? 0 : RENAME_NOREPLACE;
     376        if (renameatu (dir_fd, file + offset, dir_fd, s + offset, flags) == 0)
     377          break;
     378        int e = errno;
     379        if (! (e == EEXIST && extended))
     380          {
     381            if (dirp)
     382              closedir (dirp);
     383            free (s);
     384            errno = e;
     385            return NULL;
     386          }
     387      }
     388  
     389    if (dirp)
     390      closedir (dirp);
     391    return s;
     392  }