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 "ThreadLocalBuffer.h" 38 39 GLOBAL_INIT_THREAD_LOCAL_BUFFER(basename); 40 GLOBAL_INIT_THREAD_LOCAL_BUFFER(dirname); 41 42 char* basename(const char* path) { 43 LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, basename, MAXPATHLEN); 44 int rc = basename_r(path, basename_tls_buffer, basename_tls_buffer_size); 45 return (rc < 0) ? NULL : basename_tls_buffer; 46 } 47 48 char* dirname(const char* path) { 49 LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, dirname, MAXPATHLEN); 50 int rc = dirname_r(path, dirname_tls_buffer, dirname_tls_buffer_size); 51 return (rc < 0) ? NULL : dirname_tls_buffer; 52 } 53 54 int basename_r(const char* path, char* buffer, size_t buffer_size) { 55 const char* startp = NULL; 56 const char* endp = NULL; 57 int len; 58 int result; 59 60 // Empty or NULL string gets treated as ".". 61 if (path == NULL || *path == '\0') { 62 startp = "."; 63 len = 1; 64 goto Exit; 65 } 66 67 // Strip trailing slashes. 68 endp = path + strlen(path) - 1; 69 while (endp > path && *endp == '/') { 70 endp--; 71 } 72 73 // All slashes becomes "/". 74 if (endp == path && *endp == '/') { 75 startp = "/"; 76 len = 1; 77 goto Exit; 78 } 79 80 // Find the start of the base. 81 startp = endp; 82 while (startp > path && *(startp - 1) != '/') { 83 startp--; 84 } 85 86 len = endp - startp +1; 87 88 Exit: 89 result = len; 90 if (buffer == NULL) { 91 return result; 92 } 93 if (len > static_cast<int>(buffer_size) - 1) { 94 len = buffer_size - 1; 95 result = -1; 96 errno = ERANGE; 97 } 98 99 if (len >= 0) { 100 memcpy(buffer, startp, len); 101 buffer[len] = 0; 102 } 103 return result; 104 } 105 106 int dirname_r(const char* path, char* buffer, size_t buffer_size) { 107 const char* endp = NULL; 108 int len; 109 int result; 110 111 // Empty or NULL string gets treated as ".". 112 if (path == NULL || *path == '\0') { 113 path = "."; 114 len = 1; 115 goto Exit; 116 } 117 118 // Strip trailing slashes. 119 endp = path + strlen(path) - 1; 120 while (endp > path && *endp == '/') { 121 endp--; 122 } 123 124 // Find the start of the dir. 125 while (endp > path && *endp != '/') { 126 endp--; 127 } 128 129 // Either the dir is "/" or there are no slashes. 130 if (endp == path) { 131 path = (*endp == '/') ? "/" : "."; 132 len = 1; 133 goto Exit; 134 } 135 136 do { 137 endp--; 138 } while (endp > path && *endp == '/'); 139 140 len = endp - path + 1; 141 142 Exit: 143 result = len; 144 if (len + 1 > MAXPATHLEN) { 145 errno = ENAMETOOLONG; 146 return -1; 147 } 148 if (buffer == NULL) { 149 return result; 150 } 151 152 if (len > static_cast<int>(buffer_size) - 1) { 153 len = buffer_size - 1; 154 result = -1; 155 errno = ERANGE; 156 } 157 158 if (len >= 0) { 159 memcpy(buffer, path, len); 160 buffer[len] = 0; 161 } 162 return result; 163 } 164