Fix a problem in getDirectoryContents where sub-directory names were
[oota-llvm.git] / lib / System / Unix / Path.inc
1 //===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Reid Spencer and is distributed under the 
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Unix specific portion of the Path class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //===          is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
18
19 #include "llvm/Config/alloca.h"
20 #include "Unix.h"
21 #if HAVE_SYS_STAT_H
22 #include <sys/stat.h>
23 #endif
24 #if HAVE_FCNTL_H
25 #include <fcntl.h>
26 #endif
27 #if HAVE_UTIME_H
28 #include <utime.h>
29 #endif
30 #if HAVE_TIME_H
31 #include <time.h>
32 #endif
33 #if HAVE_DIRENT_H
34 # include <dirent.h>
35 # define NAMLEN(dirent) strlen((dirent)->d_name)
36 #else
37 # define dirent direct
38 # define NAMLEN(dirent) (dirent)->d_namlen
39 # if HAVE_SYS_NDIR_H
40 #  include <sys/ndir.h>
41 # endif
42 # if HAVE_SYS_DIR_H
43 #  include <sys/dir.h>
44 # endif
45 # if HAVE_NDIR_H
46 #  include <ndir.h>
47 # endif
48 #endif
49
50 // Put in a hack for Cygwin which falsely reports that the mkdtemp function
51 // is available when it is not.
52 #ifdef __CYGWIN__
53 # undef HAVE_MKDTEMP
54 #endif
55
56 namespace {
57 inline bool lastIsSlash(const std::string& path) {
58   return !path.empty() && path[path.length() - 1] == '/';
59 }
60
61 }
62
63 namespace llvm {
64 using namespace sys;
65
66 Path::Path(const std::string& unverified_path) : path(unverified_path) {
67   if (unverified_path.empty())
68     return;
69   if (this->isValid()) 
70     return;
71   // oops, not valid.
72   path.clear();
73   ThrowErrno(unverified_path + ": path is not valid");
74 }
75
76 bool 
77 Path::isValid() const {
78   // Check some obvious things
79   if (path.empty()) 
80     return false;
81   else if (path.length() >= MAXPATHLEN)
82     return false;
83
84   // Check that the characters are ascii chars
85   size_t len = path.length();
86   unsigned i = 0;
87   while (i < len && isascii(path[i])) 
88     ++i;
89   return i >= len; 
90 }
91
92 Path
93 Path::GetRootDirectory() {
94   Path result;
95   result.set("/");
96   return result;
97 }
98
99 Path
100 Path::GetTemporaryDirectory() {
101 #if defined(HAVE_MKDTEMP)
102   // The best way is with mkdtemp but that's not available on many systems, 
103   // Linux and FreeBSD have it. Others probably won't.
104   char pathname[MAXPATHLEN];
105   strcpy(pathname,"/tmp/llvm_XXXXXX");
106   if (0 == mkdtemp(pathname))
107     ThrowErrno(std::string(pathname) + ": can't create temporary directory");
108   Path result;
109   result.set(pathname);
110   assert(result.isValid() && "mkdtemp didn't create a valid pathname!");
111   return result;
112 #elif defined(HAVE_MKSTEMP)
113   // If no mkdtemp is available, mkstemp can be used to create a temporary file
114   // which is then removed and created as a directory. We prefer this over
115   // mktemp because of mktemp's inherent security and threading risks. We still
116   // have a slight race condition from the time the temporary file is created to
117   // the time it is re-created as a directoy. 
118   char pathname[MAXPATHLEN];
119   strcpy(pathname, "/tmp/llvm_XXXXXX");
120   int fd = 0;
121   if (-1 == (fd = mkstemp(pathname)))
122     ThrowErrno(std::string(pathname) + ": can't create temporary directory");
123   ::close(fd);
124   ::unlink(pathname); // start race condition, ignore errors
125   if (-1 == ::mkdir(pathname, S_IRWXU)) // end race condition
126     ThrowErrno(std::string(pathname) + ": can't create temporary directory");
127   Path result;
128   result.set(pathname);
129   assert(result.isValid() && "mkstemp didn't create a valid pathname!");
130   return result;
131 #elif defined(HAVE_MKTEMP)
132   // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have
133   // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable
134   // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing
135   // the XXXXXX with the pid of the process and a letter. That leads to only
136   // twenty six temporary files that can be generated.
137   char pathname[MAXPATHLEN];
138   strcpy(pathname, "/tmp/llvm_XXXXXX");
139   char *TmpName = ::mktemp(pathname);
140   if (TmpName == 0)
141     ThrowErrno(std::string(TmpName) + ": can't create unique directory name");
142   if (-1 == ::mkdir(TmpName, S_IRWXU))
143     ThrowErrno(std::string(TmpName) + ": can't create temporary directory");
144   Path result;
145   result.set(TmpName);
146   assert(result.isValid() && "mktemp didn't create a valid pathname!");
147   return result;
148 #else
149   // This is the worst case implementation. tempnam(3) leaks memory unless its
150   // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread
151   // issues. The mktemp(3) function doesn't have enough variability in the
152   // temporary name generated. So, we provide our own implementation that 
153   // increments an integer from a random number seeded by the current time. This
154   // should be sufficiently unique that we don't have many collisions between
155   // processes. Generally LLVM processes don't run very long and don't use very
156   // many temporary files so this shouldn't be a big issue for LLVM.
157   static time_t num = ::time(0);
158   char pathname[MAXPATHLEN];
159   do {
160     num++;
161     sprintf(pathname, "/tmp/llvm_%010u", unsigned(num));
162   } while ( 0 == access(pathname, F_OK ) );
163   if (-1 == ::mkdir(pathname, S_IRWXU))
164     ThrowErrno(std::string(pathname) + ": can't create temporary directory");
165   Path result;
166   result.set(pathname);
167   assert(result.isValid() && "mkstemp didn't create a valid pathname!");
168   return result;
169 #endif
170 }
171
172 static void getPathList(const char*path, std::vector<sys::Path>& Paths) {
173   const char* at = path;
174   const char* delim = strchr(at, ':');
175   Path tmpPath;
176   while( delim != 0 ) {
177     std::string tmp(at, size_t(delim-at));
178     if (tmpPath.set(tmp))
179       if (tmpPath.canRead())
180         Paths.push_back(tmpPath);
181     at = delim + 1;
182     delim = strchr(at, ':');
183   }
184   if (*at != 0)
185     if (tmpPath.set(std::string(at)))
186       if (tmpPath.canRead())
187         Paths.push_back(tmpPath);
188
189 }
190
191 void 
192 Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
193 #ifdef LTDL_SHLIBPATH_VAR
194   char* env_var = getenv(LTDL_SHLIBPATH_VAR);
195   if (env_var != 0) {
196     getPathList(env_var,Paths);
197   }
198 #endif
199   // FIXME: Should this look at LD_LIBRARY_PATH too?
200   Paths.push_back(sys::Path("/usr/local/lib/"));
201   Paths.push_back(sys::Path("/usr/X11R6/lib/"));
202   Paths.push_back(sys::Path("/usr/lib/"));
203   Paths.push_back(sys::Path("/lib/"));
204 }
205
206 void
207 Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) {
208   char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
209   if (env_var != 0) {
210     getPathList(env_var,Paths);
211   }
212 #ifdef LLVM_LIBDIR
213   {
214     Path tmpPath;
215     if (tmpPath.set(LLVM_LIBDIR))
216       if (tmpPath.canRead())
217         Paths.push_back(tmpPath);
218   }
219 #endif
220   GetSystemLibraryPaths(Paths);
221 }
222
223 Path 
224 Path::GetLLVMDefaultConfigDir() {
225   return Path("/etc/llvm/");
226 }
227
228 Path
229 Path::GetUserHomeDirectory() {
230   const char* home = getenv("HOME");
231   if (home) {
232     Path result;
233     if (result.set(home))
234       return result;
235   }
236   return GetRootDirectory();
237 }
238
239 bool
240 Path::isFile() const {
241   if (!exists())
242     return false;
243   struct stat buf;
244   if (0 != stat(path.c_str(), &buf)) {
245     ThrowErrno(path + ": can't determine type of path object: ");
246   }
247   return S_ISREG(buf.st_mode);
248 }
249
250 bool
251 Path::isDirectory() const {
252   if (!exists())
253     return false;
254   struct stat buf;
255   if (0 != stat(path.c_str(), &buf)) {
256     ThrowErrno(path + ": can't determine type of path object: ");
257   }
258   return S_ISDIR(buf.st_mode);
259 }
260
261 bool
262 Path::isHidden() const {
263   if (!exists())
264     return false;
265   size_t slash = path.rfind('/');
266   return (slash != std::string::npos && 
267           slash < path.length()-1 && 
268           path[slash+1] == '.') || 
269          (!path.empty() && slash == std::string::npos && path[0] == '.');
270 }
271
272 std::string
273 Path::getBasename() const {
274   // Find the last slash
275   size_t slash = path.rfind('/');
276   if (slash == std::string::npos)
277     slash = 0;
278   else
279     slash++;
280
281   size_t dot = path.rfind('.');
282   if (dot == std::string::npos || dot < slash)
283     return path.substr(slash);
284   else
285     return path.substr(slash, dot - slash);
286 }
287
288 bool Path::hasMagicNumber(const std::string &Magic) const {
289   if (!isFile())
290     return false;
291   size_t len = Magic.size();
292   assert(len < 1024 && "Request for magic string too long");
293   char* buf = (char*) alloca(1 + len);
294   int fd = ::open(path.c_str(),O_RDONLY);
295   if (fd < 0)
296     return false;
297   size_t read_len = ::read(fd, buf, len);
298   close(fd);
299   if (len != read_len)
300     return false;
301   buf[len] = '\0';
302   return Magic == buf;
303 }
304
305 bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
306   if (!isFile())
307     return false;
308   assert(len < 1024 && "Request for magic string too long");
309   char* buf = (char*) alloca(1 + len);
310   int fd = ::open(path.c_str(),O_RDONLY);
311   if (fd < 0)
312     return false;
313   ssize_t bytes_read = ::read(fd, buf, len);
314   ::close(fd);
315   if (ssize_t(len) != bytes_read) {
316     Magic.clear();
317     return false;
318   }
319   Magic.assign(buf,len);
320   return true;
321 }
322
323 bool 
324 Path::isBytecodeFile() const {
325   if (!isFile())
326     return false;
327   char buffer[ 4];
328   buffer[0] = 0;
329   int fd = ::open(path.c_str(),O_RDONLY);
330   if (fd < 0)
331     return false;
332   ssize_t bytes_read = ::read(fd, buffer, 4);
333   ::close(fd);
334   if (4 != bytes_read) 
335     return false;
336
337   return (buffer[0] == 'l' && buffer[1] == 'l' && buffer[2] == 'v' &&
338       (buffer[3] == 'c' || buffer[3] == 'm'));
339 }
340
341 bool
342 Path::exists() const {
343   return 0 == access(path.c_str(), F_OK );
344 }
345
346 bool
347 Path::canRead() const {
348   return 0 == access(path.c_str(), F_OK | R_OK );
349 }
350
351 bool
352 Path::canWrite() const {
353   return 0 == access(path.c_str(), F_OK | W_OK );
354 }
355
356 bool
357 Path::canExecute() const {
358   if (0 != access(path.c_str(), R_OK | X_OK ))
359     return false;
360   struct stat st;
361   int r = stat(path.c_str(), &st);
362   if (r != 0 || !S_ISREG(st.st_mode))
363     return false;
364   return true;
365 }
366
367 std::string 
368 Path::getLast() const {
369   // Find the last slash
370   size_t pos = path.rfind('/');
371
372   // Handle the corner cases
373   if (pos == std::string::npos)
374     return path;
375
376   // If the last character is a slash
377   if (pos == path.length()-1) {
378     // Find the second to last slash
379     size_t pos2 = path.rfind('/', pos-1);
380     if (pos2 == std::string::npos)
381       return path.substr(0,pos);
382     else
383       return path.substr(pos2+1,pos-pos2-1);
384   }
385   // Return everything after the last slash
386   return path.substr(pos+1);
387 }
388
389 void
390 Path::getStatusInfo(StatusInfo& info) const {
391   struct stat buf;
392   if (0 != stat(path.c_str(), &buf)) {
393     ThrowErrno(path + ": can't determine type of path object: ");
394   }
395   info.fileSize = buf.st_size;
396   info.modTime.fromEpochTime(buf.st_mtime);
397   info.mode = buf.st_mode;
398   info.user = buf.st_uid;
399   info.group = buf.st_gid;
400   info.isDir = S_ISDIR(buf.st_mode);
401 }
402
403 static bool AddPermissionBits(const std::string& Filename, int bits) {
404   // Get the umask value from the operating system.  We want to use it
405   // when changing the file's permissions. Since calling umask() sets
406   // the umask and returns its old value, we must call it a second
407   // time to reset it to the user's preference.
408   int mask = umask(0777); // The arg. to umask is arbitrary.
409   umask(mask);            // Restore the umask.
410
411   // Get the file's current mode.
412   struct stat st;
413   if ((stat(Filename.c_str(), &st)) == -1)
414     return false;
415
416   // Change the file to have whichever permissions bits from 'bits'
417   // that the umask would not disable.
418   if ((chmod(Filename.c_str(), (st.st_mode | (bits & ~mask)))) == -1)
419     return false;
420
421   return true;
422 }
423
424 void Path::makeReadableOnDisk() {
425   if (!AddPermissionBits(path,0444))
426     ThrowErrno(path + ": can't make file readable");
427 }
428
429 void Path::makeWriteableOnDisk() {
430   if (!AddPermissionBits(path,0222))
431     ThrowErrno(path + ": can't make file writable");
432 }
433
434 void Path::makeExecutableOnDisk() {
435   if (!AddPermissionBits(path,0111))
436     ThrowErrno(path + ": can't make file executable");
437 }
438
439 bool
440 Path::getDirectoryContents(std::set<Path>& result) const {
441   if (!isDirectory())
442     return false;
443   DIR* direntries = ::opendir(path.c_str());
444   if (direntries == 0)
445     ThrowErrno(path + ": can't open directory");
446
447   std::string dirPath = path;
448   if (!lastIsSlash(dirPath))
449     dirPath += '/';
450
451   result.clear();
452   struct dirent* de = ::readdir(direntries);
453   for ( ; de != 0; de = ::readdir(direntries)) {
454     if (de->d_name[0] != '.') {
455       Path aPath(dirPath + (const char*)de->d_name);
456       struct stat buf;
457       if (0 != stat(aPath.path.c_str(), &buf)) {
458         int stat_errno = errno;
459         struct stat st;
460         if (0 == lstat(aPath.path.c_str(), &st) && S_ISLNK(st.st_mode))
461           continue; // dangling symlink -- ignore
462         ThrowErrno(aPath.path + 
463           ": can't determine file object type", stat_errno);
464       }
465       result.insert(aPath);
466     }
467   }
468   
469   closedir(direntries);
470   return true;
471 }
472
473 bool
474 Path::set(const std::string& a_path) {
475   if (a_path.empty())
476     return false;
477   std::string save(path);
478   path = a_path;
479   if (!isValid()) {
480     path = save;
481     return false;
482   }
483   return true;
484 }
485
486 bool
487 Path::appendComponent(const std::string& name) {
488   if (name.empty())
489     return false;
490   std::string save(path);
491   if (!lastIsSlash(path))
492     path += '/';
493   path += name;
494   if (!isValid()) {
495     path = save;
496     return false;
497   }
498   return true;
499 }
500
501 bool
502 Path::eraseComponent() {
503   size_t slashpos = path.rfind('/',path.size());
504   if (slashpos == 0 || slashpos == std::string::npos) {
505     path.erase();
506     return true;
507   }
508   if (slashpos == path.size() - 1)
509     slashpos = path.rfind('/',slashpos-1);
510   if (slashpos == std::string::npos) {
511     path.erase();
512     return true;
513   }
514   path.erase(slashpos);
515   return true;
516 }
517
518 bool
519 Path::appendSuffix(const std::string& suffix) {
520   std::string save(path);
521   path.append(".");
522   path.append(suffix);
523   if (!isValid()) {
524     path = save;
525     return false;
526   }
527   return true;
528 }
529
530 bool
531 Path::eraseSuffix() {
532   std::string save = path;
533   size_t dotpos = path.rfind('.',path.size());
534   size_t slashpos = path.rfind('/',path.size());
535   if (dotpos != std::string::npos) {
536     if (slashpos == std::string::npos || dotpos > slashpos+1) {
537       path.erase(dotpos, path.size()-dotpos);
538       return true;
539     }
540   }
541   if (!isValid())
542     path = save;
543   return false;
544 }
545
546 bool
547 Path::createDirectoryOnDisk( bool create_parents) {
548   // Get a writeable copy of the path name
549   char pathname[MAXPATHLEN];
550   path.copy(pathname,MAXPATHLEN);
551
552   // Null-terminate the last component
553   int lastchar = path.length() - 1 ; 
554   if (pathname[lastchar] == '/') 
555     pathname[lastchar] = 0;
556   else 
557     pathname[lastchar+1] = 0;
558
559   // If we're supposed to create intermediate directories
560   if ( create_parents ) {
561     // Find the end of the initial name component
562     char * next = strchr(pathname,'/');
563     if ( pathname[0] == '/') 
564       next = strchr(&pathname[1],'/');
565
566     // Loop through the directory components until we're done 
567     while ( next != 0 ) {
568       *next = 0;
569       if (0 != access(pathname, F_OK | R_OK | W_OK))
570         if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
571           ThrowErrno(std::string(pathname) + ": can't create directory");
572       char* save = next;
573       next = strchr(next+1,'/');
574       *save = '/';
575     }
576   } 
577
578   if (0 != access(pathname, F_OK | R_OK))
579     if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
580       ThrowErrno(std::string(pathname) + ": can't create directory");
581   return true;
582 }
583
584 bool
585 Path::createFileOnDisk() {
586   // Create the file
587   int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR);
588   if (fd < 0)
589     ThrowErrno(path + ": can't create file");
590   ::close(fd);
591
592   return true;
593 }
594
595 bool
596 Path::createTemporaryFileOnDisk(bool reuse_current) {
597   // Make this into a unique file name
598   makeUnique( reuse_current );
599
600   // create the file
601   int outFile = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666);
602   if (outFile != -1) {
603     ::close(outFile);
604     return true;
605   }
606   return false;
607 }
608
609 bool
610 Path::eraseFromDisk(bool remove_contents) const {
611   // Make sure we're dealing with a directory
612   if (isFile()) {
613     if (0 != unlink(path.c_str()))
614       ThrowErrno(path + ": can't destroy file");
615   } else if (isDirectory()) {
616     if (remove_contents) {
617       // Recursively descend the directory to remove its content
618       std::string cmd("/bin/rm -rf ");
619       cmd += path;
620       system(cmd.c_str());
621     } else {
622       // Otherwise, try to just remove the one directory
623       char pathname[MAXPATHLEN];
624       path.copy(pathname,MAXPATHLEN);
625       int lastchar = path.length() - 1 ; 
626       if (pathname[lastchar] == '/') 
627         pathname[lastchar] = 0;
628       else
629         pathname[lastchar+1] = 0;
630       if ( 0 != rmdir(pathname))
631         ThrowErrno(std::string(pathname) + ": can't destroy directory");
632     }
633   }
634   else
635     return false;
636   return true;
637 }
638
639 bool
640 Path::renamePathOnDisk(const Path& newName) {
641   if (0 != ::rename(path.c_str(), newName.c_str()))
642     ThrowErrno(std::string("can't rename '") + path + "' as '" + 
643                newName.toString() + "' ");
644   return true;
645 }
646
647 bool
648 Path::setStatusInfoOnDisk(const StatusInfo& si) const {
649   struct utimbuf utb;
650   utb.actime = si.modTime.toPosixTime();
651   utb.modtime = utb.actime;
652   if (0 != ::utime(path.c_str(),&utb))
653     ThrowErrno(path + ": can't set file modification time");
654   if (0 != ::chmod(path.c_str(),si.mode))
655     ThrowErrno(path + ": can't set mode");
656   return true;
657 }
658
659 void 
660 sys::CopyFile(const sys::Path &Dest, const sys::Path &Src) {
661   int inFile = -1;
662   int outFile = -1;
663   try {
664     inFile = ::open(Src.c_str(), O_RDONLY);
665     if (inFile == -1)
666       ThrowErrno(Src.toString() + ": can't open source file to copy: ");
667
668     outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666);
669     if (outFile == -1)
670       ThrowErrno(Dest.toString() +": can't create destination file for copy: ");
671
672     char Buffer[16*1024];
673     while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) {
674       if (Amt == -1) {
675         if (errno != EINTR && errno != EAGAIN) 
676           ThrowErrno(Src.toString()+": can't read source file: ");
677       } else {
678         char *BufPtr = Buffer;
679         while (Amt) {
680           ssize_t AmtWritten = ::write(outFile, BufPtr, Amt);
681           if (AmtWritten == -1) {
682             if (errno != EINTR && errno != EAGAIN) 
683               ThrowErrno(Dest.toString() + ": can't write destination file: ");
684           } else {
685             Amt -= AmtWritten;
686             BufPtr += AmtWritten;
687           }
688         }
689       }
690     }
691     ::close(inFile);
692     ::close(outFile);
693   } catch (...) {
694     if (inFile != -1)
695       ::close(inFile);
696     if (outFile != -1)
697       ::close(outFile);
698     throw;
699   }
700 }
701
702 void 
703 Path::makeUnique(bool reuse_current) {
704   if (reuse_current && !exists())
705     return; // File doesn't exist already, just use it!
706
707   // Append an XXXXXX pattern to the end of the file for use with mkstemp, 
708   // mktemp or our own implementation.
709   char *FNBuffer = (char*) alloca(path.size()+8);
710   path.copy(FNBuffer,path.size());
711   strcpy(FNBuffer+path.size(), "-XXXXXX");
712
713 #if defined(HAVE_MKSTEMP)
714   int TempFD;
715   if ((TempFD = mkstemp(FNBuffer)) == -1) {
716     ThrowErrno(path + ": can't make unique filename");
717   }
718
719   // We don't need to hold the temp file descriptor... we will trust that no one
720   // will overwrite/delete the file before we can open it again.
721   close(TempFD);
722
723   // Save the name
724   path = FNBuffer;
725 #elif defined(HAVE_MKTEMP)
726   // If we don't have mkstemp, use the old and obsolete mktemp function.
727   if (mktemp(FNBuffer) == 0) {
728     ThrowErrno(path + ": can't make unique filename");
729   }
730
731   // Save the name
732   path = FNBuffer;
733 #else
734   // Okay, looks like we have to do it all by our lonesome.
735   static unsigned FCounter = 0;
736   unsigned offset = path.size() + 1;
737   while ( FCounter < 999999 && exists()) {
738     sprintf(FNBuffer+offset,"%06u",++FCounter);
739     path = FNBuffer;
740   }
741   if (FCounter > 999999)
742     throw std::string(path + ": can't make unique filename: too many files");
743 #endif
744
745 }
746 }
747