210 lines
7.2 KiB
C
210 lines
7.2 KiB
C
|
/*
|
||
|
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify it
|
||
|
* under the terms of version 2 of the GNU General Public License as
|
||
|
* published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope that it would be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
*
|
||
|
* Further, this software is distributed without any warranty that it is
|
||
|
* free of the rightful claim of any third person regarding infringement
|
||
|
* or the like. Any license provided herein, whether implied or
|
||
|
* otherwise, applies only to this software file. Patent licenses, if
|
||
|
* any, provided herein do not apply to combinations of this program with
|
||
|
* other software, or any other product whatsoever.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License along
|
||
|
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||
|
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||
|
*
|
||
|
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
||
|
* Mountain View, CA 94043, or:
|
||
|
*
|
||
|
* http://www.sgi.com
|
||
|
*
|
||
|
* For further information regarding this notice, see:
|
||
|
*
|
||
|
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
|
||
|
*/
|
||
|
|
||
|
/**********************************************************
|
||
|
*
|
||
|
* OS Testing - Silicon Graphics, Inc.
|
||
|
*
|
||
|
* FUNCTION NAME : rmobj()
|
||
|
*
|
||
|
* FUNCTION TITLE : Remove an object
|
||
|
*
|
||
|
* SYNOPSIS:
|
||
|
* int rmobj(char *obj, char **errmsg)
|
||
|
*
|
||
|
* AUTHOR : Kent Rogers
|
||
|
*
|
||
|
* INITIAL RELEASE : UNICOS 7.0
|
||
|
*
|
||
|
* USER DESCRIPTION
|
||
|
* This routine will remove the specified object. If the specified
|
||
|
* object is a directory, it will recursively remove the directory
|
||
|
* and everything underneath it. It assumes that it has privilege
|
||
|
* to remove everything that it tries to remove. If rmobj() encounters
|
||
|
* any problems, and errmsg is not NULL, errmsg is set to point to a
|
||
|
* string explaining the error.
|
||
|
*
|
||
|
* DETAILED DESCRIPTION
|
||
|
* Allocate space for the directory and its contents
|
||
|
* Open the directory to get access to what is in it
|
||
|
* Loop through the objects in the directory:
|
||
|
* If the object is not "." or "..":
|
||
|
* Determine the file type by calling lstat()
|
||
|
* If the object is not a directory:
|
||
|
* Remove the object with unlink()
|
||
|
* Else:
|
||
|
* Call rmobj(object) to remove the object's contents
|
||
|
* Determine the link count on object by calling lstat()
|
||
|
* If the link count >= 3:
|
||
|
* Remove the directory with unlink()
|
||
|
* Else
|
||
|
* Remove the directory with rmdir()
|
||
|
* Close the directory and free the pointers
|
||
|
*
|
||
|
* RETURN VALUE
|
||
|
* If there are any problems, rmobj() will set errmsg (if it was not
|
||
|
* NULL) and return -1. Otherwise it will return 0.
|
||
|
*
|
||
|
************************************************************/
|
||
|
#include <errno.h> /* for errno */
|
||
|
#include <stdio.h> /* for NULL */
|
||
|
#include <stdlib.h> /* for malloc() */
|
||
|
#include <string.h> /* for string function */
|
||
|
#include <limits.h> /* for PATH_MAX */
|
||
|
#include <sys/types.h> /* for opendir(), readdir(), closedir(), stat() */
|
||
|
#include <sys/stat.h> /* for [l]stat() */
|
||
|
#include <dirent.h> /* for opendir(), readdir(), closedir() */
|
||
|
#include <unistd.h> /* for rmdir(), unlink() */
|
||
|
#include "rmobj.h"
|
||
|
|
||
|
#define SYSERR strerror(errno)
|
||
|
|
||
|
int
|
||
|
rmobj(char *obj, char **errmsg)
|
||
|
{
|
||
|
int ret_val = 0; /* return value from this routine */
|
||
|
DIR *dir; /* pointer to a directory */
|
||
|
struct dirent *dir_ent; /* pointer to directory entries */
|
||
|
char dirobj[PATH_MAX]; /* object inside directory to modify */
|
||
|
struct stat statbuf; /* used to hold stat information */
|
||
|
static char err_msg[1024]; /* error message */
|
||
|
|
||
|
/* Determine the file type */
|
||
|
if ( lstat(obj, &statbuf) < 0 ) {
|
||
|
if ( errmsg != NULL ) {
|
||
|
sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
|
||
|
obj, errno, SYSERR);
|
||
|
*errmsg = err_msg;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* Take appropriate action, depending on the file type */
|
||
|
if ( (statbuf.st_mode & S_IFMT) == S_IFDIR ) {
|
||
|
/* object is a directory */
|
||
|
|
||
|
/* Do NOT perform the request if the directory is "/" */
|
||
|
if ( !strcmp(obj, "/") ) {
|
||
|
if ( errmsg != NULL ) {
|
||
|
sprintf(err_msg, "Cannot remove /");
|
||
|
*errmsg = err_msg;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* Open the directory to get access to what is in it */
|
||
|
if ( (dir = opendir(obj)) == NULL ) {
|
||
|
if ( rmdir(obj) != 0 ) {
|
||
|
if ( errmsg != NULL ) {
|
||
|
sprintf(err_msg, "rmdir(%s) failed; errno=%d: %s",
|
||
|
obj, errno, SYSERR);
|
||
|
*errmsg = err_msg;
|
||
|
}
|
||
|
return -1;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Loop through the entries in the directory, removing each one */
|
||
|
for ( dir_ent = (struct dirent *)readdir(dir);
|
||
|
dir_ent != NULL;
|
||
|
dir_ent = (struct dirent *)readdir(dir)) {
|
||
|
|
||
|
/* Don't remove "." or ".." */
|
||
|
if ( !strcmp(dir_ent->d_name, ".") || !strcmp(dir_ent->d_name, "..") )
|
||
|
continue;
|
||
|
|
||
|
/* Recursively call this routine to remove the current entry */
|
||
|
sprintf(dirobj, "%s/%s", obj, dir_ent->d_name);
|
||
|
if ( rmobj(dirobj, errmsg) != 0 )
|
||
|
ret_val = -1;
|
||
|
}
|
||
|
|
||
|
/* Close the directory */
|
||
|
closedir(dir);
|
||
|
|
||
|
/* If there were problems removing an entry, don't attempt to
|
||
|
remove the directory itself */
|
||
|
if ( ret_val == -1 )
|
||
|
return -1;
|
||
|
|
||
|
/* Get the link count, now that all the entries have been removed */
|
||
|
if ( lstat(obj, &statbuf) < 0 ) {
|
||
|
if ( errmsg != NULL ) {
|
||
|
sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
|
||
|
obj, errno, SYSERR);
|
||
|
*errmsg = err_msg;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* Remove the directory itself */
|
||
|
if ( statbuf.st_nlink >= 3 ) {
|
||
|
/* The directory is linked; unlink() must be used */
|
||
|
if ( unlink(obj) < 0 ) {
|
||
|
if ( errmsg != NULL ) {
|
||
|
sprintf(err_msg, "unlink(%s) failed; errno=%d: %s",
|
||
|
obj, errno, SYSERR);
|
||
|
*errmsg = err_msg;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
} else {
|
||
|
/* The directory is not linked; rmdir() can be used */
|
||
|
if ( rmdir(obj) < 0 ) {
|
||
|
if ( errmsg != NULL ) {
|
||
|
sprintf(err_msg, "remove(%s) failed; errno=%d: %s",
|
||
|
obj, errno, SYSERR);
|
||
|
*errmsg = err_msg;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
/* object is not a directory; just use unlink() */
|
||
|
if ( unlink(obj) < 0 ) {
|
||
|
if ( errmsg != NULL ) {
|
||
|
sprintf(err_msg, "unlink(%s) failed; errno=%d: %s",
|
||
|
obj, errno, SYSERR);
|
||
|
*errmsg = err_msg;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
} /* if obj is a directory */
|
||
|
|
||
|
/*
|
||
|
* Everything must have went ok.
|
||
|
*/
|
||
|
return 0;
|
||
|
} /* rmobj() */
|