| /* |
| * 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., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. |
| * |
| ************************************************************/ |
| #define _GNU_SOURCE |
| #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 <fcntl.h> |
| #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 */ |
| int fd; |
| |
| /* Determine the file type */ |
| |
| fd = open(obj, O_DIRECTORY | O_NOFOLLOW); |
| if (fd != -1) { |
| close(fd); |
| /* 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() */ |