1/* Work around rmdir bugs. 2 3 Copyright (C) 1988, 1990, 1999, 2003-2006, 2009-2010 Free Software 4 Foundation, Inc. 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19#include <config.h> 20 21#include <unistd.h> 22 23#include <errno.h> 24#include <string.h> 25#include <sys/stat.h> 26#include <sys/types.h> 27 28#undef rmdir 29 30/* Remove directory DIR. 31 Return 0 if successful, -1 if not. */ 32 33int 34rpl_rmdir (char const *dir) 35{ 36#if HAVE_RMDIR 37 /* Work around cygwin 1.5.x bug where rmdir("dir/./") succeeds. */ 38 size_t len = strlen (dir); 39 int result; 40 while (len && ISSLASH (dir[len - 1])) 41 len--; 42 if (len && dir[len - 1] == '.' && (1 == len || ISSLASH (dir[len - 2]))) 43 { 44 errno = EINVAL; 45 return -1; 46 } 47 result = rmdir (dir); 48 /* Work around mingw bug, where rmdir("file/") fails with EINVAL 49 instead of ENOTDIR. We've already filtered out trailing ., the 50 only reason allowed by POSIX for EINVAL. */ 51 if (result == -1 && errno == EINVAL) 52 errno = ENOTDIR; 53 return result; 54 55#else /* !HAVE_RMDIR */ 56 /* rmdir adapted from GNU tar. FIXME: Delete this implementation in 57 2010 if no one reports a system with missing rmdir. */ 58 pid_t cpid; 59 int status; 60 struct stat statbuf; 61 62 if (stat (dir, &statbuf) != 0) 63 return -1; /* errno already set */ 64 65 if (!S_ISDIR (statbuf.st_mode)) 66 { 67 errno = ENOTDIR; 68 return -1; 69 } 70 71 cpid = fork (); 72 switch (cpid) 73 { 74 case -1: /* cannot fork */ 75 return -1; /* errno already set */ 76 77 case 0: /* child process */ 78 execl ("/bin/rmdir", "rmdir", dir, (char *) 0); 79 _exit (1); 80 81 default: /* parent process */ 82 83 /* Wait for kid to finish. */ 84 85 while (wait (&status) != cpid) 86 /* Do nothing. */ ; 87 88 if (status) 89 { 90 91 /* /bin/rmdir failed. */ 92 93 errno = EIO; 94 return -1; 95 } 96 return 0; 97 } 98#endif /* !HAVE_RMDIR */ 99} 100