Commit message: None
CVE: None
Vulnerability description: None

Project: Chrome

void FilePathWatcherImpl::Cancel() {
  if (!delegate_) {
    set_cancelled();
    return;
  }

  if (!message_loop()->BelongsToCurrentThread()) {
    message_loop()->PostTask(FROM_HERE,
                             new FilePathWatcher::CancelTask(this));
  } else {
    CancelOnMessageLoopThread();
  }
}

Project: Chrome

void FilePathWatcherImpl::CancelOnMessageLoopThread() {
  if (!is_cancelled())
    set_cancelled();

  if (delegate_) {
    MessageLoop::current()->RemoveDestructionObserver(this);
    delegate_ = NULL;
  }

  for (WatchVector::iterator watch_entry(watches_.begin());
       watch_entry != watches_.end(); ++watch_entry) {
    if (watch_entry->watch_ != InotifyReader::kInvalidWatch)
      g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this);
  }
  watches_.clear();
  target_.clear();
}

Project: Chrome

FilePathWatcher::FilePathWatcher() {
  impl_ = new FilePathWatcherImpl();
}

Project: Chrome

FilePathWatcherImpl::FilePathWatcherImpl()
    : delegate_(NULL) {
}

Project: Chrome

InotifyReader::InotifyReader()
    : thread_("inotify_reader"),
      inotify_fd_(inotify_init()),
      valid_(false) {
  shutdown_pipe_[0] = -1;
  shutdown_pipe_[1] = -1;
  if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
    thread_.message_loop()->PostTask(
        FROM_HERE, new InotifyReaderTask(this, inotify_fd_, shutdown_pipe_[0]));
    valid_ = true;
  }
}

Project: Chrome

void FilePathWatcherImpl::OnFilePathChanged(
    InotifyReader::Watch fired_watch,
    const FilePath::StringType& child,
    bool created,
    bool is_directory) {

  if (!message_loop()->BelongsToCurrentThread()) {
    message_loop()->PostTask(FROM_HERE,
        base::Bind(&FilePathWatcherImpl::OnFilePathChanged,
                   this,
                   fired_watch,
                   child,
                   created,
                   is_directory));
    return;
  }

  DCHECK(MessageLoopForIO::current());

  WatchVector::const_iterator watch_entry(watches_.begin());
  for ( ; watch_entry != watches_.end(); ++watch_entry) {
    if (fired_watch == watch_entry->watch_) {
      bool change_on_target_path = child.empty() ||
          ((child == watch_entry->subdir_) && watch_entry->linkname_.empty()) ||
          (child == watch_entry->linkname_);

      DCHECK(watch_entry->subdir_.empty() ||
          (watch_entry + 1) != watches_.end());
      bool target_changed =
          (watch_entry->subdir_.empty() && (child == watch_entry->linkname_)) ||
          (watch_entry->subdir_.empty() && watch_entry->linkname_.empty()) ||
          (watch_entry->subdir_ == child && (watch_entry + 1)->subdir_.empty());

      if (change_on_target_path && !UpdateWatches()) {
        delegate_->OnFilePathError(target_);
        return;
      }

      if (target_changed ||
          (change_on_target_path && !created) ||
          (change_on_target_path && file_util::PathExists(target_))) {
        delegate_->OnFilePathChanged(target_);
        return;
      }
    }
  }

}

Project: Chrome

void InotifyReader::OnInotifyEvent(const inotify_event* event) {
  if (event->mask & IN_IGNORED)
    return;

  FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
  base::AutoLock auto_lock(lock_);

  for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
       watcher != watchers_[event->wd].end();
       ++watcher) {
    (*watcher)->OnFilePathChanged(event->wd,
                                  child,
                                  event->mask & (IN_CREATE | IN_MOVED_TO),
                                  event->mask & IN_ISDIR);
  }
}

Project: Chrome

bool InotifyReader::RemoveWatch(Watch watch,
                                FilePathWatcherImpl* watcher) {
  if (!valid_)
    return false;

  base::AutoLock auto_lock(lock_);

  watchers_[watch].erase(watcher);

  if (watchers_[watch].empty()) {
    watchers_.erase(watch);
    return (inotify_rm_watch(inotify_fd_, watch) == 0);
  }

  return true;
}

Project: Chrome

   virtual void Run() {
    while (true) {
      fd_set rfds;
      FD_ZERO(&rfds);
      FD_SET(inotify_fd_, &rfds);
      FD_SET(shutdown_fd_, &rfds);

      int select_result =
        HANDLE_EINTR(select(std::max(inotify_fd_, shutdown_fd_) + 1,
                            &rfds, NULL, NULL, NULL));
      if (select_result < 0) {
        DPLOG(WARNING) << "select failed";
        return;
      }

      if (FD_ISSET(shutdown_fd_, &rfds))
        return;

      int buffer_size;
      int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd_, FIONREAD,
                                            &buffer_size));

      if (ioctl_result != 0) {
        DPLOG(WARNING) << "ioctl failed";
        return;
      }

      std::vector<char> buffer(buffer_size);

      ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd_, &buffer[0],
                                             buffer_size));

      if (bytes_read < 0) {
        DPLOG(WARNING) << "read from inotify fd failed";
        return;
      }

      ssize_t i = 0;
      while (i < bytes_read) {
        inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
        size_t event_size = sizeof(inotify_event) + event->len;
        DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
        reader_->OnInotifyEvent(event);
        i += event_size;
      }
    }
  }

Project: Chrome

bool FilePathWatcherImpl::UpdateWatches() {
  DCHECK(message_loop()->BelongsToCurrentThread());

  FilePath path(FILE_PATH_LITERAL("/"));
  bool path_valid = true;
  for (WatchVector::iterator watch_entry(watches_.begin());
       watch_entry != watches_.end(); ++watch_entry) {
    InotifyReader::Watch old_watch = watch_entry->watch_;
    if (path_valid) {
      watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this);
      if ((watch_entry->watch_ == InotifyReader::kInvalidWatch) &&
          file_util::IsLink(path)) {
        FilePath link;
        file_util::ReadSymbolicLink(path, &link);
        if (!link.IsAbsolute())
          link = path.DirName().Append(link);
        watch_entry->watch_ =
            g_inotify_reader.Get().AddWatch(link.DirName(), this);
        if (watch_entry->watch_ != InotifyReader::kInvalidWatch) {
          watch_entry->linkname_ = link.BaseName().value();
        } else {
          DPLOG(WARNING) << "Watch failed for "  << link.DirName().value();
        }
      }
      if (watch_entry->watch_ == InotifyReader::kInvalidWatch) {
        path_valid = false;
      }
    } else {
      watch_entry->watch_ = InotifyReader::kInvalidWatch;
    }
    if (old_watch != InotifyReader::kInvalidWatch &&
        old_watch != watch_entry->watch_) {
      g_inotify_reader.Get().RemoveWatch(old_watch, this);
    }
    path = path.Append(watch_entry->subdir_);
  }

  return true;
}

Project: Chrome

bool FilePathWatcherImpl::Watch(const FilePath& path,
                                FilePathWatcher::Delegate* delegate) {
  DCHECK(target_.empty());
  DCHECK(MessageLoopForIO::current());

  set_message_loop(base::MessageLoopProxy::current());
  delegate_ = delegate;
  target_ = path;
  MessageLoop::current()->AddDestructionObserver(this);

  std::vector<FilePath::StringType> comps;
  target_.GetComponents(&comps);
  DCHECK(!comps.empty());
  for (std::vector<FilePath::StringType>::const_iterator comp(++comps.begin());
       comp != comps.end(); ++comp) {
    watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp));
  }
  watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch,
                                FilePath::StringType()));
  return UpdateWatches();
}

Project: Chrome

    WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir)
        : watch_(watch),
          subdir_(subdir) {}

Project: Chrome

void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
  CancelOnMessageLoopThread();
}

Project: Chrome

  virtual ~FilePathWatcherImpl() {}