[BACK]Return to remove.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / pkgsrc / pkgtools / pkg_install / files / lib

File: [cvs.NetBSD.org] / pkgsrc / pkgtools / pkg_install / files / lib / remove.c (download)

Revision 1.3, Sun Aug 2 17:56:45 2009 UTC (10 years, 8 months ago) by joerg
Branch: MAIN
CVS Tags: pkgsrc-2020Q1-base, pkgsrc-2020Q1, pkgsrc-2019Q4-base, pkgsrc-2019Q4, pkgsrc-2019Q3-base, pkgsrc-2019Q3, pkgsrc-2019Q2-base, pkgsrc-2019Q2, pkgsrc-2019Q1-base, pkgsrc-2019Q1, pkgsrc-2018Q4-base, pkgsrc-2018Q4, pkgsrc-2018Q3-base, pkgsrc-2018Q3, pkgsrc-2018Q2-base, pkgsrc-2018Q2, pkgsrc-2018Q1-base, pkgsrc-2018Q1, pkgsrc-2017Q4-base, pkgsrc-2017Q4, pkgsrc-2017Q3-base, pkgsrc-2017Q3, pkgsrc-2017Q2-base, pkgsrc-2017Q2, pkgsrc-2017Q1-base, pkgsrc-2017Q1, pkgsrc-2016Q4-base, pkgsrc-2016Q4, pkgsrc-2016Q3-base, pkgsrc-2016Q3, pkgsrc-2016Q2-base, pkgsrc-2016Q2, pkgsrc-2016Q1-base, pkgsrc-2016Q1, pkgsrc-2015Q4-base, pkgsrc-2015Q4, pkgsrc-2015Q3-base, pkgsrc-2015Q3, pkgsrc-2015Q2-base, pkgsrc-2015Q2, pkgsrc-2015Q1-base, pkgsrc-2015Q1, pkgsrc-2014Q4-base, pkgsrc-2014Q4, pkgsrc-2014Q3-base, pkgsrc-2014Q3, pkgsrc-2014Q2-base, pkgsrc-2014Q2, pkgsrc-2014Q1-base, pkgsrc-2014Q1, pkgsrc-2013Q4-base, pkgsrc-2013Q4, pkgsrc-2013Q3-base, pkgsrc-2013Q3, pkgsrc-2013Q2-base, pkgsrc-2013Q2, pkgsrc-2013Q1-base, pkgsrc-2013Q1, pkgsrc-2012Q4-base, pkgsrc-2012Q4, pkgsrc-2012Q3-base, pkgsrc-2012Q3, pkgsrc-2012Q2-base, pkgsrc-2012Q2, pkgsrc-2012Q1-base, pkgsrc-2012Q1, pkgsrc-2011Q4-base, pkgsrc-2011Q4, pkgsrc-2011Q3-base, pkgsrc-2011Q3, pkgsrc-2011Q2-base, pkgsrc-2011Q2, pkgsrc-2011Q1-base, pkgsrc-2011Q1, pkgsrc-2010Q4-base, pkgsrc-2010Q4, pkgsrc-2010Q3-base, pkgsrc-2010Q3, pkgsrc-2010Q2-base, pkgsrc-2010Q2, pkgsrc-2010Q1-base, pkgsrc-2010Q1, pkgsrc-2009Q4-base, pkgsrc-2009Q4, pkgsrc-2009Q3-base, pkgsrc-2009Q3, HEAD
Changes since 1.2: +3 -4 lines

pkg_install-20090727:
Make pkg_install WARNS=4 clean and fix a number of lint warnings.
Based on reports from veego about warnings with older GCC releases in
pkg_delete, where a variable is potentially used uninitialized.

/*	$NetBSD: remove.c,v 1.3 2009/08/02 17:56:45 joerg Exp $	*/

/*-
 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 HOLDERS 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.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <nbcompat.h>

#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif

__RCSID("$NetBSD: remove.c,v 1.3 2009/08/02 17:56:45 joerg Exp $");

#if HAVE_DIRENT_H
#include <dirent.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#include <errno.h>
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "lib.h"

static int
safe_fchdir(int cwd)
{
	int tmp_errno, rv;

	tmp_errno = errno;
	rv = fchdir(cwd);
	errno = tmp_errno;

	return rv;
}

static int
long_remove(const char **path_ptr, int missing_ok, int *did_chdir)
{
	char tmp_path[PATH_MAX + 1];
	const char *path;
	size_t i, len;
	int rv;

	path = *path_ptr;
	len = strlen(path);
	*did_chdir = 0;

	while (len >= PATH_MAX) {
		for (i = PATH_MAX - 1; i > 0; --i) {
			if (path[i] == '/')
				break;
		}
		if (i == 0) {
			errno = ENAMETOOLONG;
			return -1; /* Assumes PATH_MAX > NAME_MAX */
		}
		memcpy(tmp_path, path, i);
		tmp_path[i] = '\0';
		if (chdir(tmp_path))
			return -1;
		*did_chdir = 1;
		path += i + 1;
		len -= i + 1;
	}

	if (remove(path) == 0 || (errno == ENOENT && missing_ok))
		rv = 0;
	else
		rv = -1;

	*path_ptr = path;

	return rv;
}

static int
recursive_remove_internal(const char *path, int missing_ok, int cwd)
{
	DIR *dir;
	struct dirent *de;
	const char *sub_path;
	char *subdir;
	int did_chdir, rv;

	/*
	 * If the argument is longer than PATH_MAX, long_remove
	 * will try to shorten it using chdir.  So before returning,
	 * make sure to fchdir back to the original cwd.
	 */
	sub_path = path;
	if (long_remove(&sub_path, missing_ok, &did_chdir) == 0)
		rv = 0;
	else if (errno != ENOTEMPTY) /* Other errors are terminal. */
		rv = -1;
	else
		rv = 1;

	if (rv != 1) {
		if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0)
			rv = -1;
		return rv;
	}

	if ((dir = opendir(sub_path)) == NULL) {
		if (errno == EMFILE)
			warn("opendir failed");
		return -1;
	}

	if (did_chdir && fchdir(cwd) == -1)
		return -1;

	rv = 0;

	while ((de = readdir(dir)) != NULL) {
		if (strcmp(de->d_name, ".") == 0)
			continue;
		if (strcmp(de->d_name, "..") == 0)
			continue;
		subdir = xasprintf("%s/%s", path, de->d_name);
		rv = recursive_remove_internal(subdir, 1, cwd);
		free(subdir);
	}

	closedir(dir);

	safe_fchdir(cwd);

	rv |= long_remove(&path, missing_ok, &did_chdir);

	if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0)
		rv = -1;

	return rv;
}

int
recursive_remove(const char *path, int missing_ok)
{
	int orig_cwd, rv;

	/* First try the easy case of regular file or empty directory. */
	if (remove(path) == 0 || (errno == ENOENT && missing_ok))
		return 0;

	/*
	 * If the path is too long, long_remove will use chdir to shorten it,
	 * so remember the current directory first.
	 */
	if ((orig_cwd = open(".", O_RDONLY)) == -1)
		return -1;

	rv = recursive_remove_internal(path, missing_ok, orig_cwd);

	close(orig_cwd);
	return rv;
}