/*
* Copyright 2016-2018, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* rm.c -- implementation of pmempool_rm() function
*/
#include <errno.h>
#include <fcntl.h>
#include "libpmempool.h"
#include "out.h"
#include "os.h"
#include "util.h"
#include "set.h"
#include "file.h"
#define PMEMPOOL_RM_ALL_FLAGS (\
PMEMPOOL_RM_FORCE |\
PMEMPOOL_RM_POOLSET_LOCAL |\
PMEMPOOL_RM_POOLSET_REMOTE)
#define ERR_F(f, ...) do {\
if (CHECK_FLAG((f), FORCE))\
LOG(2, "!(ignored) " __VA_ARGS__);\
else\
ERR(__VA_ARGS__);\
} while (0)
#define CHECK_FLAG(f, i) ((f) & PMEMPOOL_RM_##i)
struct cb_args {
unsigned flags;
int error;
};
/*
* rm_local -- (internal) remove single local file
*/
static int
rm_local(const char *path, unsigned flags, int is_part_file)
{
int ret = util_unlink_flock(path);
if (!ret) {
LOG(3, "%s: removed", path);
return 0;
}
int oerrno = errno;
os_stat_t buff;
ret = os_stat(path, &buff);
if (!ret) {
if (S_ISDIR(buff.st_mode)) {
errno = EISDIR;
if (is_part_file)
ERR("%s: removing file failed", path);
else
ERR("removing file failed");
return -1;
}
}
errno = oerrno;
if (is_part_file)
ERR_F(flags, "%s: removing file failed", path);
else
ERR_F(flags, "removing file failed");
if (CHECK_FLAG(flags, FORCE))
return 0;
return -1;
}
/*
* rm_remote -- (internal) remove remote replica
*/
static int
rm_remote(const char *node, const char *path, unsigned flags)
{
if (!Rpmem_remove) {
ERR_F(flags, "cannot remove remote replica"
" -- missing librpmem");
return -1;
}
int rpmem_flags = 0;
if (CHECK_FLAG(flags, FORCE))
rpmem_flags |= RPMEM_REMOVE_FORCE;
if (CHECK_FLAG(flags, POOLSET_REMOTE))
rpmem_flags |= RPMEM_REMOVE_POOL_SET;
int ret = Rpmem_remove(node, path, rpmem_flags);
if (ret) {
ERR_F(flags, "%s/%s removing failed", node, path);
if (CHECK_FLAG(flags, FORCE))
ret = 0;
} else {
LOG(3, "%s/%s: removed", node, path);
}
return ret;
}
/*
* rm_cb -- (internal) foreach part callback
*/
static int
rm_cb(struct part_file *pf, void *arg)
{
struct cb_args *args = (struct cb_args *)arg;
int ret;
if (pf->is_remote) {
ret = rm_remote(pf->remote->node_addr, pf->remote->pool_desc,
args->flags);
} else {
ret = rm_local(pf->part->path, args->flags, 1);
}
if (ret)
args->error = ret;
return 0;
}
/*
* pmempool_rmU -- remove pool files or poolsets
*/
#ifndef _WIN32
static inline
#endif
int
pmempool_rmU(const char *path, unsigned flags)
{
LOG(3, "path %s flags %x", path, flags);
int ret;
if (flags & ~PMEMPOOL_RM_ALL_FLAGS) {
ERR("invalid flags specified");
errno = EINVAL;
return -1;
}
int is_poolset = util_is_poolset_file(path);
if (is_poolset < 0) {
os_stat_t buff;
ret = os_stat(path, &buff);
if (!ret) {
if (S_ISDIR(buff.st_mode)) {
errno = EISDIR;
ERR("removing file failed");
return -1;
}
}
ERR_F(flags, "removing file failed");
if (CHECK_FLAG(flags, FORCE))
return 0;
return -1;
}
if (!is_poolset) {
LOG(2, "%s: not a poolset file", path);
return rm_local(path, flags, 0);
}
LOG(2, "%s: poolset file", path);
/* fill up pool_set structure */
struct pool_set *set = NULL;
int fd = os_open(path, O_RDONLY);
if (fd == -1 || util_poolset_parse(&set, path, fd)) {
ERR_F(flags, "parsing poolset file failed");
if (fd != -1)
os_close(fd);
if (CHECK_FLAG(flags, FORCE))
return 0;
return -1;
}
os_close(fd);
if (set->remote) {
/* ignore error - it will be handled in rm_remote() */
(void) util_remote_load();
}
util_poolset_free(set);
struct cb_args args;
args.flags = flags;
args.error = 0;
ret = util_poolset_foreach_part(path, rm_cb, &args);
if (ret == -1) {
ERR_F(flags, "parsing poolset file failed");
if (CHECK_FLAG(flags, FORCE))
return 0;
return ret;
}
ASSERTeq(ret, 0);
if (args.error)
return args.error;
if (CHECK_FLAG(flags, POOLSET_LOCAL)) {
ret = rm_local(path, flags, 0);
if (ret) {
ERR_F(flags, "removing pool set file failed");
} else {
LOG(3, "%s: removed", path);
}
if (CHECK_FLAG(flags, FORCE))
return 0;
return ret;
}
return 0;
}
#ifndef _WIN32
/*
* pmempool_rm -- remove pool files or poolsets
*/
int
pmempool_rm(const char *path, unsigned flags)
{
return pmempool_rmU(path, flags);
}
#else
/*
* pmempool_rmW -- remove pool files or poolsets in widechar
*/
int
pmempool_rmW(const wchar_t *path, unsigned flags)
{
char *upath = util_toUTF8(path);
if (upath == NULL) {
ERR("Invalid poolest/pool file path.");
return -1;
}
int ret = pmempool_rmU(upath, flags);
util_free_UTF8(upath);
return ret;
}
#endif