1/* srm */ 2/* Copyright (c) 2000 Matthew D. Gauthier 3 * Portions copyright (c) 2007 Apple Inc. All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Except as contained in this notice, the name of the contributors shall 25 * not be used in advertising or otherwise to promote the sale, use or 26 * other dealings in this Software without prior written authorization. 27 */ 28 29#include <ctype.h> 30#include <dirent.h> 31#include <errno.h> 32#include <stdlib.h> 33#include <stdio.h> 34#include <string.h> 35#include <sys/stat.h> 36#include <unistd.h> 37 38#include <TargetConditionals.h> 39 40#include "removefile.h" 41#include "removefile_priv.h" 42 43static int empty_directory(const char *path) { 44 DIR *dp; 45 struct dirent *de; 46 47 dp = opendir(path); 48 if (dp == NULL) { 49 return -1; 50 } 51 while ((de = readdir(dp)) != NULL) { 52 if (de->d_namlen < 3 && (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))) { 53 continue; 54 } 55 (void)closedir(dp); 56 return -1; 57 } 58 (void)closedir(dp); 59 return 0; 60} 61 62int 63__removefile_rename_unlink(const char *path, removefile_state_t state) { 64 char *p, c; 65 struct stat statbuf; 66 67 size_t new_name_size = strlen(path) + 15; 68 char new_name[new_name_size]; 69 int i = 0; 70 71 strlcpy(new_name, path, new_name_size); 72 73 if ( (p = strrchr(new_name, '/')) != NULL ) { 74 p++; 75 *p = '\0'; 76 } else { 77 p = new_name; 78 } 79 80 do { 81 i = 0; 82 83 while (i < 14) { 84 c = __removefile_random_char(state); 85 if (isalnum((int) c)) { 86 p[i] = c; 87 i++; 88 } 89 } 90 p[i] = '\0'; 91 } while (lstat(new_name, &statbuf) == 0); 92 93 if (lstat(path, &statbuf) == -1) 94 return -1; 95 96 if (S_ISDIR(statbuf.st_mode) && (empty_directory(path) == -1)) { 97 /* Directory isn't empty (e.g. because it contains an immutable file). 98 Attempting to remove it will fail, so avoid renaming it. */ 99 errno = ENOTEMPTY; 100 return -1; 101 } 102 103 if (rename(path, new_name) == -1) 104 return -1; 105 106 if (lstat(new_name, &statbuf) == -1) { 107 errno = ENOENT; 108 return -1; 109 } 110 111 if (S_ISDIR(statbuf.st_mode)) 112 return rmdir(new_name); 113 114 return unlink(new_name); 115} 116