make vfs & filesystems use failable copying
[minix3.git] / test / ipc / lib / rmobj.c
blob33786bd5a8391de09d36c07c1530c1d4cf4777bd
1 /*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
26 * http://www.sgi.com
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
33 /**********************************************************
35 * OS Testing - Silicon Graphics, Inc.
37 * FUNCTION NAME : rmobj()
39 * FUNCTION TITLE : Remove an object
41 * SYNOPSIS:
42 * int rmobj(char *obj, char **errmsg)
44 * AUTHOR : Kent Rogers
46 * INITIAL RELEASE : UNICOS 7.0
48 * USER DESCRIPTION
49 * This routine will remove the specified object. If the specified
50 * object is a directory, it will recursively remove the directory
51 * and everything underneath it. It assumes that it has privilege
52 * to remove everything that it tries to remove. If rmobj() encounters
53 * any problems, and errmsg is not NULL, errmsg is set to point to a
54 * string explaining the error.
56 * DETAILED DESCRIPTION
57 * Allocate space for the directory and its contents
58 * Open the directory to get access to what is in it
59 * Loop through the objects in the directory:
60 * If the object is not "." or "..":
61 * Determine the file type by calling lstat()
62 * If the object is not a directory:
63 * Remove the object with unlink()
64 * Else:
65 * Call rmobj(object) to remove the object's contents
66 * Determine the link count on object by calling lstat()
67 * If the link count >= 3:
68 * Remove the directory with unlink()
69 * Else
70 * Remove the directory with rmdir()
71 * Close the directory and free the pointers
73 * RETURN VALUE
74 * If there are any problems, rmobj() will set errmsg (if it was not
75 * NULL) and return -1. Otherwise it will return 0.
77 ************************************************************/
78 #include <errno.h> /* for errno */
79 #include <stdio.h> /* for NULL */
80 #include <stdlib.h> /* for malloc() */
81 #include <string.h> /* for string function */
82 #include <limits.h> /* for PATH_MAX */
83 #include <sys/types.h> /* for opendir(), readdir(), closedir(), stat() */
84 #include <sys/stat.h> /* for [l]stat() */
85 #include <dirent.h> /* for opendir(), readdir(), closedir() */
86 #include <unistd.h> /* for rmdir(), unlink() */
87 #include "rmobj.h"
89 #define SYSERR strerror(errno)
91 int
92 rmobj(char *obj, char **errmsg)
94 int ret_val = 0; /* return value from this routine */
95 DIR *dir; /* pointer to a directory */
96 struct dirent *dir_ent; /* pointer to directory entries */
97 char dirobj[PATH_MAX]; /* object inside directory to modify */
98 struct stat statbuf; /* used to hold stat information */
99 static char err_msg[1024]; /* error message */
101 /* Determine the file type */
102 if ( lstat(obj, &statbuf) < 0 ) {
103 if ( errmsg != NULL ) {
104 sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
105 obj, errno, SYSERR);
106 *errmsg = err_msg;
108 return -1;
111 /* Take appropriate action, depending on the file type */
112 if ( (statbuf.st_mode & S_IFMT) == S_IFDIR ) {
113 /* object is a directory */
115 /* Do NOT perform the request if the directory is "/" */
116 if ( !strcmp(obj, "/") ) {
117 if ( errmsg != NULL ) {
118 sprintf(err_msg, "Cannot remove /");
119 *errmsg = err_msg;
121 return -1;
124 /* Open the directory to get access to what is in it */
125 if ( (dir = opendir(obj)) == NULL ) {
126 if ( rmdir(obj) != 0 ) {
127 if ( errmsg != NULL ) {
128 sprintf(err_msg, "rmdir(%s) failed; errno=%d: %s",
129 obj, errno, SYSERR);
130 *errmsg = err_msg;
132 return -1;
133 } else {
134 return 0;
138 /* Loop through the entries in the directory, removing each one */
139 for ( dir_ent = (struct dirent *)readdir(dir);
140 dir_ent != NULL;
141 dir_ent = (struct dirent *)readdir(dir)) {
143 /* Don't remove "." or ".." */
144 if ( !strcmp(dir_ent->d_name, ".") || !strcmp(dir_ent->d_name, "..") )
145 continue;
147 /* Recursively call this routine to remove the current entry */
148 sprintf(dirobj, "%s/%s", obj, dir_ent->d_name);
149 if ( rmobj(dirobj, errmsg) != 0 )
150 ret_val = -1;
153 /* Close the directory */
154 closedir(dir);
156 /* If there were problems removing an entry, don't attempt to
157 remove the directory itself */
158 if ( ret_val == -1 )
159 return -1;
161 /* Get the link count, now that all the entries have been removed */
162 if ( lstat(obj, &statbuf) < 0 ) {
163 if ( errmsg != NULL ) {
164 sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
165 obj, errno, SYSERR);
166 *errmsg = err_msg;
168 return -1;
171 /* Remove the directory itself */
172 if ( statbuf.st_nlink >= 3 ) {
173 /* The directory is linked; unlink() must be used */
174 if ( unlink(obj) < 0 ) {
175 if ( errmsg != NULL ) {
176 sprintf(err_msg, "unlink(%s) failed; errno=%d: %s",
177 obj, errno, SYSERR);
178 *errmsg = err_msg;
180 return -1;
182 } else {
183 /* The directory is not linked; rmdir() can be used */
184 if ( rmdir(obj) < 0 ) {
185 if ( errmsg != NULL ) {
186 sprintf(err_msg, "remove(%s) failed; errno=%d: %s",
187 obj, errno, SYSERR);
188 *errmsg = err_msg;
190 return -1;
193 } else {
194 /* object is not a directory; just use unlink() */
195 if ( unlink(obj) < 0 ) {
196 if ( errmsg != NULL ) {
197 sprintf(err_msg, "unlink(%s) failed; errno=%d: %s",
198 obj, errno, SYSERR);
199 *errmsg = err_msg;
201 return -1;
203 } /* if obj is a directory */
206 * Everything must have went ok.
208 return 0;
209 } /* rmobj() */