LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - file_util_posix.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 320 0 0.0 %
Date: 2012-06-02 Functions: 32 0 0.0 %

       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 <dirent.h>
       8                 : #include <errno.h>
       9                 : #include <fcntl.h>
      10                 : #include <fnmatch.h>
      11                 : #ifndef ANDROID
      12                 : #include <fts.h>
      13                 : #endif
      14                 : #include <libgen.h>
      15                 : #include <stdio.h>
      16                 : #include <string.h>
      17                 : #include <sys/errno.h>
      18                 : #include <sys/mman.h>
      19                 : #include <sys/stat.h>
      20                 : #include <sys/types.h>
      21                 : #include <time.h>
      22                 : #include <unistd.h>
      23                 : 
      24                 : #include <fstream>
      25                 : 
      26                 : #include "base/basictypes.h"
      27                 : #include "base/eintr_wrapper.h"
      28                 : #include "base/file_path.h"
      29                 : #include "base/logging.h"
      30                 : #include "base/string_util.h"
      31                 : #include "base/time.h"
      32                 : 
      33                 : // FreeBSD/OpenBSD lacks stat64, but its stat handles files >2GB just fine
      34                 : #if defined(OS_FREEBSD) || defined(OS_OPENBSD)
      35                 : #define stat64 stat
      36                 : #endif
      37                 : 
      38                 : namespace file_util {
      39                 : 
      40                 : #if defined(GOOGLE_CHROME_BUILD)
      41                 : static const char* kTempFileName = "com.google.chrome.XXXXXX";
      42                 : #else
      43                 : static const char* kTempFileName = "org.chromium.XXXXXX";
      44                 : #endif
      45                 : 
      46               0 : std::wstring GetDirectoryFromPath(const std::wstring& path) {
      47               0 :   if (EndsWithSeparator(path)) {
      48               0 :     std::wstring dir = path;
      49               0 :     TrimTrailingSeparator(&dir);
      50               0 :     return dir;
      51                 :   } else {
      52                 :     char full_path[PATH_MAX];
      53               0 :     base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path));
      54               0 :     return UTF8ToWide(dirname(full_path));
      55                 :   }
      56                 : }
      57                 : 
      58               0 : bool AbsolutePath(FilePath* path) {
      59                 :   char full_path[PATH_MAX];
      60               0 :   if (realpath(path->value().c_str(), full_path) == NULL)
      61               0 :     return false;
      62               0 :   *path = FilePath(full_path);
      63               0 :   return true;
      64                 : }
      65                 : 
      66               0 : int CountFilesCreatedAfter(const FilePath& path,
      67                 :                            const base::Time& comparison_time) {
      68               0 :   int file_count = 0;
      69                 : 
      70               0 :   DIR* dir = opendir(path.value().c_str());
      71               0 :   if (dir) {
      72                 :     struct dirent ent_buf;
      73                 :     struct dirent* ent;
      74               0 :     while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
      75               0 :       if ((strcmp(ent->d_name, ".") == 0) ||
      76               0 :           (strcmp(ent->d_name, "..") == 0))
      77               0 :         continue;
      78                 : 
      79                 :       struct stat64 st;
      80               0 :       int test = stat64(path.Append(ent->d_name).value().c_str(), &st);
      81               0 :       if (test != 0) {
      82               0 :         LOG(ERROR) << "stat64 failed: " << strerror(errno);
      83               0 :         continue;
      84                 :       }
      85                 :       // Here, we use Time::TimeT(), which discards microseconds. This
      86                 :       // means that files which are newer than |comparison_time| may
      87                 :       // be considered older. If we don't discard microseconds, it
      88                 :       // introduces another issue. Suppose the following case:
      89                 :       //
      90                 :       // 1. Get |comparison_time| by Time::Now() and the value is 10.1 (secs).
      91                 :       // 2. Create a file and the current time is 10.3 (secs).
      92                 :       //
      93                 :       // As POSIX doesn't have microsecond precision for |st_ctime|,
      94                 :       // the creation time of the file created in the step 2 is 10 and
      95                 :       // the file is considered older than |comparison_time|. After
      96                 :       // all, we may have to accept either of the two issues: 1. files
      97                 :       // which are older than |comparison_time| are considered newer
      98                 :       // (current implementation) 2. files newer than
      99                 :       // |comparison_time| are considered older.
     100               0 :       if (st.st_ctime >= comparison_time.ToTimeT())
     101               0 :         ++file_count;
     102                 :     }
     103               0 :     closedir(dir);
     104                 :   }
     105               0 :   return file_count;
     106                 : }
     107                 : 
     108                 : // TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
     109                 : // which works both with and without the recursive flag.  I'm not sure we need
     110                 : // that functionality. If not, remove from file_util_win.cc, otherwise add it
     111                 : // here.
     112               0 : bool Delete(const FilePath& path, bool recursive) {
     113               0 :   const char* path_str = path.value().c_str();
     114                 :   struct stat64 file_info;
     115               0 :   int test = stat64(path_str, &file_info);
     116               0 :   if (test != 0) {
     117                 :     // The Windows version defines this condition as success.
     118               0 :     bool ret = (errno == ENOENT || errno == ENOTDIR);
     119               0 :     return ret;
     120                 :   }
     121               0 :   if (!S_ISDIR(file_info.st_mode))
     122               0 :     return (unlink(path_str) == 0);
     123               0 :   if (!recursive)
     124               0 :     return (rmdir(path_str) == 0);
     125                 : 
     126                 : #ifdef ANDROID
     127                 :   // XXX Need ftsless impl for bionic
     128                 :   return false;
     129                 : #else
     130               0 :   bool success = true;
     131               0 :   int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
     132                 :   char top_dir[PATH_MAX];
     133               0 :   if (base::strlcpy(top_dir, path_str,
     134               0 :                     arraysize(top_dir)) >= arraysize(top_dir)) {
     135               0 :     return false;
     136                 :   }
     137               0 :   char* dir_list[2] = { top_dir, NULL };
     138               0 :   FTS* fts = fts_open(dir_list, ftsflags, NULL);
     139               0 :   if (fts) {
     140               0 :     FTSENT* fts_ent = fts_read(fts);
     141               0 :     while (success && fts_ent != NULL) {
     142               0 :       switch (fts_ent->fts_info) {
     143                 :         case FTS_DNR:
     144                 :         case FTS_ERR:
     145                 :           // log error
     146               0 :           success = false;
     147               0 :           continue;
     148                 :           break;
     149                 :         case FTS_DP:
     150               0 :           success = (rmdir(fts_ent->fts_accpath) == 0);
     151               0 :           break;
     152                 :         case FTS_D:
     153               0 :           break;
     154                 :         case FTS_NSOK:
     155                 :         case FTS_F:
     156                 :         case FTS_SL:
     157                 :         case FTS_SLNONE:
     158               0 :           success = (unlink(fts_ent->fts_accpath) == 0);
     159               0 :           break;
     160                 :         default:
     161               0 :           DCHECK(false);
     162               0 :           break;
     163                 :       }
     164               0 :       fts_ent = fts_read(fts);
     165                 :     }
     166               0 :     fts_close(fts);
     167                 :   }
     168               0 :   return success;
     169                 : #endif
     170                 : }
     171                 : 
     172               0 : bool Move(const FilePath& from_path, const FilePath& to_path) {
     173               0 :   if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
     174               0 :     return true;
     175                 : 
     176               0 :   if (!CopyDirectory(from_path, to_path, true))
     177               0 :     return false;
     178                 : 
     179               0 :   Delete(from_path, true);
     180               0 :   return true;
     181                 : }
     182                 : 
     183               0 : bool CopyDirectory(const FilePath& from_path,
     184                 :                    const FilePath& to_path,
     185                 :                    bool recursive) {
     186                 :   // Some old callers of CopyDirectory want it to support wildcards.
     187                 :   // After some discussion, we decided to fix those callers.
     188                 :   // Break loudly here if anyone tries to do this.
     189                 :   // TODO(evanm): remove this once we're sure it's ok.
     190               0 :   DCHECK(to_path.value().find('*') == std::string::npos);
     191               0 :   DCHECK(from_path.value().find('*') == std::string::npos);
     192                 : 
     193                 :   char top_dir[PATH_MAX];
     194               0 :   if (base::strlcpy(top_dir, from_path.value().c_str(),
     195               0 :                     arraysize(top_dir)) >= arraysize(top_dir)) {
     196               0 :     return false;
     197                 :   }
     198                 : 
     199                 : #ifdef ANDROID
     200                 :   // XXX Need ftsless impl for bionic
     201                 :   return false;
     202                 : #else
     203               0 :   char* dir_list[] = { top_dir, NULL };
     204               0 :   FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL);
     205               0 :   if (!fts) {
     206               0 :     LOG(ERROR) << "fts_open failed: " << strerror(errno);
     207               0 :     return false;
     208                 :   }
     209                 : 
     210               0 :   int error = 0;
     211                 :   FTSENT* ent;
     212               0 :   while (!error && (ent = fts_read(fts)) != NULL) {
     213                 :     // ent->fts_path is the source path, including from_path, so paste
     214                 :     // the suffix after from_path onto to_path to create the target_path.
     215               0 :     std::string suffix(&ent->fts_path[from_path.value().size()]);
     216                 :     // Strip the leading '/' (if any).
     217               0 :     if (!suffix.empty()) {
     218               0 :       DCHECK_EQ('/', suffix[0]);
     219               0 :       suffix.erase(0, 1);
     220                 :     }
     221               0 :     const FilePath target_path = to_path.Append(suffix);
     222               0 :     switch (ent->fts_info) {
     223                 :       case FTS_D:  // Preorder directory.
     224                 :         // If we encounter a subdirectory in a non-recursive copy, prune it
     225                 :         // from the traversal.
     226               0 :         if (!recursive && ent->fts_level > 0) {
     227               0 :           if (fts_set(fts, ent, FTS_SKIP) != 0)
     228               0 :             error = errno;
     229               0 :           continue;
     230                 :         }
     231                 : 
     232                 :         // Try creating the target dir, continuing on it if it exists already.
     233                 :         // Rely on the user's umask to produce correct permissions.
     234               0 :         if (mkdir(target_path.value().c_str(), 0777) != 0) {
     235               0 :           if (errno != EEXIST)
     236               0 :             error = errno;
     237                 :         }
     238               0 :         break;
     239                 :       case FTS_F:     // Regular file.
     240                 :       case FTS_NSOK:  // File, no stat info requested.
     241               0 :         errno = 0;
     242               0 :         if (!CopyFile(FilePath(ent->fts_path), target_path))
     243               0 :           error = errno ? errno : EINVAL;
     244               0 :         break;
     245                 :       case FTS_DP:   // Postorder directory.
     246                 :       case FTS_DOT:  // "." or ".."
     247                 :         // Skip it.
     248               0 :         continue;
     249                 :       case FTS_DC:   // Directory causing a cycle.
     250                 :         // Skip this branch.
     251               0 :         if (fts_set(fts, ent, FTS_SKIP) != 0)
     252               0 :           error = errno;
     253               0 :         break;
     254                 :       case FTS_DNR:  // Directory cannot be read.
     255                 :       case FTS_ERR:  // Error.
     256                 :       case FTS_NS:   // Stat failed.
     257                 :         // Abort with the error.
     258               0 :         error = ent->fts_errno;
     259               0 :         break;
     260                 :       case FTS_SL:      // Symlink.
     261                 :       case FTS_SLNONE:  // Symlink with broken target.
     262               0 :         LOG(WARNING) << "CopyDirectory() skipping symbolic link: " <<
     263               0 :             ent->fts_path;
     264               0 :         continue;
     265                 :       case FTS_DEFAULT:  // Some other sort of file.
     266               0 :         LOG(WARNING) << "CopyDirectory() skipping file of unknown type: " <<
     267               0 :             ent->fts_path;
     268               0 :         continue;
     269                 :       default:
     270               0 :         NOTREACHED();
     271               0 :         continue;  // Hope for the best!
     272                 :     }
     273                 :   }
     274                 :   // fts_read may have returned NULL and set errno to indicate an error.
     275               0 :   if (!error && errno != 0)
     276               0 :     error = errno;
     277                 : 
     278               0 :   if (!fts_close(fts)) {
     279                 :     // If we already have an error, let's use that error instead of the error
     280                 :     // fts_close set.
     281               0 :     if (!error)
     282               0 :       error = errno;
     283                 :   }
     284                 : 
     285               0 :   if (error) {
     286               0 :     LOG(ERROR) << "CopyDirectory(): " << strerror(error);
     287               0 :     return false;
     288                 :   }
     289               0 :   return true;
     290                 : #endif
     291                 : }
     292                 : 
     293               0 : bool PathExists(const FilePath& path) {
     294                 :   struct stat64 file_info;
     295               0 :   return (stat64(path.value().c_str(), &file_info) == 0);
     296                 : }
     297                 : 
     298               0 : bool PathIsWritable(const FilePath& path) {
     299               0 :   FilePath test_path(path);
     300                 :   struct stat64 file_info;
     301               0 :   if (stat64(test_path.value().c_str(), &file_info) != 0) {
     302                 :     // If the path doesn't exist, test the parent dir.
     303               0 :     test_path = test_path.DirName();
     304                 :     // If the parent dir doesn't exist, then return false (the path is not
     305                 :     // directly writable).
     306               0 :     if (stat64(test_path.value().c_str(), &file_info) != 0)
     307               0 :       return false;
     308                 :   }
     309               0 :   if (S_IWOTH & file_info.st_mode)
     310               0 :     return true;
     311               0 :   if (getegid() == file_info.st_gid && (S_IWGRP & file_info.st_mode))
     312               0 :     return true;
     313               0 :   if (geteuid() == file_info.st_uid && (S_IWUSR & file_info.st_mode))
     314               0 :     return true;
     315               0 :   return false;
     316                 : }
     317                 : 
     318               0 : bool DirectoryExists(const FilePath& path) {
     319                 :   struct stat64 file_info;
     320               0 :   if (stat64(path.value().c_str(), &file_info) == 0)
     321               0 :     return S_ISDIR(file_info.st_mode);
     322               0 :   return false;
     323                 : }
     324                 : 
     325                 : // TODO(erikkay): implement
     326                 : #if 0
     327                 : bool GetFileCreationLocalTimeFromHandle(int fd,
     328                 :                                         LPSYSTEMTIME creation_time) {
     329                 :   if (!file_handle)
     330                 :     return false;
     331                 : 
     332                 :   FILETIME utc_filetime;
     333                 :   if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
     334                 :     return false;
     335                 : 
     336                 :   FILETIME local_filetime;
     337                 :   if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
     338                 :     return false;
     339                 : 
     340                 :   return !!FileTimeToSystemTime(&local_filetime, creation_time);
     341                 : }
     342                 : 
     343                 : bool GetFileCreationLocalTime(const std::string& filename,
     344                 :                               LPSYSTEMTIME creation_time) {
     345                 :   ScopedHandle file_handle(
     346                 :       CreateFile(filename.c_str(), GENERIC_READ,
     347                 :                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
     348                 :                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
     349                 :   return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
     350                 : }
     351                 : #endif
     352                 : 
     353               0 : bool ReadFromFD(int fd, char* buffer, size_t bytes) {
     354               0 :   size_t total_read = 0;
     355               0 :   while (total_read < bytes) {
     356                 :     ssize_t bytes_read =
     357               0 :         HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
     358               0 :     if (bytes_read <= 0)
     359               0 :       break;
     360               0 :     total_read += bytes_read;
     361                 :   }
     362               0 :   return total_read == bytes;
     363                 : }
     364                 : 
     365                 : // Creates and opens a temporary file in |directory|, returning the
     366                 : // file descriptor.  |path| is set to the temporary file path.
     367                 : // Note TODO(erikkay) comment in header for BlahFileName() calls; the
     368                 : // intent is to rename these files BlahFile() (since they create
     369                 : // files, not filenames).  This function does NOT unlink() the file.
     370               0 : int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
     371               0 :   *path = directory.Append(kTempFileName);
     372               0 :   const std::string& tmpdir_string = path->value();
     373                 :   // this should be OK since mkstemp just replaces characters in place
     374               0 :   char* buffer = const_cast<char*>(tmpdir_string.c_str());
     375                 : 
     376               0 :   return mkstemp(buffer);
     377                 : }
     378                 : 
     379               0 : bool CreateTemporaryFileName(FilePath* path) {
     380               0 :   FilePath directory;
     381               0 :   if (!GetTempDir(&directory))
     382               0 :     return false;
     383               0 :   int fd = CreateAndOpenFdForTemporaryFile(directory, path);
     384               0 :   if (fd < 0)
     385               0 :     return false;
     386               0 :   close(fd);
     387               0 :   return true;
     388                 : }
     389                 : 
     390               0 : FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) {
     391               0 :   FilePath directory;
     392               0 :   if (!GetShmemTempDir(&directory))
     393               0 :     return false;
     394                 : 
     395               0 :   return CreateAndOpenTemporaryFileInDir(directory, path);
     396                 : }
     397                 : 
     398               0 : FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
     399               0 :   int fd = CreateAndOpenFdForTemporaryFile(dir, path);
     400               0 :   if (fd < 0)
     401               0 :     return NULL;
     402                 : 
     403               0 :   return fdopen(fd, "a+");
     404                 : }
     405                 : 
     406               0 : bool CreateTemporaryFileNameInDir(const std::wstring& dir,
     407                 :                                   std::wstring* temp_file) {
     408                 :   // Not implemented yet.
     409               0 :   NOTREACHED();
     410               0 :   return false;
     411                 : }
     412                 : 
     413               0 : bool CreateNewTempDirectory(const FilePath::StringType& prefix,
     414                 :                             FilePath* new_temp_path) {
     415               0 :   FilePath tmpdir;
     416               0 :   if (!GetTempDir(&tmpdir))
     417               0 :     return false;
     418               0 :   tmpdir = tmpdir.Append(kTempFileName);
     419               0 :   std::string tmpdir_string = tmpdir.value();
     420                 :   // this should be OK since mkdtemp just replaces characters in place
     421               0 :   char* buffer = const_cast<char*>(tmpdir_string.c_str());
     422                 : #ifdef ANDROID
     423                 :   char* dtemp = NULL;
     424                 : #else
     425               0 :   char* dtemp = mkdtemp(buffer);
     426                 : #endif
     427               0 :   if (!dtemp)
     428               0 :     return false;
     429               0 :   *new_temp_path = FilePath(dtemp);
     430               0 :   return true;
     431                 : }
     432                 : 
     433               0 : bool CreateDirectory(const FilePath& full_path) {
     434               0 :   std::vector<FilePath> subpaths;
     435                 : 
     436                 :   // Collect a list of all parent directories.
     437               0 :   FilePath last_path = full_path;
     438               0 :   subpaths.push_back(full_path);
     439               0 :   for (FilePath path = full_path.DirName();
     440               0 :        path.value() != last_path.value(); path = path.DirName()) {
     441               0 :     subpaths.push_back(path);
     442               0 :     last_path = path;
     443                 :   }
     444                 : 
     445                 :   // Iterate through the parents and create the missing ones.
     446               0 :   for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
     447               0 :        i != subpaths.rend(); ++i) {
     448               0 :     if (!DirectoryExists(*i)) {
     449               0 :       if (mkdir(i->value().c_str(), 0777) != 0)
     450               0 :         return false;
     451                 :     }
     452                 :   }
     453               0 :   return true;
     454                 : }
     455                 : 
     456               0 : bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
     457                 :   struct stat64 file_info;
     458               0 :   if (stat64(file_path.value().c_str(), &file_info) != 0)
     459               0 :     return false;
     460               0 :   results->is_directory = S_ISDIR(file_info.st_mode);
     461               0 :   results->size = file_info.st_size;
     462               0 :   return true;
     463                 : }
     464                 : 
     465               0 : FILE* OpenFile(const std::string& filename, const char* mode) {
     466               0 :   return OpenFile(FilePath(filename), mode);
     467                 : }
     468                 : 
     469               0 : FILE* OpenFile(const FilePath& filename, const char* mode) {
     470               0 :   return fopen(filename.value().c_str(), mode);
     471                 : }
     472                 : 
     473               0 : int ReadFile(const FilePath& filename, char* data, int size) {
     474               0 :   int fd = open(filename.value().c_str(), O_RDONLY);
     475               0 :   if (fd < 0)
     476               0 :     return -1;
     477                 : 
     478               0 :   int ret_value = HANDLE_EINTR(read(fd, data, size));
     479               0 :   HANDLE_EINTR(close(fd));
     480               0 :   return ret_value;
     481                 : }
     482                 : 
     483               0 : int WriteFile(const FilePath& filename, const char* data, int size) {
     484               0 :   int fd = creat(filename.value().c_str(), 0666);
     485               0 :   if (fd < 0)
     486               0 :     return -1;
     487                 : 
     488                 :   // Allow for partial writes
     489               0 :   ssize_t bytes_written_total = 0;
     490               0 :   do {
     491                 :     ssize_t bytes_written_partial =
     492               0 :       HANDLE_EINTR(write(fd, data + bytes_written_total,
     493                 :                          size - bytes_written_total));
     494               0 :     if (bytes_written_partial < 0) {
     495               0 :       HANDLE_EINTR(close(fd));
     496               0 :       return -1;
     497                 :     }
     498               0 :     bytes_written_total += bytes_written_partial;
     499                 :   } while (bytes_written_total < size);
     500                 : 
     501               0 :   HANDLE_EINTR(close(fd));
     502               0 :   return bytes_written_total;
     503                 : }
     504                 : 
     505                 : // Gets the current working directory for the process.
     506               0 : bool GetCurrentDirectory(FilePath* dir) {
     507               0 :   char system_buffer[PATH_MAX] = "";
     508               0 :   if (!getcwd(system_buffer, sizeof(system_buffer))) {
     509               0 :     NOTREACHED();
     510               0 :     return false;
     511                 :   }
     512               0 :   *dir = FilePath(system_buffer);
     513               0 :   return true;
     514                 : }
     515                 : 
     516                 : // Sets the current working directory for the process.
     517               0 : bool SetCurrentDirectory(const FilePath& path) {
     518               0 :   int ret = chdir(path.value().c_str());
     519               0 :   return !ret;
     520                 : }
     521                 : 
     522                 : ///////////////////////////////////////////////
     523                 : // FileEnumerator
     524                 : 
     525               0 : FileEnumerator::FileEnumerator(const FilePath& root_path,
     526                 :                                bool recursive,
     527                 :                                FileEnumerator::FILE_TYPE file_type)
     528                 :     : recursive_(recursive),
     529                 :       file_type_(file_type),
     530                 :       is_in_find_op_(false),
     531               0 :       fts_(NULL) {
     532               0 :   pending_paths_.push(root_path);
     533               0 : }
     534                 : 
     535               0 : FileEnumerator::FileEnumerator(const FilePath& root_path,
     536                 :                                bool recursive,
     537                 :                                FileEnumerator::FILE_TYPE file_type,
     538                 :                                const FilePath::StringType& pattern)
     539                 :     : recursive_(recursive),
     540                 :       file_type_(file_type),
     541               0 :       pattern_(root_path.value()),
     542                 :       is_in_find_op_(false),
     543               0 :       fts_(NULL) {
     544                 :   // The Windows version of this code only matches against items in the top-most
     545                 :   // directory, and we're comparing fnmatch against full paths, so this is the
     546                 :   // easiest way to get the right pattern.
     547               0 :   pattern_ = pattern_.Append(pattern);
     548               0 :   pending_paths_.push(root_path);
     549               0 : }
     550                 : 
     551               0 : FileEnumerator::~FileEnumerator() {
     552                 : #ifndef ANDROID
     553               0 :   if (fts_)
     554               0 :     fts_close(fts_);
     555                 : #endif
     556               0 : }
     557                 : 
     558               0 : void FileEnumerator::GetFindInfo(FindInfo* info) {
     559               0 :   DCHECK(info);
     560                 : 
     561               0 :   if (!is_in_find_op_)
     562               0 :     return;
     563                 : 
     564                 : #ifndef ANDROID
     565               0 :   memcpy(&(info->stat), fts_ent_->fts_statp, sizeof(info->stat));
     566               0 :   info->filename.assign(fts_ent_->fts_name);
     567                 : #endif
     568                 : }
     569                 : 
     570                 : // As it stands, this method calls itself recursively when the next item of
     571                 : // the fts enumeration doesn't match (type, pattern, etc.).  In the case of
     572                 : // large directories with many files this can be quite deep.
     573                 : // TODO(erikkay) - get rid of this recursive pattern
     574               0 : FilePath FileEnumerator::Next() {
     575                 : #ifdef ANDROID
     576                 :   return FilePath();
     577                 : #else
     578               0 :   if (!is_in_find_op_) {
     579               0 :     if (pending_paths_.empty())
     580               0 :       return FilePath();
     581                 : 
     582                 :     // The last find FindFirstFile operation is done, prepare a new one.
     583               0 :     root_path_ = pending_paths_.top();
     584               0 :     root_path_ = root_path_.StripTrailingSeparators();
     585               0 :     pending_paths_.pop();
     586                 : 
     587                 :     // Start a new find operation.
     588               0 :     int ftsflags = FTS_LOGICAL;
     589                 :     char top_dir[PATH_MAX];
     590               0 :     base::strlcpy(top_dir, root_path_.value().c_str(), arraysize(top_dir));
     591               0 :     char* dir_list[2] = { top_dir, NULL };
     592               0 :     fts_ = fts_open(dir_list, ftsflags, NULL);
     593               0 :     if (!fts_)
     594               0 :       return Next();
     595               0 :     is_in_find_op_ = true;
     596                 :   }
     597                 : 
     598               0 :   fts_ent_ = fts_read(fts_);
     599               0 :   if (fts_ent_ == NULL) {
     600               0 :     fts_close(fts_);
     601               0 :     fts_ = NULL;
     602               0 :     is_in_find_op_ = false;
     603               0 :     return Next();
     604                 :   }
     605                 : 
     606                 :   // Level 0 is the top, which is always skipped.
     607               0 :   if (fts_ent_->fts_level == 0)
     608               0 :     return Next();
     609                 : 
     610                 :   // Patterns are only matched on the items in the top-most directory.
     611                 :   // (see Windows implementation)
     612               0 :   if (fts_ent_->fts_level == 1 && pattern_.value().length() > 0) {
     613               0 :     if (fnmatch(pattern_.value().c_str(), fts_ent_->fts_path, 0) != 0) {
     614               0 :       if (fts_ent_->fts_info == FTS_D)
     615               0 :         fts_set(fts_, fts_ent_, FTS_SKIP);
     616               0 :       return Next();
     617                 :     }
     618                 :   }
     619                 : 
     620               0 :   FilePath cur_file(fts_ent_->fts_path);
     621               0 :   if (fts_ent_->fts_info == FTS_D) {
     622                 :     // If not recursive, then prune children.
     623               0 :     if (!recursive_)
     624               0 :       fts_set(fts_, fts_ent_, FTS_SKIP);
     625               0 :     return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
     626               0 :   } else if (fts_ent_->fts_info == FTS_F) {
     627               0 :     return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
     628                 :   }
     629                 :   // TODO(erikkay) - verify that the other fts_info types aren't interesting
     630               0 :   return Next();
     631                 : #endif
     632                 : }
     633                 : 
     634                 : ///////////////////////////////////////////////
     635                 : // MemoryMappedFile
     636                 : 
     637               0 : MemoryMappedFile::MemoryMappedFile()
     638                 :     : file_(-1),
     639                 :       data_(NULL),
     640               0 :       length_(0) {
     641               0 : }
     642                 : 
     643               0 : bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
     644               0 :   file_ = open(file_name.value().c_str(), O_RDONLY);
     645               0 :   if (file_ == -1)
     646               0 :     return false;
     647                 : 
     648                 :   struct stat file_stat;
     649               0 :   if (fstat(file_, &file_stat) == -1)
     650               0 :     return false;
     651               0 :   length_ = file_stat.st_size;
     652                 : 
     653                 :   data_ = static_cast<uint8*>(
     654               0 :       mmap(NULL, length_, PROT_READ, MAP_SHARED, file_, 0));
     655               0 :   if (data_ == MAP_FAILED)
     656               0 :     data_ = NULL;
     657               0 :   return data_ != NULL;
     658                 : }
     659                 : 
     660               0 : void MemoryMappedFile::CloseHandles() {
     661               0 :   if (data_ != NULL)
     662               0 :     munmap(data_, length_);
     663               0 :   if (file_ != -1)
     664               0 :     close(file_);
     665                 : 
     666               0 :   data_ = NULL;
     667               0 :   length_ = 0;
     668               0 :   file_ = -1;
     669               0 : }
     670                 : 
     671                 : } // namespace file_util

Generated by: LCOV version 1.7