1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <libgen.h> 30 31 #include <errno.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <sys/cdefs.h> 35 #include <sys/param.h> 36 37 #include "bionic/pthread_internal.h" 38 39 static int __basename_r(const char* path, char* buffer, size_t buffer_size) { 40 const char* startp = NULL; 41 const char* endp = NULL; 42 int len; 43 int result; 44 45 // Empty or NULL string gets treated as ".". 46 if (path == NULL || *path == '\0') { 47 startp = "."; 48 len = 1; 49 goto Exit; 50 } 51 52 // Strip trailing slashes. 53 endp = path + strlen(path) - 1; 54 while (endp > path && *endp == '/') { 55 endp--; 56 } 57 58 // All slashes becomes "/". 59 if (endp == path && *endp == '/') { 60 startp = "/"; 61 len = 1; 62 goto Exit; 63 } 64 65 // Find the start of the base. 66 startp = endp; 67 while (startp > path && *(startp - 1) != '/') { 68 startp--; 69 } 70 71 len = endp - startp +1; 72 73 Exit: 74 result = len; 75 if (buffer == NULL) { 76 return result; 77 } 78 if (len > static_cast<int>(buffer_size) - 1) { 79 len = buffer_size - 1; 80 result = -1; 81 errno = ERANGE; 82 } 83 84 if (len >= 0) { 85 memcpy(buffer, startp, len); 86 buffer[len] = 0; 87 } 88 return result; 89 } 90 91 // Since this is a non-standard symbol, it might be hijacked by a basename_r in the executable. 92 __LIBC32_LEGACY_PUBLIC__ int basename_r(const char* path, char* buffer, size_t buffer_size) { 93 return __basename_r(path, buffer, buffer_size); 94 } 95 96 static int __dirname_r(const char* path, char* buffer, size_t buffer_size) { 97 const char* endp = NULL; 98 int len; 99 int result; 100 101 // Empty or NULL string gets treated as ".". 102 if (path == NULL || *path == '\0') { 103 path = "."; 104 len = 1; 105 goto Exit; 106 } 107 108 // Strip trailing slashes. 109 endp = path + strlen(path) - 1; 110 while (endp > path && *endp == '/') { 111 endp--; 112 } 113 114 // Find the start of the dir. 115 while (endp > path && *endp != '/') { 116 endp--; 117 } 118 119 // Either the dir is "/" or there are no slashes. 120 if (endp == path) { 121 path = (*endp == '/') ? "/" : "."; 122 len = 1; 123 goto Exit; 124 } 125 126 do { 127 endp--; 128 } while (endp > path && *endp == '/'); 129 130 len = endp - path + 1; 131 132 Exit: 133 result = len; 134 if (len + 1 > MAXPATHLEN) { 135 errno = ENAMETOOLONG; 136 return -1; 137 } 138 if (buffer == NULL) { 139 return result; 140 } 141 142 if (len > static_cast<int>(buffer_size) - 1) { 143 len = buffer_size - 1; 144 result = -1; 145 errno = ERANGE; 146 } 147 148 if (len >= 0) { 149 memcpy(buffer, path, len); 150 buffer[len] = 0; 151 } 152 return result; 153 } 154 155 // Since this is a non-standard symbol, it might be hijacked by a basename_r in the executable. 156 __LIBC32_LEGACY_PUBLIC__ int dirname_r(const char* path, char* buffer, size_t buffer_size) { 157 return __dirname_r(path, buffer, buffer_size); 158 } 159 160 char* basename(const char* path) { 161 char* buf = __get_bionic_tls().basename_buf; 162 int rc = __basename_r(path, buf, sizeof(__get_bionic_tls().basename_buf)); 163 return (rc < 0) ? NULL : buf; 164 } 165 166 char* dirname(const char* path) { 167 char* buf = __get_bionic_tls().dirname_buf; 168 int rc = __dirname_r(path, buf, sizeof(__get_bionic_tls().dirname_buf)); 169 return (rc < 0) ? NULL : buf; 170 } 171