1*eda14cbcSMatt Macy /* 2*eda14cbcSMatt Macy * CDDL HEADER START 3*eda14cbcSMatt Macy * 4*eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5*eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6*eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7*eda14cbcSMatt Macy * 8*eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*eda14cbcSMatt Macy * or http://www.opensolaris.org/os/licensing. 10*eda14cbcSMatt Macy * See the License for the specific language governing permissions 11*eda14cbcSMatt Macy * and limitations under the License. 12*eda14cbcSMatt Macy * 13*eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14*eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16*eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17*eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18*eda14cbcSMatt Macy * 19*eda14cbcSMatt Macy * CDDL HEADER END 20*eda14cbcSMatt Macy */ 21*eda14cbcSMatt Macy 22*eda14cbcSMatt Macy /* 23*eda14cbcSMatt Macy * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*eda14cbcSMatt Macy * Use is subject to license terms. 25*eda14cbcSMatt Macy */ 26*eda14cbcSMatt Macy 27*eda14cbcSMatt Macy /* Copyright (c) 1988 AT&T */ 28*eda14cbcSMatt Macy /* All Rights Reserved */ 29*eda14cbcSMatt Macy 30*eda14cbcSMatt Macy /* 31*eda14cbcSMatt Macy * Creates directory and it's parents if the parents do not 32*eda14cbcSMatt Macy * exist yet. 33*eda14cbcSMatt Macy * 34*eda14cbcSMatt Macy * Returns -1 if fails for reasons other than non-existing 35*eda14cbcSMatt Macy * parents. 36*eda14cbcSMatt Macy * Does NOT simplify pathnames with . or .. in them. 37*eda14cbcSMatt Macy */ 38*eda14cbcSMatt Macy 39*eda14cbcSMatt Macy #include <sys/types.h> 40*eda14cbcSMatt Macy #include <libgen.h> 41*eda14cbcSMatt Macy #include <stdlib.h> 42*eda14cbcSMatt Macy #include <unistd.h> 43*eda14cbcSMatt Macy #include <errno.h> 44*eda14cbcSMatt Macy #include <string.h> 45*eda14cbcSMatt Macy #include <sys/stat.h> 46*eda14cbcSMatt Macy 47*eda14cbcSMatt Macy static char *simplify(const char *str); 48*eda14cbcSMatt Macy 49*eda14cbcSMatt Macy int 50*eda14cbcSMatt Macy mkdirp(const char *d, mode_t mode) 51*eda14cbcSMatt Macy { 52*eda14cbcSMatt Macy char *endptr, *ptr, *slash, *str; 53*eda14cbcSMatt Macy 54*eda14cbcSMatt Macy str = simplify(d); 55*eda14cbcSMatt Macy 56*eda14cbcSMatt Macy /* If space couldn't be allocated for the simplified names, return. */ 57*eda14cbcSMatt Macy 58*eda14cbcSMatt Macy if (str == NULL) 59*eda14cbcSMatt Macy return (-1); 60*eda14cbcSMatt Macy 61*eda14cbcSMatt Macy /* Try to make the directory */ 62*eda14cbcSMatt Macy 63*eda14cbcSMatt Macy if (mkdir(str, mode) == 0) { 64*eda14cbcSMatt Macy free(str); 65*eda14cbcSMatt Macy return (0); 66*eda14cbcSMatt Macy } 67*eda14cbcSMatt Macy if (errno != ENOENT) { 68*eda14cbcSMatt Macy free(str); 69*eda14cbcSMatt Macy return (-1); 70*eda14cbcSMatt Macy } 71*eda14cbcSMatt Macy endptr = strrchr(str, '\0'); 72*eda14cbcSMatt Macy slash = strrchr(str, '/'); 73*eda14cbcSMatt Macy 74*eda14cbcSMatt Macy /* Search upward for the non-existing parent */ 75*eda14cbcSMatt Macy 76*eda14cbcSMatt Macy while (slash != NULL) { 77*eda14cbcSMatt Macy 78*eda14cbcSMatt Macy ptr = slash; 79*eda14cbcSMatt Macy *ptr = '\0'; 80*eda14cbcSMatt Macy 81*eda14cbcSMatt Macy /* If reached an existing parent, break */ 82*eda14cbcSMatt Macy 83*eda14cbcSMatt Macy if (access(str, F_OK) == 0) 84*eda14cbcSMatt Macy break; 85*eda14cbcSMatt Macy 86*eda14cbcSMatt Macy /* If non-existing parent */ 87*eda14cbcSMatt Macy 88*eda14cbcSMatt Macy else { 89*eda14cbcSMatt Macy slash = strrchr(str, '/'); 90*eda14cbcSMatt Macy 91*eda14cbcSMatt Macy /* If under / or current directory, make it. */ 92*eda14cbcSMatt Macy 93*eda14cbcSMatt Macy if (slash == NULL || slash == str) { 94*eda14cbcSMatt Macy if (mkdir(str, mode) != 0 && errno != EEXIST) { 95*eda14cbcSMatt Macy free(str); 96*eda14cbcSMatt Macy return (-1); 97*eda14cbcSMatt Macy } 98*eda14cbcSMatt Macy break; 99*eda14cbcSMatt Macy } 100*eda14cbcSMatt Macy } 101*eda14cbcSMatt Macy } 102*eda14cbcSMatt Macy 103*eda14cbcSMatt Macy /* Create directories starting from upmost non-existing parent */ 104*eda14cbcSMatt Macy 105*eda14cbcSMatt Macy while ((ptr = strchr(str, '\0')) != endptr) { 106*eda14cbcSMatt Macy *ptr = '/'; 107*eda14cbcSMatt Macy if (mkdir(str, mode) != 0 && errno != EEXIST) { 108*eda14cbcSMatt Macy /* 109*eda14cbcSMatt Macy * If the mkdir fails because str already 110*eda14cbcSMatt Macy * exists (EEXIST), then str has the form 111*eda14cbcSMatt Macy * "existing-dir/..", and this is really 112*eda14cbcSMatt Macy * ok. (Remember, this loop is creating the 113*eda14cbcSMatt Macy * portion of the path that didn't exist) 114*eda14cbcSMatt Macy */ 115*eda14cbcSMatt Macy free(str); 116*eda14cbcSMatt Macy return (-1); 117*eda14cbcSMatt Macy } 118*eda14cbcSMatt Macy } 119*eda14cbcSMatt Macy free(str); 120*eda14cbcSMatt Macy return (0); 121*eda14cbcSMatt Macy } 122*eda14cbcSMatt Macy 123*eda14cbcSMatt Macy /* 124*eda14cbcSMatt Macy * simplify - given a pathname, simplify that path by removing 125*eda14cbcSMatt Macy * duplicate contiguous slashes. 126*eda14cbcSMatt Macy * 127*eda14cbcSMatt Macy * A simplified copy of the argument is returned to the 128*eda14cbcSMatt Macy * caller, or NULL is returned on error. 129*eda14cbcSMatt Macy * 130*eda14cbcSMatt Macy * The caller should handle error reporting based upon the 131*eda14cbcSMatt Macy * returned value, and should free the returned value, 132*eda14cbcSMatt Macy * when appropriate. 133*eda14cbcSMatt Macy */ 134*eda14cbcSMatt Macy 135*eda14cbcSMatt Macy static char * 136*eda14cbcSMatt Macy simplify(const char *str) 137*eda14cbcSMatt Macy { 138*eda14cbcSMatt Macy int i; 139*eda14cbcSMatt Macy size_t mbPathlen; /* length of multi-byte path */ 140*eda14cbcSMatt Macy size_t wcPathlen; /* length of wide-character path */ 141*eda14cbcSMatt Macy wchar_t *wptr; /* scratch pointer */ 142*eda14cbcSMatt Macy wchar_t *wcPath; /* wide-character version of the path */ 143*eda14cbcSMatt Macy char *mbPath; /* The copy fo the path to be returned */ 144*eda14cbcSMatt Macy 145*eda14cbcSMatt Macy /* 146*eda14cbcSMatt Macy * bail out if there is nothing there. 147*eda14cbcSMatt Macy */ 148*eda14cbcSMatt Macy 149*eda14cbcSMatt Macy if (!str) { 150*eda14cbcSMatt Macy errno = ENOENT; 151*eda14cbcSMatt Macy return (NULL); 152*eda14cbcSMatt Macy } 153*eda14cbcSMatt Macy 154*eda14cbcSMatt Macy /* 155*eda14cbcSMatt Macy * Get a copy of the argument. 156*eda14cbcSMatt Macy */ 157*eda14cbcSMatt Macy 158*eda14cbcSMatt Macy if ((mbPath = strdup(str)) == NULL) { 159*eda14cbcSMatt Macy return (NULL); 160*eda14cbcSMatt Macy } 161*eda14cbcSMatt Macy 162*eda14cbcSMatt Macy /* 163*eda14cbcSMatt Macy * convert the multi-byte version of the path to a 164*eda14cbcSMatt Macy * wide-character rendering, for doing our figuring. 165*eda14cbcSMatt Macy */ 166*eda14cbcSMatt Macy 167*eda14cbcSMatt Macy mbPathlen = strlen(mbPath); 168*eda14cbcSMatt Macy 169*eda14cbcSMatt Macy if ((wcPath = calloc(mbPathlen+1, sizeof (wchar_t))) == NULL) { 170*eda14cbcSMatt Macy free(mbPath); 171*eda14cbcSMatt Macy return (NULL); 172*eda14cbcSMatt Macy } 173*eda14cbcSMatt Macy 174*eda14cbcSMatt Macy if ((wcPathlen = mbstowcs(wcPath, mbPath, mbPathlen)) == (size_t)-1) { 175*eda14cbcSMatt Macy free(mbPath); 176*eda14cbcSMatt Macy free(wcPath); 177*eda14cbcSMatt Macy return (NULL); 178*eda14cbcSMatt Macy } 179*eda14cbcSMatt Macy 180*eda14cbcSMatt Macy /* 181*eda14cbcSMatt Macy * remove duplicate slashes first ("//../" -> "/") 182*eda14cbcSMatt Macy */ 183*eda14cbcSMatt Macy 184*eda14cbcSMatt Macy for (wptr = wcPath, i = 0; i < wcPathlen; i++) { 185*eda14cbcSMatt Macy *wptr++ = wcPath[i]; 186*eda14cbcSMatt Macy 187*eda14cbcSMatt Macy if (wcPath[i] == '/') { 188*eda14cbcSMatt Macy i++; 189*eda14cbcSMatt Macy 190*eda14cbcSMatt Macy while (wcPath[i] == '/') { 191*eda14cbcSMatt Macy i++; 192*eda14cbcSMatt Macy } 193*eda14cbcSMatt Macy 194*eda14cbcSMatt Macy i--; 195*eda14cbcSMatt Macy } 196*eda14cbcSMatt Macy } 197*eda14cbcSMatt Macy 198*eda14cbcSMatt Macy *wptr = '\0'; 199*eda14cbcSMatt Macy 200*eda14cbcSMatt Macy /* 201*eda14cbcSMatt Macy * now convert back to the multi-byte format. 202*eda14cbcSMatt Macy */ 203*eda14cbcSMatt Macy 204*eda14cbcSMatt Macy if (wcstombs(mbPath, wcPath, mbPathlen) == (size_t)-1) { 205*eda14cbcSMatt Macy free(mbPath); 206*eda14cbcSMatt Macy free(wcPath); 207*eda14cbcSMatt Macy return (NULL); 208*eda14cbcSMatt Macy } 209*eda14cbcSMatt Macy 210*eda14cbcSMatt Macy free(wcPath); 211*eda14cbcSMatt Macy return (mbPath); 212*eda14cbcSMatt Macy } 213