1// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/file_util.h" 6 7#include <fcntl.h> 8 9#include <string> 10#include <vector> 11 12#include "base/eintr_wrapper.h" 13#include "base/file_path.h" 14#include "base/string_util.h" 15 16// just lifted off bionic, no should find out why it doesn't get linked in 17 18static int _gettemp(char *, int *, int, int); 19 20extern uint32_t arc4random(); 21 22int 23mkstemps(char *path, int slen) 24{ 25 int fd; 26 27 return (_gettemp(path, &fd, 0, slen) ? fd : -1); 28} 29 30int 31mkstemp(char *path) 32{ 33 int fd; 34 35 return (_gettemp(path, &fd, 0, 0) ? fd : -1); 36} 37 38char * 39mkdtemp(char *path) 40{ 41 return(_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL); 42} 43 44char *_mktemp(char *); 45 46char * 47_mktemp(char *path) 48{ 49 return(_gettemp(path, (int *)NULL, 0, 0) ? path : (char *)NULL); 50} 51 52#ifdef __BIONIC__ 53__warn_references(mktemp, 54 "warning: mktemp() possibly used unsafely; consider using mkstemp()"); 55#endif 56 57char * 58mktemp(char *path) 59{ 60 return(_mktemp(path)); 61} 62 63 64static int 65_gettemp(char *path, int *doopen, int domkdir, int slen) 66{ 67 char *start, *trv, *suffp; 68 struct stat sbuf; 69 int rval; 70 pid_t pid; 71 72 if (doopen && domkdir) { 73 errno = EINVAL; 74 return(0); 75 } 76 77 for (trv = path; *trv; ++trv) 78 ; 79 trv -= slen; 80 suffp = trv; 81 --trv; 82 if (trv < path) { 83 errno = EINVAL; 84 return (0); 85 } 86 pid = getpid(); 87 while (trv >= path && *trv == 'X' && pid != 0) { 88 *trv-- = (pid % 10) + '0'; 89 pid /= 10; 90 } 91 while (trv >= path && *trv == 'X') { 92 char c; 93 94 pid = (arc4random() & 0xffff) % (26+26); 95 if (pid < 26) 96 c = pid + 'A'; 97 else 98 c = (pid - 26) + 'a'; 99 *trv-- = c; 100 } 101 start = trv + 1; 102 103 /* 104 * check the target directory; if you have six X's and it 105 * doesn't exist this runs for a *very* long time. 106 */ 107 if (doopen || domkdir) { 108 for (;; --trv) { 109 if (trv <= path) 110 break; 111 if (*trv == '/') { 112 *trv = '\0'; 113 rval = stat(path, &sbuf); 114 *trv = '/'; 115 if (rval != 0) 116 return(0); 117 if (!S_ISDIR(sbuf.st_mode)) { 118 errno = ENOTDIR; 119 return(0); 120 } 121 break; 122 } 123 } 124 } 125 126 for (;;) { 127 if (doopen) { 128 if ((*doopen = 129 open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) 130 return(1); 131 if (errno != EEXIST) 132 return(0); 133 } else if (domkdir) { 134 if (mkdir(path, 0700) == 0) 135 return(1); 136 if (errno != EEXIST) 137 return(0); 138 } else if (lstat(path, &sbuf)) 139 return(errno == ENOENT ? 1 : 0); 140 141 /* tricky little algorithm for backward compatibility */ 142 for (trv = start;;) { 143 if (!*trv) 144 return (0); 145 if (*trv == 'Z') { 146 if (trv == suffp) 147 return (0); 148 *trv++ = 'a'; 149 } else { 150 if (isdigit(*trv)) 151 *trv = 'a'; 152 else if (*trv == 'z') /* inc from z to A */ 153 *trv = 'A'; 154 else { 155 if (trv == suffp) 156 return (0); 157 ++*trv; 158 } 159 break; 160 } 161 } 162 } 163 /*NOTREACHED*/ 164} 165