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 buf; 00457 if (0 != stat(aPath.path.c_str(), &buf)) { 00458 int stat_errno = errno; 00459 struct stat st; 00460 if (0 == lstat(aPath.path.c_str(), &st) && S_ISLNK(st.st_mode)) 00461 continue; // dangling symlink -- ignore 00462 ThrowErrno(aPath.path + 00463 ": can't determine file object type", stat_errno); 00464 } 00465 result.insert(aPath); 00466 } 00467 } 00468 00469 closedir(direntries); 00470 return true; 00471 } 00472 00473 bool 00474 Path::set(const std::string& a_path) { 00475 if (a_path.empty()) 00476 return false; 00477 std::string save(path); 00478 path = a_path; 00479 if (!isValid()) { 00480 path = save; 00481 return false; 00482 } 00483 return true; 00484 } 00485 00486 bool 00487 Path::appendComponent(const std::string& name) { 00488 if (name.empty()) 00489 return false; 00490 std::string save(path); 00491 if (!lastIsSlash(path)) 00492 path += '/'; 00493 path += name; 00494 if (!isValid()) { 00495 path = save; 00496 return false; 00497 } 00498 return true; 00499 } 00500 00501 bool 00502 Path::eraseComponent() { 00503 size_t slashpos = path.rfind('/',path.size()); 00504 if (slashpos == 0 || slashpos == std::string::npos) { 00505 path.erase(); 00506 return true; 00507 } 00508 if (slashpos == path.size() - 1) 00509 slashpos = path.rfind('/',slashpos-1); 00510 if (slashpos == std::string::npos) { 00511 path.erase(); 00512 return true; 00513 } 00514 path.erase(slashpos); 00515 return true; 00516 } 00517 00518 bool 00519 Path::appendSuffix(const std::string& suffix) { 00520 std::string save(path); 00521 path.append("."); 00522 path.append(suffix); 00523 if (!isValid()) { 00524 path = save; 00525 return false; 00526 } 00527 return true; 00528 } 00529 00530 bool 00531 Path::eraseSuffix() { 00532 std::string save = path; 00533 size_t dotpos = path.rfind('.',path.size()); 00534 size_t slashpos = path.rfind('/',path.size()); 00535 if (dotpos != std::string::npos) { 00536 if (slashpos == std::string::npos || dotpos > slashpos+1) { 00537 path.erase(dotpos, path.size()-dotpos); 00538 return true; 00539 } 00540 } 00541 if (!isValid()) 00542 path = save; 00543 return false; 00544 } 00545 00546 bool 00547 Path::createDirectoryOnDisk( bool create_parents) { 00548 // Get a writeable copy of the path name 00549 char pathname[MAXPATHLEN]; 00550 path.copy(pathname,MAXPATHLEN); 00551 00552 // Null-terminate the last component 00553 int lastchar = path.length() - 1 ; 00554 if (pathname[lastchar] == '/') 00555 pathname[lastchar] = 0; 00556 else 00557 pathname[lastchar+1] = 0; 00558 00559 // If we're supposed to create intermediate directories 00560 if ( create_parents ) { 00561 // Find the end of the initial name component 00562 char * next = strchr(pathname,'/'); 00563 if ( pathname[0] == '/') 00564 next = strchr(&pathname[1],'/'); 00565 00566 // Loop through the directory components until we're done 00567 while ( next != 0 ) { 00568 *next = 0; 00569 if (0 != access(pathname, F_OK | R_OK | W_OK)) 00570 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) 00571 ThrowErrno(std::string(pathname) + ": can't create directory"); 00572 char* save = next; 00573 next = strchr(next+1,'/'); 00574 *save = '/'; 00575 } 00576 } 00577 00578 if (0 != access(pathname, F_OK | R_OK)) 00579 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) 00580 ThrowErrno(std::string(pathname) + ": can't create directory"); 00581 return true; 00582 } 00583 00584 bool 00585 Path::createFileOnDisk() { 00586 // Create the file 00587 int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); 00588 if (fd < 0) 00589 ThrowErrno(path + ": can't create file"); 00590 ::close(fd); 00591 00592 return true; 00593 } 00594 00595 bool 00596 Path::createTemporaryFileOnDisk(bool reuse_current) { 00597 // Make this into a unique file name 00598 makeUnique( reuse_current ); 00599 00600 // create the file 00601 int outFile = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); 00602 if (outFile != -1) { 00603 ::close(outFile); 00604 return true; 00605 } 00606 return false; 00607 } 00608 00609 bool 00610 Path::eraseFromDisk(bool remove_contents) const { 00611 // Make sure we're dealing with a directory 00612 if (isFile()) { 00613 if (0 != unlink(path.c_str())) 00614 ThrowErrno(path + ": can't destroy file"); 00615 } else if (isDirectory()) { 00616 if (remove_contents) { 00617 // Recursively descend the directory to remove its content 00618 std::string cmd("/bin/rm -rf "); 00619 cmd += path; 00620 system(cmd.c_str()); 00621 } else { 00622 // Otherwise, try to just remove the one directory 00623 char pathname[MAXPATHLEN]; 00624 path.copy(pathname,MAXPATHLEN); 00625 int lastchar = path.length() - 1 ; 00626 if (pathname[lastchar] == '/') 00627 pathname[lastchar] = 0; 00628 else 00629 pathname[lastchar+1] = 0; 00630 if ( 0 != rmdir(pathname)) 00631 ThrowErrno(std::string(pathname) + ": can't destroy directory"); 00632 } 00633 } 00634 else 00635 return false; 00636 return true; 00637 } 00638 00639 bool 00640 Path::renamePathOnDisk(const Path& newName) { 00641 if (0 != ::rename(path.c_str(), newName.c_str())) 00642 ThrowErrno(std::string("can't rename '") + path + "' as '" + 00643 newName.toString() + "' "); 00644 return true; 00645 } 00646 00647 bool 00648 Path::setStatusInfoOnDisk(const StatusInfo& si) const { 00649 struct utimbuf utb; 00650 utb.actime = si.modTime.toPosixTime(); 00651 utb.modtime = utb.actime; 00652 if (0 != ::utime(path.c_str(),&utb)) 00653 ThrowErrno(path + ": can't set file modification time"); 00654 if (0 != ::chmod(path.c_str(),si.mode)) 00655 ThrowErrno(path + ": can't set mode"); 00656 return true; 00657 } 00658 00659 void 00660 sys::CopyFile(const sys::Path &Dest, const sys::Path &Src) { 00661 int inFile = -1; 00662 int outFile = -1; 00663 try { 00664 inFile = ::open(Src.c_str(), O_RDONLY); 00665 if (inFile == -1) 00666 ThrowErrno(Src.toString() + ": can't open source file to copy: "); 00667 00668 outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); 00669 if (outFile == -1) 00670 ThrowErrno(Dest.toString() +": can't create destination file for copy: "); 00671 00672 char Buffer[16*1024]; 00673 while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) { 00674 if (Amt == -1) { 00675 if (errno != EINTR && errno != EAGAIN) 00676 ThrowErrno(Src.toString()+": can't read source file: "); 00677 } else { 00678 char *BufPtr = Buffer; 00679 while (Amt) { 00680 ssize_t AmtWritten = ::write(outFile, BufPtr, Amt); 00681 if (AmtWritten == -1) { 00682 if (errno != EINTR && errno != EAGAIN) 00683 ThrowErrno(Dest.toString() + ": can't write destination file: "); 00684 } else { 00685 Amt -= AmtWritten; 00686 BufPtr += AmtWritten; 00687 } 00688 } 00689 } 00690 } 00691 ::close(inFile); 00692 ::close(outFile); 00693 } catch (...) { 00694 if (inFile != -1) 00695 ::close(inFile); 00696 if (outFile != -1) 00697 ::close(outFile); 00698 throw; 00699 } 00700 } 00701 00702 void 00703 Path::makeUnique(bool reuse_current) { 00704 if (reuse_current && !exists()) 00705 return; // File doesn't exist already, just use it! 00706 00707 // Append an XXXXXX pattern to the end of the file for use with mkstemp, 00708 // mktemp or our own implementation. 00709 char *FNBuffer = (char*) alloca(path.size()+8); 00710 path.copy(FNBuffer,path.size()); 00711 strcpy(FNBuffer+path.size(), "-XXXXXX"); 00712 00713 #if defined(HAVE_MKSTEMP) 00714 int TempFD; 00715 if ((TempFD = mkstemp(FNBuffer)) == -1) { 00716 ThrowErrno(path + ": can't make unique filename"); 00717 } 00718 00719 // We don't need to hold the temp file descriptor... we will trust that no one 00720 // will overwrite/delete the file before we can open it again. 00721 close(TempFD); 00722 00723 // Save the name 00724 path = FNBuffer; 00725 #elif defined(HAVE_MKTEMP) 00726 // If we don't have mkstemp, use the old and obsolete mktemp function. 00727 if (mktemp(FNBuffer) == 0) { 00728 ThrowErrno(path + ": can't make unique filename"); 00729 } 00730 00731 // Save the name 00732 path = FNBuffer; 00733 #else 00734 // Okay, looks like we have to do it all by our lonesome. 00735 static unsigned FCounter = 0; 00736 unsigned offset = path.size() + 1; 00737 while ( FCounter < 999999 && exists()) { 00738 sprintf(FNBuffer+offset,"%06u",++FCounter); 00739 path = FNBuffer; 00740 } 00741 if (FCounter > 999999) 00742 throw std::string(path + ": can't make unique filename: too many files"); 00743 #endif 00744 00745 } 00746 } 00747