LLVM API Documentation
00001 //===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by Reid Spencer and is distributed under the 00006 // University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the Unix specific portion of the Path class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 //===----------------------------------------------------------------------===// 00015 //=== WARNING: Implementation here must contain only generic UNIX code that 00016 //=== is guaranteed to work on *all* UNIX variants. 00017 //===----------------------------------------------------------------------===// 00018 00019 #include "llvm/Config/alloca.h" 00020 #include "Unix.h" 00021 #if HAVE_SYS_STAT_H 00022 #include <sys/stat.h> 00023 #endif 00024 #if HAVE_FCNTL_H 00025 #include <fcntl.h> 00026 #endif 00027 #if HAVE_UTIME_H 00028 #include <utime.h> 00029 #endif 00030 #if HAVE_TIME_H 00031 #include <time.h> 00032 #endif 00033 #if HAVE_DIRENT_H 00034 # include <dirent.h> 00035 # define NAMLEN(dirent) strlen((dirent)->d_name) 00036 #else 00037 # define dirent direct 00038 # define NAMLEN(dirent) (dirent)->d_namlen 00039 # if HAVE_SYS_NDIR_H 00040 # include <sys/ndir.h> 00041 # endif 00042 # if HAVE_SYS_DIR_H 00043 # include <sys/dir.h> 00044 # endif 00045 # if HAVE_NDIR_H 00046 # include <ndir.h> 00047 # endif 00048 #endif 00049 00050 // Put in a hack for Cygwin which falsely reports that the mkdtemp function 00051 // is available when it is not. 00052 #ifdef __CYGWIN__ 00053 # undef HAVE_MKDTEMP 00054 #endif 00055 00056 namespace { 00057 inline bool lastIsSlash(const std::string& path) { 00058 return !path.empty() && path[path.length() - 1] == '/'; 00059 } 00060 00061 } 00062 00063 namespace llvm { 00064 using namespace sys; 00065 00066 Path::Path(const std::string& unverified_path) : path(unverified_path) { 00067 if (unverified_path.empty()) 00068 return; 00069 if (this->isValid()) 00070 return; 00071 // oops, not valid. 00072 path.clear(); 00073 ThrowErrno(unverified_path + ": path is not valid"); 00074 } 00075 00076 bool 00077 Path::isValid() const { 00078 // Check some obvious things 00079 if (path.empty()) 00080 return false; 00081 else if (path.length() >= MAXPATHLEN) 00082 return false; 00083 00084 // Check that the characters are ascii chars 00085 size_t len = path.length(); 00086 unsigned i = 0; 00087 while (i < len && isascii(path[i])) 00088 ++i; 00089 return i >= len; 00090 } 00091 00092 Path 00093 Path::GetRootDirectory() { 00094 Path result; 00095 result.set("/"); 00096 return result; 00097 } 00098 00099 Path 00100 Path::GetTemporaryDirectory() { 00101 #if defined(HAVE_MKDTEMP) 00102 // The best way is with mkdtemp but that's not available on many systems, 00103 // Linux and FreeBSD have it. Others probably won't. 00104 char pathname[MAXPATHLEN]; 00105 strcpy(pathname,"/tmp/llvm_XXXXXX"); 00106 if (0 == mkdtemp(pathname)) 00107 ThrowErrno(std::string(pathname) + ": can't create temporary directory"); 00108 Path result; 00109 result.set(pathname); 00110 assert(result.isValid() && "mkdtemp didn't create a valid pathname!"); 00111 return result; 00112 #elif defined(HAVE_MKSTEMP) 00113 // If no mkdtemp is available, mkstemp can be used to create a temporary file 00114 // which is then removed and created as a directory. We prefer this over 00115 // mktemp because of mktemp's inherent security and threading risks. We still 00116 // have a slight race condition from the time the temporary file is created to 00117 // the time it is re-created as a directoy. 00118 char pathname[MAXPATHLEN]; 00119 strcpy(pathname, "/tmp/llvm_XXXXXX"); 00120 int fd = 0; 00121 if (-1 == (fd = mkstemp(pathname))) 00122 ThrowErrno(std::string(pathname) + ": can't create temporary directory"); 00123 ::close(fd); 00124 ::unlink(pathname); // start race condition, ignore errors 00125 if (-1 == ::mkdir(pathname, S_IRWXU)) // end race condition 00126 ThrowErrno(std::string(pathname) + ": can't create temporary directory"); 00127 Path result; 00128 result.set(pathname); 00129 assert(result.isValid() && "mkstemp didn't create a valid pathname!"); 00130 return result; 00131 #elif defined(HAVE_MKTEMP) 00132 // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have 00133 // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable 00134 // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing 00135 // the XXXXXX with the pid of the process and a letter. That leads to only 00136 // twenty six temporary files that can be generated. 00137 char pathname[MAXPATHLEN]; 00138 strcpy(pathname, "/tmp/llvm_XXXXXX"); 00139 char *TmpName = ::mktemp(pathname); 00140 if (TmpName == 0) 00141 ThrowErrno(std::string(TmpName) + ": can't create unique directory name"); 00142 if (-1 == ::mkdir(TmpName, S_IRWXU)) 00143 ThrowErrno(std::string(TmpName) + ": can't create temporary directory"); 00144 Path result; 00145 result.set(TmpName); 00146 assert(result.isValid() && "mktemp didn't create a valid pathname!"); 00147 return result; 00148 #else 00149 // This is the worst case implementation. tempnam(3) leaks memory unless its 00150 // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread 00151 // issues. The mktemp(3) function doesn't have enough variability in the 00152 // temporary name generated. So, we provide our own implementation that 00153 // increments an integer from a random number seeded by the current time. This 00154 // should be sufficiently unique that we don't have many collisions between 00155 // processes. Generally LLVM processes don't run very long and don't use very 00156 // many temporary files so this shouldn't be a big issue for LLVM. 00157 static time_t num = ::time(0); 00158 char pathname[MAXPATHLEN]; 00159 do { 00160 num++; 00161 sprintf(pathname, "/tmp/llvm_%010u", unsigned(num)); 00162 } while ( 0 == access(pathname, F_OK ) ); 00163 if (-1 == ::mkdir(pathname, S_IRWXU)) 00164 ThrowErrno(std::string(pathname) + ": can't create temporary directory"); 00165 Path result; 00166 result.set(pathname); 00167 assert(result.isValid() && "mkstemp didn't create a valid pathname!"); 00168 return result; 00169 #endif 00170 } 00171 00172 static void getPathList(const char*path, std::vector<sys::Path>& Paths) { 00173 const char* at = path; 00174 const char* delim = strchr(at, ':'); 00175 Path tmpPath; 00176 while( delim != 0 ) { 00177 std::string tmp(at, size_t(delim-at)); 00178 if (tmpPath.set(tmp)) 00179 if (tmpPath.canRead()) 00180 Paths.push_back(tmpPath); 00181 at = delim + 1; 00182 delim = strchr(at, ':'); 00183 } 00184 if (*at != 0) 00185 if (tmpPath.set(std::string(at))) 00186 if (tmpPath.canRead()) 00187 Paths.push_back(tmpPath); 00188 00189 } 00190 00191 void 00192 Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) { 00193 #ifdef LTDL_SHLIBPATH_VAR 00194 char* env_var = getenv(LTDL_SHLIBPATH_VAR); 00195 if (env_var != 0) { 00196 getPathList(env_var,Paths); 00197 } 00198 #endif 00199 // FIXME: Should this look at LD_LIBRARY_PATH too? 00200 Paths.push_back(sys::Path("/usr/local/lib/")); 00201 Paths.push_back(sys::Path("/usr/X11R6/lib/")); 00202 Paths.push_back(sys::Path("/usr/lib/")); 00203 Paths.push_back(sys::Path("/lib/")); 00204 } 00205 00206 void 00207 Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) { 00208 char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); 00209 if (env_var != 0) { 00210 getPathList(env_var,Paths); 00211 } 00212 #ifdef LLVM_LIBDIR 00213 { 00214 Path tmpPath; 00215 if (tmpPath.set(LLVM_LIBDIR)) 00216 if (tmpPath.canRead()) 00217 Paths.push_back(tmpPath); 00218 } 00219 #endif 00220 GetSystemLibraryPaths(Paths); 00221 } 00222 00223 Path 00224 Path::GetLLVMDefaultConfigDir() { 00225 return Path("/etc/llvm/"); 00226 } 00227 00228 Path 00229 Path::GetUserHomeDirectory() { 00230 const char* home = getenv("HOME"); 00231 if (home) { 00232 Path result; 00233 if (result.set(home)) 00234 return result; 00235 } 00236 return GetRootDirectory(); 00237 } 00238 00239 bool 00240 Path::isFile() const { 00241 if (!exists()) 00242 return false; 00243 struct stat buf; 00244 if (0 != stat(path.c_str(), &buf)) { 00245 ThrowErrno(path + ": can't determine type of path object: "); 00246 } 00247 return S_ISREG(buf.st_mode); 00248 } 00249 00250 bool 00251 Path::isDirectory() const { 00252 if (!exists()) 00253 return false; 00254 struct stat buf; 00255 if (0 != stat(path.c_str(), &buf)) { 00256 ThrowErrno(path + ": can't determine type of path object: "); 00257 } 00258 return S_ISDIR(buf.st_mode); 00259 } 00260 00261 bool 00262 Path::isHidden() const { 00263 if (!exists()) 00264 return false; 00265 size_t slash = path.rfind('/'); 00266 return (slash != std::string::npos && 00267 slash < path.length()-1 && 00268 path[slash+1] == '.') || 00269 (!path.empty() && slash == std::string::npos && path[0] == '.'); 00270 } 00271 00272 std::string 00273 Path::getBasename() const { 00274 // Find the last slash 00275 size_t slash = path.rfind('/'); 00276 if (slash == std::string::npos) 00277 slash = 0; 00278 else 00279 slash++; 00280 00281 size_t dot = path.rfind('.'); 00282 if (dot == std::string::npos || dot < slash) 00283 return path.substr(slash); 00284 else 00285 return path.substr(slash, dot - slash); 00286 } 00287 00288 bool Path::hasMagicNumber(const std::string &Magic) const { 00289 if (!isFile()) 00290 return false; 00291 size_t len = Magic.size(); 00292 assert(len < 1024 && "Request for magic string too long"); 00293 char* buf = (char*) alloca(1 + len); 00294 int fd = ::open(path.c_str(),O_RDONLY); 00295 if (fd < 0) 00296 return false; 00297 size_t read_len = ::read(fd, buf, len); 00298 close(fd); 00299 if (len != read_len) 00300 return false; 00301 buf[len] = '\0'; 00302 return Magic == buf; 00303 } 00304 00305 bool Path::getMagicNumber(std::string& Magic, unsigned len) const { 00306 if (!isFile()) 00307 return false; 00308 assert(len < 1024 && "Request for magic string too long"); 00309 char* buf = (char*) alloca(1 + len); 00310 int fd = ::open(path.c_str(),O_RDONLY); 00311 if (fd < 0) 00312 return false; 00313 ssize_t bytes_read = ::read(fd, buf, len); 00314 ::close(fd); 00315 if (ssize_t(len) != bytes_read) { 00316 Magic.clear(); 00317 return false; 00318 } 00319 Magic.assign(buf,len); 00320 return true; 00321 } 00322 00323 bool 00324 Path::isBytecodeFile() const { 00325 if (!isFile()) 00326 return false; 00327 char buffer[ 4]; 00328 buffer[0] = 0; 00329 int fd = ::open(path.c_str(),O_RDONLY); 00330 if (fd < 0) 00331 return false; 00332 ssize_t bytes_read = ::read(fd, buffer, 4); 00333 ::close(fd); 00334 if (4 != bytes_read) 00335 return false; 00336 00337 return (buffer[0] == 'l' && buffer[1] == 'l' && buffer[2] == 'v' && 00338 (buffer[3] == 'c' || buffer[3] == 'm')); 00339 } 00340 00341 bool 00342 Path::exists() const { 00343 return 0 == access(path.c_str(), F_OK ); 00344 } 00345 00346 bool 00347 Path::canRead() const { 00348 return 0 == access(path.c_str(), F_OK | R_OK ); 00349 } 00350 00351 bool 00352 Path::canWrite() const { 00353 return 0 == access(path.c_str(), F_OK | W_OK ); 00354 } 00355 00356 bool 00357 Path::canExecute() const { 00358 if (0 != access(path.c_str(), R_OK | X_OK )) 00359 return false; 00360 struct stat st; 00361 int r = stat(path.c_str(), &st); 00362 if (r != 0 || !S_ISREG(st.st_mode)) 00363 return false; 00364 return true; 00365 } 00366 00367 std::string 00368 Path::getLast() const { 00369 // Find the last slash 00370 size_t pos = path.rfind('/'); 00371 00372 // Handle the corner cases 00373 if (pos == std::string::npos) 00374 return path; 00375 00376 // If the last character is a slash 00377 if (pos == path.length()-1) { 00378 // Find the second to last slash 00379 size_t pos2 = path.rfind('/', pos-1); 00380 if (pos2 == std::string::npos) 00381 return path.substr(0,pos); 00382 else 00383 return path.substr(pos2+1,pos-pos2-1); 00384 } 00385 // Return everything after the last slash 00386 return path.substr(pos+1); 00387 } 00388 00389 void 00390 Path::getStatusInfo(StatusInfo& info) const { 00391 struct stat buf; 00392 if (0 != stat(path.c_str(), &buf)) { 00393 ThrowErrno(path + ": can't determine type of path object: "); 00394 } 00395 info.fileSize = buf.st_size; 00396 info.modTime.fromEpochTime(buf.st_mtime); 00397 info.mode = buf.st_mode; 00398 info.user = buf.st_uid; 00399 info.group = buf.st_gid; 00400 info.isDir = S_ISDIR(buf.st_mode); 00401 } 00402 00403 static bool AddPermissionBits(const std::string& Filename, int bits) { 00404 // Get the umask value from the operating system. We want to use it 00405 // when changing the file's permissions. Since calling umask() sets 00406 // the umask and returns its old value, we must call it a second 00407 // time to reset it to the user's preference. 00408 int mask = umask(0777); // The arg. to umask is arbitrary. 00409 umask(mask); // Restore the umask. 00410 00411 // Get the file's current mode. 00412 struct stat st; 00413 if ((stat(Filename.c_str(), &st)) == -1) 00414 return false; 00415 00416 // Change the file to have whichever permissions bits from 'bits' 00417 // that the umask would not disable. 00418 if ((chmod(Filename.c_str(), (st.st_mode | (bits & ~mask)))) == -1) 00419 return false; 00420 00421 return true; 00422 } 00423 00424 void Path::makeReadableOnDisk() { 00425 if (!AddPermissionBits(path,0444)) 00426 ThrowErrno(path + ": can't make file readable"); 00427 } 00428 00429 void Path::makeWriteableOnDisk() { 00430 if (!AddPermissionBits(path,0222)) 00431 ThrowErrno(path + ": can't make file writable"); 00432 } 00433 00434 void Path::makeExecutableOnDisk() { 00435 if (!AddPermissionBits(path,0111)) 00436 ThrowErrno(path + ": can't make file executable"); 00437 } 00438 00439 bool 00440 Path::getDirectoryContents(std::set<Path>& result) const { 00441 if (!isDirectory()) 00442 return false; 00443 DIR* direntries = ::opendir(path.c_str()); 00444 if (direntries == 0) 00445 ThrowErrno(path + ": can't open directory"); 00446 00447 std::string dirPath = path; 00448 if (!lastIsSlash(dirPath)) 00449 dirPath += '/'; 00450 00451 result.clear(); 00452 struct dirent* de = ::readdir(direntries); 00453 for ( ; de != 0; de = ::readdir(direntries)) { 00454 if (de->d_name[0] != '.') { 00455 Path aPath(dirPath + (const char*)de->d_name); 00456 struct stat st; 00457 if (0 != lstat(aPath.path.c_str(), &st)) { 00458 if (S_ISLNK(st.st_mode)) 00459 continue; // dangling symlink -- ignore 00460 ThrowErrno(aPath.path + ": can't determine file object type"); 00461 } 00462 result.insert(aPath); 00463 } 00464 } 00465 00466 closedir(direntries); 00467 return true; 00468 } 00469 00470 bool 00471 Path::set(const std::string& a_path) { 00472 if (a_path.empty()) 00473 return false; 00474 std::string save(path); 00475 path = a_path; 00476 if (!isValid()) { 00477 path = save; 00478 return false; 00479 } 00480 return true; 00481 } 00482 00483 bool 00484 Path::appendComponent(const std::string& name) { 00485 if (name.empty()) 00486 return false; 00487 std::string save(path); 00488 if (!lastIsSlash(path)) 00489 path += '/'; 00490 path += name; 00491 if (!isValid()) { 00492 path = save; 00493 return false; 00494 } 00495 return true; 00496 } 00497 00498 bool 00499 Path::eraseComponent() { 00500 size_t slashpos = path.rfind('/',path.size()); 00501 if (slashpos == 0 || slashpos == std::string::npos) { 00502 path.erase(); 00503 return true; 00504 } 00505 if (slashpos == path.size() - 1) 00506 slashpos = path.rfind('/',slashpos-1); 00507 if (slashpos == std::string::npos) { 00508 path.erase(); 00509 return true; 00510 } 00511 path.erase(slashpos); 00512 return true; 00513 } 00514 00515 bool 00516 Path::appendSuffix(const std::string& suffix) { 00517 std::string save(path); 00518 path.append("."); 00519 path.append(suffix); 00520 if (!isValid()) { 00521 path = save; 00522 return false; 00523 } 00524 return true; 00525 } 00526 00527 bool 00528 Path::eraseSuffix() { 00529 std::string save = path; 00530 size_t dotpos = path.rfind('.',path.size()); 00531 size_t slashpos = path.rfind('/',path.size()); 00532 if (dotpos != std::string::npos) { 00533 if (slashpos == std::string::npos || dotpos > slashpos+1) { 00534 path.erase(dotpos, path.size()-dotpos); 00535 return true; 00536 } 00537 } 00538 if (!isValid()) 00539 path = save; 00540 return false; 00541 } 00542 00543 bool 00544 Path::createDirectoryOnDisk( bool create_parents) { 00545 // Get a writeable copy of the path name 00546 char pathname[MAXPATHLEN]; 00547 path.copy(pathname,MAXPATHLEN); 00548 00549 // Null-terminate the last component 00550 int lastchar = path.length() - 1 ; 00551 if (pathname[lastchar] == '/') 00552 pathname[lastchar] = 0; 00553 else 00554 pathname[lastchar+1] = 0; 00555 00556 // If we're supposed to create intermediate directories 00557 if ( create_parents ) { 00558 // Find the end of the initial name component 00559 char * next = strchr(pathname,'/'); 00560 if ( pathname[0] == '/') 00561 next = strchr(&pathname[1],'/'); 00562 00563 // Loop through the directory components until we're done 00564 while ( next != 0 ) { 00565 *next = 0; 00566 if (0 != access(pathname, F_OK | R_OK | W_OK)) 00567 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) 00568 ThrowErrno(std::string(pathname) + ": can't create directory"); 00569 char* save = next; 00570 next = strchr(next+1,'/'); 00571 *save = '/'; 00572 } 00573 } 00574 00575 if (0 != access(pathname, F_OK | R_OK)) 00576 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) 00577 ThrowErrno(std::string(pathname) + ": can't create directory"); 00578 return true; 00579 } 00580 00581 bool 00582 Path::createFileOnDisk() { 00583 // Create the file 00584 int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); 00585 if (fd < 0) 00586 ThrowErrno(path + ": can't create file"); 00587 ::close(fd); 00588 00589 return true; 00590 } 00591 00592 bool 00593 Path::createTemporaryFileOnDisk(bool reuse_current) { 00594 // Make this into a unique file name 00595 makeUnique( reuse_current ); 00596 00597 // create the file 00598 int outFile = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); 00599 if (outFile != -1) { 00600 ::close(outFile); 00601 return true; 00602 } 00603 return false; 00604 } 00605 00606 bool 00607 Path::eraseFromDisk(bool remove_contents) const { 00608 // Make sure we're dealing with a directory 00609 if (isFile()) { 00610 if (0 != unlink(path.c_str())) 00611 ThrowErrno(path + ": can't destroy file"); 00612 } else if (isDirectory()) { 00613 if (remove_contents) { 00614 // Recursively descend the directory to remove its content 00615 std::string cmd("/bin/rm -rf "); 00616 cmd += path; 00617 system(cmd.c_str()); 00618 } else { 00619 // Otherwise, try to just remove the one directory 00620 char pathname[MAXPATHLEN]; 00621 path.copy(pathname,MAXPATHLEN); 00622 int lastchar = path.length() - 1 ; 00623 if (pathname[lastchar] == '/') 00624 pathname[lastchar] = 0; 00625 else 00626 pathname[lastchar+1] = 0; 00627 if ( 0 != rmdir(pathname)) 00628 ThrowErrno(std::string(pathname) + ": can't destroy directory"); 00629 } 00630 } 00631 else 00632 return false; 00633 return true; 00634 } 00635 00636 bool 00637 Path::renamePathOnDisk(const Path& newName) { 00638 if (0 != ::rename(path.c_str(), newName.c_str())) 00639 ThrowErrno(std::string("can't rename '") + path + "' as '" + 00640 newName.toString() + "' "); 00641 return true; 00642 } 00643 00644 bool 00645 Path::setStatusInfoOnDisk(const StatusInfo& si) const { 00646 struct utimbuf utb; 00647 utb.actime = si.modTime.toPosixTime(); 00648 utb.modtime = utb.actime; 00649 if (0 != ::utime(path.c_str(),&utb)) 00650 ThrowErrno(path + ": can't set file modification time"); 00651 if (0 != ::chmod(path.c_str(),si.mode)) 00652 ThrowErrno(path + ": can't set mode"); 00653 return true; 00654 } 00655 00656 void 00657 sys::CopyFile(const sys::Path &Dest, const sys::Path &Src) { 00658 int inFile = -1; 00659 int outFile = -1; 00660 try { 00661 inFile = ::open(Src.c_str(), O_RDONLY); 00662 if (inFile == -1) 00663 ThrowErrno(Src.toString() + ": can't open source file to copy: "); 00664 00665 outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); 00666 if (outFile == -1) 00667 ThrowErrno(Dest.toString() +": can't create destination file for copy: "); 00668 00669 char Buffer[16*1024]; 00670 while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) { 00671 if (Amt == -1) { 00672 if (errno != EINTR && errno != EAGAIN) 00673 ThrowErrno(Src.toString()+": can't read source file: "); 00674 } else { 00675 char *BufPtr = Buffer; 00676 while (Amt) { 00677 ssize_t AmtWritten = ::write(outFile, BufPtr, Amt); 00678 if (AmtWritten == -1) { 00679 if (errno != EINTR && errno != EAGAIN) 00680 ThrowErrno(Dest.toString() + ": can't write destination file: "); 00681 } else { 00682 Amt -= AmtWritten; 00683 BufPtr += AmtWritten; 00684 } 00685 } 00686 } 00687 } 00688 ::close(inFile); 00689 ::close(outFile); 00690 } catch (...) { 00691 if (inFile != -1) 00692 ::close(inFile); 00693 if (outFile != -1) 00694 ::close(outFile); 00695 throw; 00696 } 00697 } 00698 00699 void 00700 Path::makeUnique(bool reuse_current) { 00701 if (reuse_current && !exists()) 00702 return; // File doesn't exist already, just use it! 00703 00704 // Append an XXXXXX pattern to the end of the file for use with mkstemp, 00705 // mktemp or our own implementation. 00706 char *FNBuffer = (char*) alloca(path.size()+8); 00707 path.copy(FNBuffer,path.size()); 00708 strcpy(FNBuffer+path.size(), "-XXXXXX"); 00709 00710 #if defined(HAVE_MKSTEMP) 00711 int TempFD; 00712 if ((TempFD = mkstemp(FNBuffer)) == -1) { 00713 ThrowErrno(path + ": can't make unique filename"); 00714 } 00715 00716 // We don't need to hold the temp file descriptor... we will trust that no one 00717 // will overwrite/delete the file before we can open it again. 00718 close(TempFD); 00719 00720 // Save the name 00721 path = FNBuffer; 00722 #elif defined(HAVE_MKTEMP) 00723 // If we don't have mkstemp, use the old and obsolete mktemp function. 00724 if (mktemp(FNBuffer) == 0) { 00725 ThrowErrno(path + ": can't make unique filename"); 00726 } 00727 00728 // Save the name 00729 path = FNBuffer; 00730 #else 00731 // Okay, looks like we have to do it all by our lonesome. 00732 static unsigned FCounter = 0; 00733 unsigned offset = path.size() + 1; 00734 while ( FCounter < 999999 && exists()) { 00735 sprintf(FNBuffer+offset,"%06u",++FCounter); 00736 path = FNBuffer; 00737 } 00738 if (FCounter > 999999) 00739 throw std::string(path + ": can't make unique filename: too many files"); 00740 #endif 00741 00742 } 00743 } 00744