17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*a77d64afScf46844 23*a77d64afScf46844 /* 24*a77d64afScf46844 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25*a77d64afScf46844 * Use is subject to license terms. 26*a77d64afScf46844 */ 27*a77d64afScf46844 287c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 297c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 307c478bd9Sstevel@tonic-gate /* */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * make directory. 367c478bd9Sstevel@tonic-gate * If -m is used with a valid mode, directories will be 377c478bd9Sstevel@tonic-gate * created in that mode. Otherwise, the default mode will 387c478bd9Sstevel@tonic-gate * be 777 possibly altered by the process's file mode creation 397c478bd9Sstevel@tonic-gate * mask. 407c478bd9Sstevel@tonic-gate * If -p is used, make the directory as well as 417c478bd9Sstevel@tonic-gate * its non-existing parent directories. 427c478bd9Sstevel@tonic-gate */ 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <signal.h> 457c478bd9Sstevel@tonic-gate #include <stdio.h> 467c478bd9Sstevel@tonic-gate #include <sys/types.h> 477c478bd9Sstevel@tonic-gate #include <sys/stat.h> 487c478bd9Sstevel@tonic-gate #include <errno.h> 497c478bd9Sstevel@tonic-gate #include <string.h> 507c478bd9Sstevel@tonic-gate #include <locale.h> 517c478bd9Sstevel@tonic-gate #include <stdlib.h> 527c478bd9Sstevel@tonic-gate #include <unistd.h> 537c478bd9Sstevel@tonic-gate #include <libgen.h> 547c478bd9Sstevel@tonic-gate #include <stdarg.h> 557c478bd9Sstevel@tonic-gate #include <wchar.h> 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate #define MSGEXISTS "\"%s\": Exists but is not a directory\n" 587c478bd9Sstevel@tonic-gate #define MSGUSAGE "usage: mkdir [-m mode] [-p] dirname ...\n" 597c478bd9Sstevel@tonic-gate #define MSGFMT1 "\"%s\": %s\n" 607c478bd9Sstevel@tonic-gate #define MSGFAILED "Failed to make directory \"%s\"; %s\n" 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate extern int optind, errno; 637c478bd9Sstevel@tonic-gate extern char *optarg; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate static char 667c478bd9Sstevel@tonic-gate *simplify(char *path); 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate void 697c478bd9Sstevel@tonic-gate errmsg(int severity, int code, char *format, ...); 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate extern mode_t 727c478bd9Sstevel@tonic-gate newmode(char *ms, mode_t new_mode, mode_t umsk, char *file, char *path); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #define ALLRWX (S_IRWXU | S_IRWXG | S_IRWXO) 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate 77*a77d64afScf46844 int 787c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate int pflag, errflg, mflag; 817c478bd9Sstevel@tonic-gate int c, local_errno, tmp_errno; 827c478bd9Sstevel@tonic-gate mode_t cur_umask; 837c478bd9Sstevel@tonic-gate mode_t mode; 847c478bd9Sstevel@tonic-gate mode_t modediff; 857c478bd9Sstevel@tonic-gate char *d; 867c478bd9Sstevel@tonic-gate struct stat buf; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate pflag = mflag = errflg = 0; 897c478bd9Sstevel@tonic-gate local_errno = 0; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 947c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 957c478bd9Sstevel@tonic-gate #endif 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate cur_umask = umask(0); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate mode = ALLRWX; 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "m:p")) != EOF) { 1047c478bd9Sstevel@tonic-gate switch (c) { 1057c478bd9Sstevel@tonic-gate case 'm': 1067c478bd9Sstevel@tonic-gate mflag++; 1077c478bd9Sstevel@tonic-gate mode = newmode(optarg, ALLRWX, cur_umask, "", ""); 1087c478bd9Sstevel@tonic-gate break; 1097c478bd9Sstevel@tonic-gate case 'p': 1107c478bd9Sstevel@tonic-gate pflag++; 1117c478bd9Sstevel@tonic-gate break; 1127c478bd9Sstevel@tonic-gate case '?': 1137c478bd9Sstevel@tonic-gate errflg++; 1147c478bd9Sstevel@tonic-gate break; 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * When using default ACLs, mkdir() should be called with 1217c478bd9Sstevel@tonic-gate * 0777 always; and umask or default ACL should do the work. 1227c478bd9Sstevel@tonic-gate * Because of the POSIX.2 requirement that the 1237c478bd9Sstevel@tonic-gate * intermediate mode be at least -wx------, 1247c478bd9Sstevel@tonic-gate * we do some trickery here. 1257c478bd9Sstevel@tonic-gate * 1267c478bd9Sstevel@tonic-gate * If pflag is not set, we can just leave the umask as 1277c478bd9Sstevel@tonic-gate * it the user specified it, unless it masks any of bits 0300. 1287c478bd9Sstevel@tonic-gate */ 1297c478bd9Sstevel@tonic-gate if (pflag) { 1307c478bd9Sstevel@tonic-gate modediff = cur_umask & (S_IXUSR | S_IWUSR); 1317c478bd9Sstevel@tonic-gate if (modediff) 1327c478bd9Sstevel@tonic-gate cur_umask &= ~modediff; 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate (void) umask(cur_umask); 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate argc -= optind; 1377c478bd9Sstevel@tonic-gate if (argc < 1 || errflg) { 1387c478bd9Sstevel@tonic-gate errmsg(0, 2, gettext(MSGUSAGE)); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate argv = &argv[optind]; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate errno = 0; 1437c478bd9Sstevel@tonic-gate while (argc--) { 1447c478bd9Sstevel@tonic-gate if ((d = simplify(*argv++)) == NULL) { 1457c478bd9Sstevel@tonic-gate exit(2); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * When -p is set, invokes mkdirp library routine. 1507c478bd9Sstevel@tonic-gate * Although successfully invoked, mkdirp sets errno to ENOENT 1517c478bd9Sstevel@tonic-gate * if one of the directory in the pathname does not exist, 1527c478bd9Sstevel@tonic-gate * thus creates a confusion on success/failure status 1537c478bd9Sstevel@tonic-gate * possibly checked by the calling routine or shell. 1547c478bd9Sstevel@tonic-gate * Therefore, errno is reset only when 1557c478bd9Sstevel@tonic-gate * mkdirp has executed successfully, otherwise save 1567c478bd9Sstevel@tonic-gate * in local_errno. 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate if (pflag) { 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * POSIX.2 says that it is not an error if 1617c478bd9Sstevel@tonic-gate * the argument names an existing directory. 1627c478bd9Sstevel@tonic-gate * We will, however, complain if the argument 1637c478bd9Sstevel@tonic-gate * exists but is not a directory. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate if (lstat(d, &buf) != -1) { 1667c478bd9Sstevel@tonic-gate if (S_ISDIR(buf.st_mode)) { 1677c478bd9Sstevel@tonic-gate continue; 1687c478bd9Sstevel@tonic-gate } else { 1697c478bd9Sstevel@tonic-gate local_errno = EEXIST; 1707c478bd9Sstevel@tonic-gate errmsg(0, 0, gettext(MSGEXISTS), d); 1717c478bd9Sstevel@tonic-gate continue; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate errno = 0; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if (mkdirp(d, ALLRWX) < 0) { 1777c478bd9Sstevel@tonic-gate tmp_errno = errno; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if (tmp_errno == EEXIST) { 1807c478bd9Sstevel@tonic-gate if (lstat(d, &buf) != -1) { 1817c478bd9Sstevel@tonic-gate if (! S_ISDIR(buf.st_mode)) { 1827c478bd9Sstevel@tonic-gate local_errno = 1837c478bd9Sstevel@tonic-gate tmp_errno; 1847c478bd9Sstevel@tonic-gate errmsg(0, 0, gettext( 1857c478bd9Sstevel@tonic-gate MSGEXISTS), d); 1867c478bd9Sstevel@tonic-gate continue; 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate /* S_ISDIR: do nothing */ 1897c478bd9Sstevel@tonic-gate } else { 1907c478bd9Sstevel@tonic-gate local_errno = tmp_errno; 1917c478bd9Sstevel@tonic-gate perror("mkdir"); 1927c478bd9Sstevel@tonic-gate errmsg(0, 0, 1937c478bd9Sstevel@tonic-gate gettext(MSGFAILED), d, 1947c478bd9Sstevel@tonic-gate strerror(local_errno)); 1957c478bd9Sstevel@tonic-gate continue; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate } else { 1987c478bd9Sstevel@tonic-gate local_errno = tmp_errno; 1997c478bd9Sstevel@tonic-gate errmsg(0, 0, gettext(MSGFMT1), d, 2007c478bd9Sstevel@tonic-gate strerror(tmp_errno)); 2017c478bd9Sstevel@tonic-gate continue; 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate errno = 0; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * get the file mode for the newly 2097c478bd9Sstevel@tonic-gate * created directory and test for 2107c478bd9Sstevel@tonic-gate * set gid bit being inherited from the parent 2117c478bd9Sstevel@tonic-gate * directory to include it with the file 2127c478bd9Sstevel@tonic-gate * mode creation for the last directory 2137c478bd9Sstevel@tonic-gate * on the dir path. 2147c478bd9Sstevel@tonic-gate * 2157c478bd9Sstevel@tonic-gate * This is only needed if mflag was specified 2167c478bd9Sstevel@tonic-gate * or if the umask was adjusted with -wx----- 2177c478bd9Sstevel@tonic-gate * 2187c478bd9Sstevel@tonic-gate * If mflag is specified, we chmod to the specified 2197c478bd9Sstevel@tonic-gate * mode, oring in the 02000 bit. 2207c478bd9Sstevel@tonic-gate * 2217c478bd9Sstevel@tonic-gate * If modediff is set, those bits need to be 2227c478bd9Sstevel@tonic-gate * removed from the last directory component, 2237c478bd9Sstevel@tonic-gate * all other bits are kept regardless of umask 2247c478bd9Sstevel@tonic-gate * in case a default ACL is present. 2257c478bd9Sstevel@tonic-gate */ 2267c478bd9Sstevel@tonic-gate if (mflag || modediff) { 2277c478bd9Sstevel@tonic-gate mode_t tmpmode; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate (void) lstat(d, &buf); 2307c478bd9Sstevel@tonic-gate if (modediff && !mflag) 2317c478bd9Sstevel@tonic-gate tmpmode = (buf.st_mode & 07777) 2327c478bd9Sstevel@tonic-gate & ~modediff; 2337c478bd9Sstevel@tonic-gate else 2347c478bd9Sstevel@tonic-gate tmpmode = mode | (buf.st_mode & 02000); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate if (chmod(d, tmpmode) < 0) { 2377c478bd9Sstevel@tonic-gate tmp_errno = errno; 2387c478bd9Sstevel@tonic-gate local_errno = errno; 2397c478bd9Sstevel@tonic-gate errmsg(0, 0, gettext(MSGFMT1), d, 2407c478bd9Sstevel@tonic-gate strerror(tmp_errno)); 2417c478bd9Sstevel@tonic-gate continue; 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate errno = 0; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate continue; 2477c478bd9Sstevel@tonic-gate } else { 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * No -p. Make only one directory 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate errno = 0; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (mkdir(d, mode) < 0) { 2557c478bd9Sstevel@tonic-gate local_errno = tmp_errno = errno; 2567c478bd9Sstevel@tonic-gate errmsg(0, 0, gettext(MSGFAILED), d, 2577c478bd9Sstevel@tonic-gate strerror(tmp_errno)); 2587c478bd9Sstevel@tonic-gate continue; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate if (mflag) { 2617c478bd9Sstevel@tonic-gate mode_t tmpmode; 2627c478bd9Sstevel@tonic-gate (void) lstat(d, &buf); 2637c478bd9Sstevel@tonic-gate tmpmode = mode | (buf.st_mode & 02000); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if (chmod(d, tmpmode) < 0) { 2667c478bd9Sstevel@tonic-gate tmp_errno = errno; 2677c478bd9Sstevel@tonic-gate local_errno = errno; 2687c478bd9Sstevel@tonic-gate errmsg(0, 0, gettext(MSGFMT1), d, 2697c478bd9Sstevel@tonic-gate strerror(tmp_errno)); 2707c478bd9Sstevel@tonic-gate continue; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate errno = 0; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } /* end while */ 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate /* When pflag is set, the errno is saved in local_errno */ 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if (local_errno) 2807c478bd9Sstevel@tonic-gate errno = local_errno; 281*a77d64afScf46844 return (errno ? 2: 0); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * errmsg - This is an interface required by the code common to mkdir and 2867c478bd9Sstevel@tonic-gate * chmod. The severity parameter is ignored here, but is meaningful 2877c478bd9Sstevel@tonic-gate * to chmod. 2887c478bd9Sstevel@tonic-gate */ 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2917c478bd9Sstevel@tonic-gate /* PRINTFLIKE3 */ 2927c478bd9Sstevel@tonic-gate void 2937c478bd9Sstevel@tonic-gate errmsg(int severity, int code, char *format, ...) 2947c478bd9Sstevel@tonic-gate { 2957c478bd9Sstevel@tonic-gate va_list ap; 2967c478bd9Sstevel@tonic-gate va_start(ap, format); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "mkdir: "); 2997c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate va_end(ap); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if (code > 0) { 3047c478bd9Sstevel@tonic-gate exit(code); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * simplify - given a pathname in a writable buffer, simplify that 3107c478bd9Sstevel@tonic-gate * path by removing meaningless occurances of path 3117c478bd9Sstevel@tonic-gate * syntax. 3127c478bd9Sstevel@tonic-gate * 3137c478bd9Sstevel@tonic-gate * The change happens in place in the argument. The 3147c478bd9Sstevel@tonic-gate * result is neceassarily no longer than the original. 3157c478bd9Sstevel@tonic-gate * 3167c478bd9Sstevel@tonic-gate * Return the pointer supplied by the caller on success, or 3177c478bd9Sstevel@tonic-gate * NULL on error. 3187c478bd9Sstevel@tonic-gate * 3197c478bd9Sstevel@tonic-gate * The caller should handle error reporting based upon the 3207c478bd9Sstevel@tonic-gate * returned vlaue. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate static char * 3247c478bd9Sstevel@tonic-gate simplify(char *mbPath) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate int i; 3277c478bd9Sstevel@tonic-gate size_t mbPathlen; /* length of multi-byte path */ 3287c478bd9Sstevel@tonic-gate size_t wcPathlen; /* length of wide-character path */ 3297c478bd9Sstevel@tonic-gate wchar_t *wptr; /* scratch pointer */ 3307c478bd9Sstevel@tonic-gate wchar_t *wcPath; /* wide-character version of the path */ 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * bail out if there is nothing there. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate if (!mbPath) 3377c478bd9Sstevel@tonic-gate return (mbPath); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * convert the multi-byte version of the path to a 3417c478bd9Sstevel@tonic-gate * wide-character rendering, for doing our figuring. 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate mbPathlen = strlen(mbPath); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if ((wcPath = calloc(sizeof (wchar_t), mbPathlen+1)) == NULL) { 3477c478bd9Sstevel@tonic-gate perror("mkdir"); 3487c478bd9Sstevel@tonic-gate exit(2); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if ((wcPathlen = mbstowcs(wcPath, mbPath, mbPathlen)) == (size_t)-1) { 3527c478bd9Sstevel@tonic-gate free(wcPath); 3537c478bd9Sstevel@tonic-gate return (NULL); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * remove duplicate slashes first ("//../" -> "/") 3587c478bd9Sstevel@tonic-gate */ 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate for (wptr = wcPath, i = 0; i < wcPathlen; i++) { 3617c478bd9Sstevel@tonic-gate *wptr++ = wcPath[i]; 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate if (wcPath[i] == '/') { 3647c478bd9Sstevel@tonic-gate i++; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate while (wcPath[i] == '/') { 3677c478bd9Sstevel@tonic-gate i++; 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate i--; 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate *wptr = '\0'; 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * next skip initial occurances of "./" 3787c478bd9Sstevel@tonic-gate */ 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate for (wcPathlen = wcslen(wcPath), wptr = wcPath, i = 0; 3817c478bd9Sstevel@tonic-gate i < wcPathlen-2 && wcPath[i] == '.' && wcPath[i+1] == '/'; 3827c478bd9Sstevel@tonic-gate i += 2) { 3837c478bd9Sstevel@tonic-gate /* empty body */ 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * now make reductions of various forms. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate while (i < wcPathlen) { 3917c478bd9Sstevel@tonic-gate if (i < wcPathlen-2 && wcPath[i] == '/' && 3927c478bd9Sstevel@tonic-gate wcPath[i+1] == '.' && wcPath[i+2] == '/') { 3937c478bd9Sstevel@tonic-gate /* "/./" -> "/" */ 3947c478bd9Sstevel@tonic-gate i += 2; 3957c478bd9Sstevel@tonic-gate } else { 3967c478bd9Sstevel@tonic-gate /* Normal case: copy the character */ 3977c478bd9Sstevel@tonic-gate *wptr++ = wcPath[i++]; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate *wptr = '\0'; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * now convert back to the multi-byte format. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate if (wcstombs(mbPath, wcPath, mbPathlen) == (size_t)-1) { 4087c478bd9Sstevel@tonic-gate free(wcPath); 4097c478bd9Sstevel@tonic-gate return (NULL); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate free(wcPath); 4137c478bd9Sstevel@tonic-gate return (mbPath); 4147c478bd9Sstevel@tonic-gate } 415