Compress-Stream-Zstd

 view release on metacpan or  search on metacpan

ext/zstd/programs/util.c  view on Meta::CPAN

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under both the BSD-style license (found in the
 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
 * in the COPYING file in the root directory of this source tree).
 * You may select, at your option, one of the above-listed licenses.
 */

#if defined (__cplusplus)
extern "C" {
#endif


/*-****************************************
*  Dependencies
******************************************/
#include "util.h"       /* note : ensure that platform.h is included first ! */
#include <stdlib.h>     /* malloc, realloc, free */
#include <stdio.h>      /* fprintf */
#include <time.h>       /* clock_t, clock, CLOCKS_PER_SEC, nanosleep */
#include <errno.h>
#include <assert.h>

#if defined(_WIN32)
#  include <sys/utime.h>  /* utime */
#  include <io.h>         /* _chmod */
#else
#  include <unistd.h>     /* chown, stat */
#  if PLATFORM_POSIX_VERSION < 200809L || !defined(st_mtime)
#    include <utime.h>    /* utime */
#  else
#    include <fcntl.h>    /* AT_FDCWD */
#    include <sys/stat.h> /* utimensat */
#  endif
#endif

#if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__)
#include <direct.h>     /* needed for _mkdir in windows */
#endif

#if defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L)  /* opendir, readdir require POSIX.1-2001 */
#  include <dirent.h>       /* opendir, readdir */
#  include <string.h>       /* strerror, memcpy */
#endif /* #ifdef _WIN32 */

/*-****************************************
*  Internal Macros
******************************************/

/* CONTROL is almost like an assert(), but is never disabled.
 * It's designed for failures that may happen rarely,
 * but we don't want to maintain a specific error code path for them,
 * such as a malloc() returning NULL for example.
 * Since it's always active, this macro can trigger side effects.
 */
#define CONTROL(c)  {         \
    if (!(c)) {               \
        UTIL_DISPLAYLEVEL(1, "Error : %s, %i : %s",  \
                          __FILE__, __LINE__, #c);   \
        exit(1);              \
}   }

/* console log */
#define UTIL_DISPLAY(...)         fprintf(stderr, __VA_ARGS__)
#define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } }

static int g_traceDepth = 0;
int g_traceFileStat = 0;

#define UTIL_TRACE_CALL(...)                                         \
    {                                                                \
        if (g_traceFileStat) {                                       \
            UTIL_DISPLAY("Trace:FileStat: %*s> ", g_traceDepth, ""); \
            UTIL_DISPLAY(__VA_ARGS__);                               \
            UTIL_DISPLAY("\n");                                      \
            ++g_traceDepth;                                          \
        }                                                            \
    }

#define UTIL_TRACE_RET(ret)                                                     \
    {                                                                           \
        if (g_traceFileStat) {                                                  \
            --g_traceDepth;                                                     \
            UTIL_DISPLAY("Trace:FileStat: %*s< %d\n", g_traceDepth, "", (ret)); \
        }                                                                      \
    }

/* A modified version of realloc().

ext/zstd/programs/util.c  view on Meta::CPAN

        return ret;
    }
}

/* set access and modification times */
int UTIL_utime(const char* filename, const stat_t *statbuf)
{
    int ret;
    UTIL_TRACE_CALL("UTIL_utime(%s)", filename);
    /* We check that st_mtime is a macro here in order to give us confidence
     * that struct stat has a struct timespec st_mtim member. We need this
     * check because there are some platforms that claim to be POSIX 2008
     * compliant but which do not have st_mtim... */
#if (PLATFORM_POSIX_VERSION >= 200809L) && defined(st_mtime)
    {
        /* (atime, mtime) */
        struct timespec timebuf[2] = { {0, UTIME_NOW} };
        timebuf[1] = statbuf->st_mtim;
        ret = utimensat(AT_FDCWD, filename, timebuf, 0);
    }
#else
    {
        struct utimbuf timebuf;
        timebuf.actime = time(NULL);
        timebuf.modtime = statbuf->st_mtime;
        ret = utime(filename, &timebuf);
    }
#endif
    errno = 0;
    UTIL_TRACE_RET(ret);
    return ret;
}

int UTIL_setFileStat(const char *filename, const stat_t *statbuf)
{
    return UTIL_setFDStat(-1, filename, statbuf);
}

int UTIL_setFDStat(const int fd, const char *filename, const stat_t *statbuf)
{
    int res = 0;
    stat_t curStatBuf;
    UTIL_TRACE_CALL("UTIL_setFileStat(%d, %s)", fd, filename);

    if (!UTIL_fstat(fd, filename, &curStatBuf) || !UTIL_isRegularFileStat(&curStatBuf)) {
        UTIL_TRACE_RET(-1);
        return -1;
    }

    /* Mimic gzip's behavior:
     *
     * "Change the group first, then the permissions, then the owner.
     * That way, the permissions will be correct on systems that allow
     * users to give away files, without introducing a security hole.
     * Security depends on permissions not containing the setuid or
     * setgid bits." */

#if !defined(_WIN32)
#ifdef ZSTD_HAVE_FCHOWN
    if (fd >= 0) {
        res += fchown(fd, -1, statbuf->st_gid);  /* Apply group ownership */
    } else
#endif
    {
        res += chown(filename, -1, statbuf->st_gid);  /* Apply group ownership */
    }
#endif

    res += UTIL_fchmod(fd, filename, &curStatBuf, statbuf->st_mode & 0777);  /* Copy file permissions */

#if !defined(_WIN32)
#ifdef ZSTD_HAVE_FCHOWN
    if (fd >= 0) {
        res += fchown(fd, statbuf->st_uid, -1);  /* Apply user ownership */
    } else
#endif
    {
        res += chown(filename, statbuf->st_uid, -1);  /* Apply user ownership */
    }
#endif

    errno = 0;
    UTIL_TRACE_RET(-res);
    return -res; /* number of errors is returned */
}

int UTIL_isDirectory(const char* infilename)
{
    stat_t statbuf;
    int ret;
    UTIL_TRACE_CALL("UTIL_isDirectory(%s)", infilename);
    ret = UTIL_stat(infilename, &statbuf) && UTIL_isDirectoryStat(&statbuf);
    UTIL_TRACE_RET(ret);
    return ret;
}

int UTIL_isDirectoryStat(const stat_t* statbuf)
{
    int ret;
    UTIL_TRACE_CALL("UTIL_isDirectoryStat()");
#if defined(_MSC_VER)
    ret = (statbuf->st_mode & _S_IFDIR) != 0;
#else
    ret = S_ISDIR(statbuf->st_mode) != 0;
#endif
    UTIL_TRACE_RET(ret);
    return ret;
}

int UTIL_compareStr(const void *p1, const void *p2) {
    return strcmp(* (char * const *) p1, * (char * const *) p2);
}

int UTIL_isSameFile(const char* fName1, const char* fName2)
{
    int ret;
    assert(fName1 != NULL); assert(fName2 != NULL);
    UTIL_TRACE_CALL("UTIL_isSameFile(%s, %s)", fName1, fName2);
#if defined(_MSC_VER) || defined(_WIN32)
    /* note : Visual does not support file identification by inode.
     *        inode does not work on Windows, even with a posix layer, like msys2.
     *        The following work-around is limited to detecting exact name repetition only,
     *        aka `filename` is considered different from `subdir/../filename` */
    ret = !strcmp(fName1, fName2);
#else
    {   stat_t file1Stat;
        stat_t file2Stat;
        ret =  UTIL_stat(fName1, &file1Stat)
            && UTIL_stat(fName2, &file2Stat)
            && UTIL_isSameFileStat(fName1, fName2, &file1Stat, &file2Stat);
    }
#endif
    UTIL_TRACE_RET(ret);
    return ret;
}

int UTIL_isSameFileStat(
        const char* fName1, const char* fName2,



( run in 1.116 second using v1.01-cache-2.11-cpan-71847e10f99 )