projects
/
debian
/
gzip
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
maint: prefer HTTPS to HTTP, FTP in URLs
[debian/gzip]
/
gzip.c
diff --git
a/gzip.c
b/gzip.c
index e243f2edf357b57132fe9fa7bf4163f2f51be94c..a4717aaad8be2fa7723f450e2ab1d094c995fec3 100644
(file)
--- a/
gzip.c
+++ b/
gzip.c
@@
-1,6
+1,6
@@
/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- Copyright (C) 1999, 2001-2002, 2006-2007, 2009-201
6
Free Software
+ Copyright (C) 1999, 2001-2002, 2006-2007, 2009-201
7
Free Software
Foundation, Inc.
Copyright (C) 1992-1993 Jean-loup Gailly
Foundation, Inc.
Copyright (C) 1992-1993 Jean-loup Gailly
@@
-32,7
+32,7
@@
static char const *const license_msg[] = {
"Copyright (C) 2016 Free Software Foundation, Inc.",
"Copyright (C) 1993 Jean-loup Gailly.",
"This is free software. You may redistribute copies of it under the terms of",
"Copyright (C) 2016 Free Software Foundation, Inc.",
"Copyright (C) 1993 Jean-loup Gailly.",
"This is free software. You may redistribute copies of it under the terms of",
-"the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.",
+"the GNU General Public License <http
s
://www.gnu.org/licenses/gpl.html>.",
"There is NO WARRANTY, to the extent permitted by law.",
0};
"There is NO WARRANTY, to the extent permitted by law.",
0};
@@
-43,7
+43,7
@@
static char const *const license_msg[] = {
* or stdout with -c option or if stdin used as input.
* If the output file name had to be truncated, the original name is kept
* in the compressed file.
* or stdout with -c option or if stdin used as input.
* If the output file name had to be truncated, the original name is kept
* in the compressed file.
- * On MSDOS, file.tmp -> file.tmz.
On VMS, file.tmp -> file.tmp-gz.
+ * On MSDOS, file.tmp -> file.tmz.
*
* Using gz on MSDOS would create too many file name conflicts. For
* example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
*
* Using gz on MSDOS would create too many file name conflicts. For
* example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
@@
-63,7
+63,6
@@
static char const *const license_msg[] = {
#include <sys/stat.h>
#include <errno.h>
#include <sys/stat.h>
#include <errno.h>
-#include "closein.h"
#include "tailor.h"
#include "gzip.h"
#include "intprops.h"
#include "tailor.h"
#include "gzip.h"
#include "intprops.h"
@@
-72,6
+71,7
@@
static char const *const license_msg[] = {
#include "timespec.h"
#include "dirname.h"
#include "timespec.h"
#include "dirname.h"
+#include "dosname.h"
#include "fcntl--.h"
#include "getopt.h"
#include "ignore-value.h"
#include "fcntl--.h"
#include "getopt.h"
#include "ignore-value.h"
@@
-189,12
+189,17
@@
static int foreground = 0; /* set if program run in foreground */
int save_orig_name; /* set if original name must be saved */
static int last_member; /* set for .zip and .Z files */
static int part_nb; /* number of parts in .gz file */
int save_orig_name; /* set if original name must be saved */
static int last_member; /* set for .zip and .Z files */
static int part_nb; /* number of parts in .gz file */
- struct timespec time_stamp; /* original time stamp (modification time) */
off_t ifile_size; /* input file size, -1 for devices (debug only) */
static char *env; /* contents of GZIP env variable */
static char const *z_suffix; /* default suffix (can be set with --suffix) */
static size_t z_len; /* strlen(z_suffix) */
off_t ifile_size; /* input file size, -1 for devices (debug only) */
static char *env; /* contents of GZIP env variable */
static char const *z_suffix; /* default suffix (can be set with --suffix) */
static size_t z_len; /* strlen(z_suffix) */
+/* The original timestamp (modification time). Its tv_nsec component
+ is negative if the original time is unknown or is out of time_t
+ range; the latter can happen on hosts with 32-bit signed time_t
+ because the gzip format's MTIME is 32-bit unsigned. */
+struct timespec time_stamp;
+
/* The set of signals that are caught. */
static sigset_t caught_signals;
/* The set of signals that are caught. */
static sigset_t caught_signals;
@@
-206,6
+211,8
@@
static int volatile exiting_signal;
/* If nonnegative, close this file descriptor and unlink ofname on error. */
static int volatile remove_ofname_fd = -1;
/* If nonnegative, close this file descriptor and unlink ofname on error. */
static int volatile remove_ofname_fd = -1;
+static bool stdin_was_read;
+
off_t bytes_in; /* number of input bytes */
off_t bytes_out; /* number of output bytes */
static off_t total_in; /* input bytes for all files */
off_t bytes_in; /* number of input bytes */
off_t bytes_out; /* number of output bytes */
static off_t total_in; /* input bytes for all files */
@@
-283,7
+290,6
@@
static const struct option longopts[] =
{"recursive", 0, 0, 'r'}, /* recurse through directories */
{"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
{"test", 0, 0, 't'}, /* test compressed file integrity */
{"recursive", 0, 0, 'r'}, /* recurse through directories */
{"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
{"test", 0, 0, 't'}, /* test compressed file integrity */
- {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */
{"verbose", 0, 0, 'v'}, /* verbose mode */
{"version", 0, 0, 'V'}, /* display version number */
{"fast", 0, 0, '1'}, /* compress faster */
{"verbose", 0, 0, 'v'}, /* verbose mode */
{"version", 0, 0, 'V'}, /* display version number */
{"fast", 0, 0, '1'}, /* compress faster */
@@
-317,6
+323,7
@@
local void install_signal_handlers (void);
local void remove_output_file (void);
local RETSIGTYPE abort_gzip_signal (int);
local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
local void remove_output_file (void);
local RETSIGTYPE abort_gzip_signal (int);
local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
+static void finish_out (void);
int main (int argc, char **argv);
static int (*work) (int infile, int outfile) = zip; /* function to call */
int main (int argc, char **argv);
static int (*work) (int infile, int outfile) = zip; /* function to call */
@@
-355,15
+362,16
@@
local void help()
" -l, --list list compressed file contents",
" -L, --license display software license",
#ifdef UNDOCUMENTED
" -l, --list list compressed file contents",
" -L, --license display software license",
#ifdef UNDOCUMENTED
- " -m
, --no-time
do not save or restore the original modification time",
+ " -m
do not save or restore the original modification time",
" -M, --time save or restore the original modification time",
#endif
" -M, --time save or restore the original modification time",
#endif
- " -n, --no-name do not save or restore the original name and time
stamp",
- " -N, --name save or restore the original name and time
stamp",
+ " -n, --no-name do not save or restore the original name and timestamp",
+ " -N, --name save or restore the original name and timestamp",
" -q, --quiet suppress all warnings",
#if ! NO_DIR
" -r, --recursive operate recursively on directories",
#endif
" -q, --quiet suppress all warnings",
#if ! NO_DIR
" -r, --recursive operate recursively on directories",
#endif
+ " --rsyncable make rsync-friendly archive",
" -S, --suffix=SUF use suffix SUF on compressed files",
" --synchronous synchronous output (safer if system crashes, but slower)",
" -t, --test test compressed file integrity",
" -S, --suffix=SUF use suffix SUF on compressed files",
" --synchronous synchronous output (safer if system crashes, but slower)",
" -t, --test test compressed file integrity",
@@
-375,7
+383,6
@@
local void help()
" -Z, --lzw produce output compatible with old compress",
" -b, --bits=BITS max number of bits per code (implies -Z)",
#endif
" -Z, --lzw produce output compatible with old compress",
" -b, --bits=BITS max number of bits per code (implies -Z)",
#endif
- " --rsyncable Make rsync-friendly archive",
"",
"With no FILE, or when FILE is -, read standard input.",
"",
"",
"With no FILE, or when FILE is -, read standard input.",
"",
@@
-427,9
+434,7
@@
int main (int argc, char **argv)
program_name = gzip_base_name (argv[0]);
proglen = strlen (program_name);
program_name = gzip_base_name (argv[0]);
proglen = strlen (program_name);
- atexit (close_stdin);
-
- /* Suppress .exe for MSDOS, OS/2 and VMS: */
+ /* Suppress .exe for MSDOS and OS/2: */
if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
program_name[proglen - 4] = '\0';
if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
program_name[proglen - 4] = '\0';
@@
-447,7
+452,7
@@
int main (int argc, char **argv)
* gzip even if it is invoked under the name gunzip or zcat.
*
* Systems which do not support links can still use -d or -dc.
* gzip even if it is invoked under the name gunzip or zcat.
*
* Systems which do not support links can still use -d or -dc.
- * Ignore an .exe extension for MSDOS
, OS/2 and VMS
.
+ * Ignore an .exe extension for MSDOS
and OS/2
.
*/
if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
|| strncmp (program_name, "gun", 3) == 0) /* gunzip */
*/
if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
|| strncmp (program_name, "gun", 3) == 0) /* gunzip */
@@
-527,13
+532,13
@@
int main (int argc, char **argv)
case 'f':
force++; break;
case 'h': case 'H':
case 'f':
force++; break;
case 'h': case 'H':
- help
(); do_exit(OK
); break;
+ help
(); finish_out (
); break;
case 'k':
keep = 1; break;
case 'l':
list = decompress = to_stdout = 1; break;
case 'L':
case 'k':
keep = 1; break;
case 'l':
list = decompress = to_stdout = 1; break;
case 'L':
- license
(); do_exit(OK
); break;
+ license
(); finish_out (
); break;
case 'm': /* undocumented, may change later */
no_time = 1; break;
case 'M': /* undocumented, may change later */
case 'm': /* undocumented, may change later */
no_time = 1; break;
case 'M': /* undocumented, may change later */
@@
-560,6
+565,7
@@
int main (int argc, char **argv)
break;
case RSYNCABLE_OPTION:
break;
case RSYNCABLE_OPTION:
+ case RSYNCABLE_OPTION + ENV_OPTION:
rsync = 1;
break;
case 'S':
rsync = 1;
break;
case 'S':
@@
-579,7
+585,7
@@
int main (int argc, char **argv)
case 'v' + ENV_OPTION:
verbose++; quiet = 0; break;
case 'V':
case 'v' + ENV_OPTION:
verbose++; quiet = 0; break;
case 'V':
- version
(); do_exit(OK
); break;
+ version
(); finish_out (
); break;
case 'Z':
#ifdef LZW
do_lzw = 1; break;
case 'Z':
#ifdef LZW
do_lzw = 1; break;
@@
-593,7
+599,7
@@
int main (int argc, char **argv)
case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
optc -= ENV_OPTION;
case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
optc -= ENV_OPTION;
- /* Fall through. */
+ FALLTHROUGH;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
level = optc - '0';
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
level = optc - '0';
@@
-663,12
+669,22
@@
int main (int argc, char **argv)
} else { /* Standard input */
treat_stdin();
}
} else { /* Standard input */
treat_stdin();
}
- if (list && !quiet && file_count > 1) {
- do_list(-1, -1); /* print totals */
- }
+ if (stdin_was_read && close (STDIN_FILENO) != 0)
+ {
+ strcpy (ifname, "stdin");
+ read_error ();
+ }
+ if (list)
+ {
+ /* Output any totals, and check for output errors. */
+ if (!quiet && 1 < file_count)
+ do_list (-1, -1);
+ if (fflush (stdout) != 0)
+ write_error ();
+ }
if (to_stdout
&& ((synchronous
if (to_stdout
&& ((synchronous
- &&
(fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
)
+ &&
fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL
)
|| close (STDOUT_FILENO) != 0)
&& errno != EBADF)
write_error ();
|| close (STDOUT_FILENO) != 0)
&& errno != EBADF)
write_error ();
@@
-736,7
+752,7
@@
local void treat_stdin()
strcpy(ifname, "stdin");
strcpy(ofname, "stdout");
strcpy(ifname, "stdin");
strcpy(ofname, "stdout");
- /* Get the file's time
stamp and size. */
+ /* Get the file's timestamp and size. */
if (fstat (STDIN_FILENO, &istat) != 0)
{
progerror ("standard input");
if (fstat (STDIN_FILENO, &istat) != 0)
{
progerror ("standard input");
@@
-756,6
+772,7
@@
local void treat_stdin()
to_stdout = 1;
part_nb = 0;
ifd = STDIN_FILENO;
to_stdout = 1;
part_nb = 0;
ifd = STDIN_FILENO;
+ stdin_was_read = true;
if (decompress) {
method = get_method(ifd);
if (decompress) {
method = get_method(ifd);
@@
-1137,8
+1154,6
@@
local int create_outfile()
* also accepted suffixes. For Unix, we do not want to accept any
* .??z suffix as indicating a compressed file; some people use .xyz
* to denote volume data.
* also accepted suffixes. For Unix, we do not want to accept any
* .??z suffix as indicating a compressed file; some people use .xyz
* to denote volume data.
- * On systems allowing multiple versions of the same file (such as VMS),
- * this function removes any version suffix in the given name.
*/
local char *get_suffix(name)
char *name;
*/
local char *get_suffix(name)
char *name;
@@
-1170,13
+1185,6
@@
local char *get_suffix(name)
: 0] = z_suffix;
suf = known_suffixes + suffix_of_builtin;
: 0] = z_suffix;
suf = known_suffixes + suffix_of_builtin;
-#ifdef SUFFIX_SEP
- /* strip a version number from the file name */
- {
- char *v = strrchr(name, SUFFIX_SEP);
- if (v != NULL) *v = '\0';
- }
-#endif
nlen = strlen(name);
if (nlen <= MAX_SUFFIX+2) {
strcpy(suffix, name);
nlen = strlen(name);
if (nlen <= MAX_SUFFIX+2) {
strcpy(suffix, name);
@@
-1187,7
+1195,7
@@
local char *get_suffix(name)
slen = strlen(suffix);
do {
int s = strlen(*suf);
slen = strlen(suffix);
do {
int s = strlen(*suf);
- if (slen > s &&
suffix[slen-s-1] != PATH_SEP
+ if (slen > s &&
! ISSLASH (suffix[slen - s - 1])
&& strequ(suffix + slen - s, *suf)) {
return name+nlen-s;
}
&& strequ(suffix + slen - s, *suf)) {
return name+nlen-s;
}
@@
-1214,7
+1222,7
@@
open_and_stat (char *name, int flags, struct stat *st)
flags |= O_NOFOLLOW;
else
{
flags |= O_NOFOLLOW;
else
{
-#if
HAVE_LSTAT || defined lstat
+#if
def S_ISLNK
if (lstat (name, st) != 0)
return -1;
else if (S_ISLNK (st->st_mode))
if (lstat (name, st) != 0)
return -1;
else if (S_ISLNK (st->st_mode))
@@
-1289,9
+1297,7
@@
open_input_file (iname, sbuf)
progerror(ifname);
return -1;
}
progerror(ifname);
return -1;
}
- /* file.ext doesn't exist, try adding a suffix (after removing any
- * version number for VMS).
- */
+ /* File.ext doesn't exist. Try adding a suffix. */
s = get_suffix(ifname);
if (s != NULL) {
progerror(ifname); /* ifname already has z suffix and does not exist */
s = get_suffix(ifname);
if (s != NULL) {
progerror(ifname); /* ifname already has z suffix and does not exist */
@@
-1460,7
+1466,7
@@
discard_input_bytes (nbytes, flags)
* original name was given and to_stdout is not set.
* Return the compression method, -1 for error, -2 for warning.
* Set inptr to the offset of the next byte to be processed.
* original name was given and to_stdout is not set.
* Return the compression method, -1 for error, -2 for warning.
* Set inptr to the offset of the next byte to be processed.
- * Updates time_stamp if there is one and
--no-time is not
used.
+ * Updates time_stamp if there is one and
neither -m nor -n is
used.
* This function may be called repeatedly for an input file consisting
* of several contiguous gzip'ed members.
* IN assertions: there is at least one remaining compressed member.
* This function may be called repeatedly for an input file consisting
* of several contiguous gzip'ed members.
* IN assertions: there is at least one remaining compressed member.
@@
-1473,7
+1479,7
@@
local int get_method(in)
uch magic[10]; /* magic header */
int imagic0; /* first magic byte or EOF */
int imagic1; /* like magic[1], but can represent EOF */
uch magic[10]; /* magic header */
int imagic0; /* first magic byte or EOF */
int imagic1; /* like magic[1], but can represent EOF */
- ulg stamp; /* time
stamp */
+ ulg stamp; /* timestamp */
/* If --force and --stdout, zcat == cat, so do not complain about
* premature end of file: use try_byte instead of get_byte.
/* If --force and --stdout, zcat == cat, so do not complain about
* premature end of file: use try_byte instead of get_byte.
@@
-1498,7
+1504,7
@@
local int get_method(in)
method = -1; /* unknown yet */
part_nb++; /* number of parts in gzip file */
header_bytes = 0;
method = -1; /* unknown yet */
part_nb++; /* number of parts in gzip file */
header_bytes = 0;
- last_member =
RECORD_IO
;
+ last_member =
0
;
/* assume multiple members in gzip file except for record oriented I/O */
if (memcmp(magic, GZIP_MAGIC, 2) == 0
/* assume multiple members in gzip file except for record oriented I/O */
if (memcmp(magic, GZIP_MAGIC, 2) == 0
@@
-1533,7
+1539,7
@@
local int get_method(in)
stamp |= ((ulg)get_byte()) << 8;
stamp |= ((ulg)get_byte()) << 16;
stamp |= ((ulg)get_byte()) << 24;
stamp |= ((ulg)get_byte()) << 8;
stamp |= ((ulg)get_byte()) << 16;
stamp |= ((ulg)get_byte()) << 24;
- if (
stamp != 0 && !no_time
)
+ if (
!no_time && 0 < stamp && stamp <= TYPE_MAXIMUM (time_t)
)
{
time_stamp.tv_sec = stamp;
time_stamp.tv_nsec = 0;
{
time_stamp.tv_sec = stamp;
time_stamp.tv_nsec = 0;
@@
-1741,7
+1747,7
@@
local void do_list(ifd, method)
bytes_out = -1L;
bytes_in = ifile_size;
bytes_out = -1L;
bytes_in = ifile_size;
- if (
!RECORD_IO &&
method == DEFLATED && !last_member) {
+ if (method == DEFLATED && !last_member) {
/* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
* If the lseek fails, we could use read() to get to the end, but
* --list is used to get quick results.
/* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
* If the lseek fails, we could use read() to get to the end, but
* --list is used to get quick results.
@@
-1762,12
+1768,15
@@
local void do_list(ifd, method)
if (verbose)
{
if (verbose)
{
- struct tm *tm = localtime (&time_stamp.tv_sec);
+ static char const month_abbr[][4]
+ = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ struct tm *tm = (time_stamp.tv_nsec < 0
+ ? NULL
+ : localtime (&time_stamp.tv_sec));
printf ("%5s %08lx ", methods[method], crc);
if (tm)
printf ("%5s %08lx ", methods[method], crc);
if (tm)
- printf ("%s%3d %02d:%02d ",
- ("Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec"
- + 4 * tm->tm_mon),
+ printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
tm->tm_mday, tm->tm_hour, tm->tm_min);
else
printf ("??? ?? ??:?? ");
tm->tm_mday, tm->tm_hour, tm->tm_min);
else
printf ("??? ?? ??:?? ");
@@
-1832,8
+1841,7
@@
local void shorten_name(name)
* 1234.678.012.gz -> 123.678.012.gz
*/
do {
* 1234.678.012.gz -> 123.678.012.gz
*/
do {
- p = strrchr(name, PATH_SEP);
- p = p ? p+1 : name;
+ p = last_component (name);
while (*p) {
plen = strcspn(p, PART_SEP);
p += plen;
while (*p) {
plen = strcspn(p, PART_SEP);
p += plen;
@@
-1911,21
+1919,23
@@
local void copy_stat(ifstat)
int r;
#ifndef NO_UTIME
int r;
#ifndef NO_UTIME
+ bool restoring;
struct timespec timespec[2];
timespec[0] = get_stat_atime (ifstat);
timespec[1] = get_stat_mtime (ifstat);
struct timespec timespec[2];
timespec[0] = get_stat_atime (ifstat);
timespec[1] = get_stat_mtime (ifstat);
+ restoring = (decompress && 0 <= time_stamp.tv_nsec
+ && ! (timespec[1].tv_sec == time_stamp.tv_sec
+ && timespec[1].tv_nsec == time_stamp.tv_nsec));
+ if (restoring)
+ timespec[1] = time_stamp;
- if (decompress && 0 <= time_stamp.tv_nsec
- && ! (timespec[1].tv_sec == time_stamp.tv_sec
- && timespec[1].tv_nsec == time_stamp.tv_nsec))
+ if (fdutimens (ofd, ofname, timespec) == 0)
{
{
- timespec[1] = time_stamp;
- if (verbose > 1) {
- fprintf(stderr, "%s: time stamp restored\n", ofname);
+ if (restoring && 1 < verbose) {
+ fprintf(stderr, "%s: timestamp restored\n", ofname);
}
}
}
}
-
- if (fdutimens (ofd, ofname, timespec) != 0)
+ else
{
int e = errno;
WARN ((stderr, "%s: ", program_name));
{
int e = errno;
WARN ((stderr, "%s: ", program_name));
@@
-2000,16
+2010,8
@@
local void treat_dir (fd, dir)
continue;
if (len + entrylen < MAX_PATH_LEN - 2) {
strcpy(nbuf,dir);
continue;
if (len + entrylen < MAX_PATH_LEN - 2) {
strcpy(nbuf,dir);
- if (len != 0 /* dir = "" means current dir on Amiga */
-#ifdef PATH_SEP2
- && dir[len-1] != PATH_SEP2
-#endif
-#ifdef PATH_SEP3
- && dir[len-1] != PATH_SEP3
-#endif
- ) {
- nbuf[len++] = PATH_SEP;
- }
+ if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
+ nbuf[len++] = '/';
strcpy (nbuf + len, entry);
treat_file(nbuf);
} else {
strcpy (nbuf + len, entry);
treat_file(nbuf);
} else {
@@
-2089,6
+2091,14
@@
local void do_exit(exitcode)
exit(exitcode);
}
exit(exitcode);
}
+static void
+finish_out (void)
+{
+ if (fclose (stdout) != 0)
+ write_error ();
+ do_exit (OK);
+}
+
/* ========================================================================
* Close and unlink the output file.
*/
/* ========================================================================
* Close and unlink the output file.
*/