/* * 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/ */ /* $Id: rmobj.c,v 1.5 2009/07/20 10:59:32 vapier Exp $ */ /********************************************************** * * 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 /* for errno */ #include /* for NULL */ #include /* for malloc() */ #include /* for string function */ #include /* for PATH_MAX */ #include /* for opendir(), readdir(), closedir(), stat() */ #include /* for [l]stat() */ #include /* for opendir(), readdir(), closedir() */ #include /* 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; remove() can be used */ if (remove(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() */