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 "private/ThreadLocalBuffer.h" 38 39 __LIBC64_HIDDEN__ 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 __LIBC64_HIDDEN__ int dirname_r(const char* path, char* buffer, size_t buffer_size) { 92 const char* endp = NULL; 93 int len; 94 int result; 95 96 // Empty or NULL string gets treated as ".". 97 if (path == NULL || *path == '\0') { 98 path = "."; 99 len = 1; 100 goto Exit; 101 } 102 103 // Strip trailing slashes. 104 endp = path + strlen(path) - 1; 105 while (endp > path && *endp == '/') { 106 endp--; 107 } 108 109 // Find the start of the dir. 110 while (endp > path && *endp != '/') { 111 endp--; 112 } 113 114 // Either the dir is "/" or there are no slashes. 115 if (endp == path) { 116 path = (*endp == '/') ? "/" : "."; 117 len = 1; 118 goto Exit; 119 } 120 121 do { 122 endp--; 123 } while (endp > path && *endp == '/'); 124 125 len = endp - path + 1; 126 127 Exit: 128 result = len; 129 if (len + 1 > MAXPATHLEN) { 130 errno = ENAMETOOLONG; 131 return -1; 132 } 133 if (buffer == NULL) { 134 return result; 135 } 136 137 if (len > static_cast<int>(buffer_size) - 1) { 138 len = buffer_size - 1; 139 result = -1; 140 errno = ERANGE; 141 } 142 143 if (len >= 0) { 144 memcpy(buffer, path, len); 145 buffer[len] = 0; 146 } 147 return result; 148 } 149 150 GLOBAL_INIT_THREAD_LOCAL_BUFFER(basename); 151 GLOBAL_INIT_THREAD_LOCAL_BUFFER(dirname); 152 153 char* basename(const char* path) { 154 LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, basename, MAXPATHLEN); 155 int rc = basename_r(path, basename_tls_buffer, basename_tls_buffer_size); 156 return (rc < 0) ? NULL : basename_tls_buffer; 157 } 158 159 char* dirname(const char* path) { 160 LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, dirname, MAXPATHLEN); 161 int rc = dirname_r(path, dirname_tls_buffer, dirname_tls_buffer_size); 162 return (rc < 0) ? NULL : dirname_tls_buffer; 163 } 164