1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License, Version 1.0 only 6168404Spjd * (the "License"). You may not use this file except in compliance 7168404Spjd * with the License. 8168404Spjd * 9168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10168404Spjd * or http://www.opensolaris.org/os/licensing. 11168404Spjd * See the License for the specific language governing permissions 12168404Spjd * and limitations under the License. 13168404Spjd * 14168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 15168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16168404Spjd * If applicable, add the following below this CDDL HEADER, with the 17168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 18168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 19168404Spjd * 20168404Spjd * CDDL HEADER END 21178414Sjb * 22178414Sjb * $FreeBSD$ 23168404Spjd */ 24168404Spjd 25168404Spjd/* Copyright (c) 1988 AT&T */ 26168404Spjd/* All Rights Reserved */ 27168404Spjd 28168404Spjd/* 29168404Spjd * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30168404Spjd * Use is subject to license terms. 31168404Spjd */ 32168404Spjd 33168404Spjd#pragma ident "@(#)mkdirp.c 1.15 06/01/04 SMI" 34168404Spjd 35168404Spjd/* 36168404Spjd * Creates directory and it's parents if the parents do not 37168404Spjd * exist yet. 38168404Spjd * 39168404Spjd * Returns -1 if fails for reasons other than non-existing 40168404Spjd * parents. 41168404Spjd * Does NOT simplify pathnames with . or .. in them. 42168404Spjd */ 43168404Spjd 44168404Spjd#include <sys/types.h> 45168404Spjd#include <libgen.h> 46168404Spjd#include <stdlib.h> 47168404Spjd#include <unistd.h> 48168404Spjd#include <errno.h> 49168404Spjd#include <string.h> 50168404Spjd#include <sys/stat.h> 51168404Spjd 52168404Spjdstatic char *simplify(const char *str); 53168404Spjd 54168404Spjdint 55168404Spjdmkdirp(const char *d, mode_t mode) 56168404Spjd{ 57168404Spjd char *endptr, *ptr, *slash, *str; 58168404Spjd 59168404Spjd str = simplify(d); 60168404Spjd 61168404Spjd /* If space couldn't be allocated for the simplified names, return. */ 62168404Spjd 63168404Spjd if (str == NULL) 64168404Spjd return (-1); 65168404Spjd 66168404Spjd /* Try to make the directory */ 67168404Spjd 68168404Spjd if (mkdir(str, mode) == 0) { 69168404Spjd free(str); 70168404Spjd return (0); 71168404Spjd } 72168404Spjd if (errno != ENOENT) { 73168404Spjd free(str); 74168404Spjd return (-1); 75168404Spjd } 76168404Spjd endptr = strrchr(str, '\0'); 77168404Spjd slash = strrchr(str, '/'); 78168404Spjd 79168404Spjd /* Search upward for the non-existing parent */ 80168404Spjd 81168404Spjd while (slash != NULL) { 82168404Spjd 83168404Spjd ptr = slash; 84168404Spjd *ptr = '\0'; 85168404Spjd 86168404Spjd /* If reached an existing parent, break */ 87168404Spjd 88168404Spjd if (access(str, F_OK) == 0) 89168404Spjd break; 90168404Spjd 91168404Spjd /* If non-existing parent */ 92168404Spjd 93168404Spjd else { 94168404Spjd slash = strrchr(str, '/'); 95168404Spjd 96168404Spjd /* If under / or current directory, make it. */ 97168404Spjd 98168404Spjd if (slash == NULL || slash == str) { 99168404Spjd if (mkdir(str, mode) != 0 && errno != EEXIST) { 100168404Spjd free(str); 101168404Spjd return (-1); 102168404Spjd } 103168404Spjd break; 104168404Spjd } 105168404Spjd } 106168404Spjd } 107168404Spjd 108168404Spjd /* Create directories starting from upmost non-existing parent */ 109168404Spjd 110168404Spjd while ((ptr = strchr(str, '\0')) != endptr) { 111168404Spjd *ptr = '/'; 112168404Spjd if (mkdir(str, mode) != 0 && errno != EEXIST) { 113168404Spjd /* 114168404Spjd * If the mkdir fails because str already 115168404Spjd * exists (EEXIST), then str has the form 116168404Spjd * "existing-dir/..", and this is really 117168404Spjd * ok. (Remember, this loop is creating the 118168404Spjd * portion of the path that didn't exist) 119168404Spjd */ 120168404Spjd free(str); 121168404Spjd return (-1); 122168404Spjd } 123168404Spjd } 124168404Spjd free(str); 125168404Spjd return (0); 126168404Spjd} 127168404Spjd 128168404Spjd/* 129168404Spjd * simplify - given a pathname, simplify that path by removing 130168404Spjd * duplicate contiguous slashes. 131168404Spjd * 132168404Spjd * A simplified copy of the argument is returned to the 133168404Spjd * caller, or NULL is returned on error. 134168404Spjd * 135168404Spjd * The caller should handle error reporting based upon the 136168404Spjd * returned vlaue, and should free the returned value, 137168404Spjd * when appropriate. 138168404Spjd */ 139168404Spjd 140168404Spjdstatic char * 141168404Spjdsimplify(const char *str) 142168404Spjd{ 143168404Spjd int i; 144168404Spjd size_t mbPathlen; /* length of multi-byte path */ 145168404Spjd size_t wcPathlen; /* length of wide-character path */ 146168404Spjd wchar_t *wptr; /* scratch pointer */ 147168404Spjd wchar_t *wcPath; /* wide-character version of the path */ 148168404Spjd char *mbPath; /* The copy fo the path to be returned */ 149168404Spjd 150168404Spjd /* 151168404Spjd * bail out if there is nothing there. 152168404Spjd */ 153168404Spjd 154168404Spjd if (!str) 155168404Spjd return (NULL); 156168404Spjd 157168404Spjd /* 158168404Spjd * Get a copy of the argument. 159168404Spjd */ 160168404Spjd 161168404Spjd if ((mbPath = strdup(str)) == NULL) { 162168404Spjd return (NULL); 163168404Spjd } 164168404Spjd 165168404Spjd /* 166168404Spjd * convert the multi-byte version of the path to a 167168404Spjd * wide-character rendering, for doing our figuring. 168168404Spjd */ 169168404Spjd 170168404Spjd mbPathlen = strlen(mbPath); 171168404Spjd 172168404Spjd if ((wcPath = calloc(sizeof (wchar_t), mbPathlen+1)) == NULL) { 173168404Spjd free(mbPath); 174168404Spjd return (NULL); 175168404Spjd } 176168404Spjd 177168404Spjd if ((wcPathlen = mbstowcs(wcPath, mbPath, mbPathlen)) == (size_t)-1) { 178168404Spjd free(mbPath); 179168404Spjd free(wcPath); 180168404Spjd return (NULL); 181168404Spjd } 182168404Spjd 183168404Spjd /* 184168404Spjd * remove duplicate slashes first ("//../" -> "/") 185168404Spjd */ 186168404Spjd 187168404Spjd for (wptr = wcPath, i = 0; i < wcPathlen; i++) { 188168404Spjd *wptr++ = wcPath[i]; 189168404Spjd 190168404Spjd if (wcPath[i] == '/') { 191168404Spjd i++; 192168404Spjd 193168404Spjd while (wcPath[i] == '/') { 194168404Spjd i++; 195168404Spjd } 196168404Spjd 197168404Spjd i--; 198168404Spjd } 199168404Spjd } 200168404Spjd 201168404Spjd *wptr = '\0'; 202168404Spjd 203168404Spjd /* 204168404Spjd * now convert back to the multi-byte format. 205168404Spjd */ 206168404Spjd 207168404Spjd if (wcstombs(mbPath, wcPath, mbPathlen) == (size_t)-1) { 208168404Spjd free(mbPath); 209168404Spjd free(wcPath); 210168404Spjd return (NULL); 211168404Spjd } 212168404Spjd 213168404Spjd free(wcPath); 214168404Spjd return (mbPath); 215168404Spjd} 216