1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2013 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
1627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
17072359ca138504065e1e0c1189eb38c09576d324Alex Vakulenko// This provides access to timestamps with nanosecond resolution in
1827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// struct stat, See NOTES in stat(2) for details.
1927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#ifndef _BSD_SOURCE
2027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#define _BSD_SOURCE
2127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#endif
2227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
2327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include "update_engine/p2p_manager.h"
2427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
2527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <errno.h>
2627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <fcntl.h>
2727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <linux/falloc.h>
2827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <signal.h>
2927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <string.h>
3027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <sys/stat.h>
3127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <sys/statvfs.h>
3227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <sys/types.h>
336f20dd4fc8861d93d188cd27323d2f9746464aafAlex Deymo#include <sys/xattr.h>
3427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <unistd.h>
3527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
36d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko#include <algorithm>
3727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <map>
3802f7c1dee242f490143791dbb73fa23fa3007cfaBen Chan#include <memory>
3927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <utility>
4027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <vector>
4127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
424a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold#include <base/bind.h>
43454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo#include <base/files/file_enumerator.h>
4475039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/files/file_path.h>
45c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo#include <base/format_macros.h>
4627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen#include <base/logging.h>
47454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo#include <base/strings/string_util.h>
4875039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/stringprintf.h>
4927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
5039910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/subprocess.h"
5139910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
524a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold#include "update_engine/update_manager/policy.h"
534a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold#include "update_engine/update_manager/update_manager.h"
5427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
554a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnoldusing base::Bind;
564a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnoldusing base::Callback;
5727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenusing base::FilePath;
5827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenusing base::StringPrintf;
5927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenusing base::Time;
6027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenusing base::TimeDelta;
613f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenkousing brillo::MessageLoop;
624a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnoldusing chromeos_update_manager::EvalStatus;
634a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnoldusing chromeos_update_manager::Policy;
644a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnoldusing chromeos_update_manager::UpdateManager;
6527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenusing std::map;
6627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenusing std::pair;
6727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenusing std::string;
6802f7c1dee242f490143791dbb73fa23fa3007cfaBen Chanusing std::unique_ptr;
6927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenusing std::vector;
7027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
7127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthennamespace chromeos_update_engine {
7227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
7327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthennamespace {
7427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
7527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// The default p2p directory.
7627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenconst char kDefaultP2PDir[] = "/var/cache/p2p";
7727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
7827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// The p2p xattr used for conveying the final size of a file - see the
7927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// p2p ddoc for details.
8027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenconst char kCrosP2PFileSizeXAttrName[] = "user.cros-p2p-filesize";
8127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
82d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko}  // namespace
8327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
8427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// The default P2PManager::Configuration implementation.
8527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenclass ConfigurationImpl : public P2PManager::Configuration {
86d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko public:
8727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  ConfigurationImpl() {}
8827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
89610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  FilePath GetP2PDir() override {
90f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo    return FilePath(kDefaultP2PDir);
9127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
9227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
93610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  vector<string> GetInitctlArgs(bool is_start) override {
9427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    vector<string> args;
9527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    args.push_back("initctl");
9627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    args.push_back(is_start ? "start" : "stop");
9727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    args.push_back("p2p");
9827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return args;
9927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
10027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
101610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  vector<string> GetP2PClientArgs(const string &file_id,
102610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo                                  size_t minimum_size) override {
10327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    vector<string> args;
10427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    args.push_back("p2p-client");
10527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    args.push_back(string("--get-url=") + file_id);
106c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo    args.push_back(StringPrintf("--minimum-size=%" PRIuS, minimum_size));
10727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return args;
10827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
10927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
110d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko private:
11127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  DISALLOW_COPY_AND_ASSIGN(ConfigurationImpl);
11227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen};
11327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
11427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// The default P2PManager implementation.
11527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenclass P2PManagerImpl : public P2PManager {
116d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko public:
11727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  P2PManagerImpl(Configuration *configuration,
11841f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen                 ClockInterface *clock,
1194a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold                 UpdateManager* update_manager,
12027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                 const string& file_extension,
12141f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen                 const int num_files_to_keep,
12229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo                 const TimeDelta& max_file_age);
12327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
12427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // P2PManager methods.
125610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  void SetDevicePolicy(const policy::DevicePolicy* device_policy) override;
126610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  bool IsP2PEnabled() override;
127610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  bool EnsureP2PRunning() override;
128610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  bool EnsureP2PNotRunning() override;
129610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  bool PerformHousekeeping() override;
130610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  void LookupUrlForFile(const string& file_id,
131610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo                        size_t minimum_size,
132610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo                        TimeDelta max_time_to_wait,
133610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo                        LookupCallback callback) override;
134610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  bool FileShare(const string& file_id,
135610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo                 size_t expected_size) override;
136610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  FilePath FileGetPath(const string& file_id) override;
137610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  ssize_t FileGetSize(const string& file_id) override;
138610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  ssize_t FileGetExpectedSize(const string& file_id) override;
139610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  bool FileGetVisible(const string& file_id,
140610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo                      bool *out_result) override;
141610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  bool FileMakeVisible(const string& file_id) override;
142610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  int CountSharedFiles() override;
14327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
144d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko private:
14527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Enumeration for specifying visibility.
14627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  enum Visibility {
14727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    kVisible,
14827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    kNonVisible
14927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  };
15027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
15127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Returns "." + |file_extension_| + ".p2p" if |visibility| is
15227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // |kVisible|. Returns the same concatenated with ".tmp" otherwise.
15327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  string GetExt(Visibility visibility);
15427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
15527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Gets the on-disk path for |file_id| depending on if the file
15627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // is visible or not.
157f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath GetPath(const string& file_id, Visibility visibility);
15827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
15927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Utility function used by EnsureP2PRunning() and EnsureP2PNotRunning().
16027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  bool EnsureP2P(bool should_be_running);
16127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
16241f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // Utility function to delete a file given by |path| and log the
16341f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // path as well as |reason|. Returns false on failure.
16429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  bool DeleteP2PFile(const FilePath& path, const string& reason);
16541f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen
1664a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  // Schedules an async request for tracking changes in P2P enabled status.
1674a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  void ScheduleEnabledStatusChange();
1684a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
1694a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  // An async callback used by the above.
1704a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  void OnEnabledStatusChange(EvalStatus status, const bool& result);
1714a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
17288b591f24cb3f94f982d7024c2e8ed25c2cc26a2Alex Vakulenko  // The device policy being used or null if no policy is being used.
1734a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  const policy::DevicePolicy* device_policy_ = nullptr;
17492d9c8bc5cd418e34944d6fc4bae44e3b4370246David Zeuthen
17527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Configuration object.
17602f7c1dee242f490143791dbb73fa23fa3007cfaBen Chan  unique_ptr<Configuration> configuration_;
17727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
17841f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // Object for telling the time.
17941f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  ClockInterface* clock_;
18041f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen
1814a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  // A pointer to the global Update Manager.
1824a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  UpdateManager* update_manager_;
1834a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
18427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // A short string unique to the application (for example "cros_au")
18527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // used to mark a file as being owned by a particular application.
18627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  const string file_extension_;
18727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
18827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // If non-zero, this number denotes how many files in /var/cache/p2p
18927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // owned by the application (cf. |file_extension_|) to keep after
19027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // performing housekeeping.
19127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  const int num_files_to_keep_;
19227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
19341f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // If non-zero, files older than this will not be kept after
19441f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // performing housekeeping.
19529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  const TimeDelta max_file_age_;
19641f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen
19727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // The string ".p2p".
19827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  static const char kP2PExtension[];
19927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
20027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // The string ".tmp".
20127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  static const char kTmpExtension[];
20227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
203ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  // Whether P2P service may be running; initially, we assume it may be.
204ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  bool may_be_running_ = true;
205ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold
2064a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  // The current known enabled status of the P2P feature (initialized lazily),
2074a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  // and whether an async status check has been scheduled.
2084a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  bool is_enabled_;
2094a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  bool waiting_for_enabled_status_change_ = false;
2104a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
21127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  DISALLOW_COPY_AND_ASSIGN(P2PManagerImpl);
21227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen};
21327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
21427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenconst char P2PManagerImpl::kP2PExtension[] = ".p2p";
21527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
21627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenconst char P2PManagerImpl::kTmpExtension[] = ".tmp";
21727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
21827a48bc3f2531166370c214f7a21e17fb1fc7af1David ZeuthenP2PManagerImpl::P2PManagerImpl(Configuration *configuration,
21941f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen                               ClockInterface *clock,
2204a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold                               UpdateManager* update_manager,
22127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                               const string& file_extension,
22241f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen                               const int num_files_to_keep,
22329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo                               const TimeDelta& max_file_age)
2244a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  : clock_(clock),
2254a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    update_manager_(update_manager),
22627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    file_extension_(file_extension),
22741f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    num_files_to_keep_(num_files_to_keep),
22841f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    max_file_age_(max_file_age) {
22988b591f24cb3f94f982d7024c2e8ed25c2cc26a2Alex Vakulenko  configuration_.reset(configuration != nullptr ? configuration :
23027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                       new ConfigurationImpl());
23127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
23227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
23392d9c8bc5cd418e34944d6fc4bae44e3b4370246David Zeuthenvoid P2PManagerImpl::SetDevicePolicy(
23492d9c8bc5cd418e34944d6fc4bae44e3b4370246David Zeuthen    const policy::DevicePolicy* device_policy) {
23592d9c8bc5cd418e34944d6fc4bae44e3b4370246David Zeuthen  device_policy_ = device_policy;
23627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
23727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
23827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenbool P2PManagerImpl::IsP2PEnabled() {
2394a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  if (!waiting_for_enabled_status_change_) {
2404a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    // Get and store an initial value.
2414a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    if (update_manager_->PolicyRequest(&Policy::P2PEnabled, &is_enabled_) ==
2424a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold        EvalStatus::kFailed) {
2434a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold      is_enabled_ = false;
2444a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold      LOG(ERROR) << "Querying P2P enabled status failed, disabling.";
24592d9c8bc5cd418e34944d6fc4bae44e3b4370246David Zeuthen    }
2464a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
2474a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    // Track future changes (async).
2484a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    ScheduleEnabledStatusChange();
24992d9c8bc5cd418e34944d6fc4bae44e3b4370246David Zeuthen  }
25092d9c8bc5cd418e34944d6fc4bae44e3b4370246David Zeuthen
2514a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  return is_enabled_;
25227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
25327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
25427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenbool P2PManagerImpl::EnsureP2P(bool should_be_running) {
25529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  int return_code = 0;
25629b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  string output;
25727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
258ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  may_be_running_ = true;  // Unless successful, we must be conservative.
259ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold
26027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  vector<string> args = configuration_->GetInitctlArgs(should_be_running);
26129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  if (!Subprocess::SynchronousExec(args, &return_code, &output)) {
26229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    LOG(ERROR) << "Error spawning " << utils::StringVectorToString(args);
26327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return false;
26427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
26527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
266ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  // If initctl(8) does not exit normally (exit status other than zero), ensure
267ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  // that the error message is not benign by scanning stderr; this is a
268ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  // necessity because initctl does not offer actions such as "start if not
269ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  // running" or "stop if running".
27027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // TODO(zeuthen,chromium:277051): Avoid doing this.
27129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  if (return_code != 0) {
27229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    const char *expected_error_message = should_be_running ?
273ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold      "initctl: Job is already running: p2p\n" :
274ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold      "initctl: Unknown instance \n";
27529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    if (output != expected_error_message)
276ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold      return false;
27727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
27827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
279ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  may_be_running_ = should_be_running;  // Successful after all.
280ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold  return true;
28127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
28227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
28327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenbool P2PManagerImpl::EnsureP2PRunning() {
28427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return EnsureP2P(true);
28527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
28627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
28727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenbool P2PManagerImpl::EnsureP2PNotRunning() {
28827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return EnsureP2P(false);
28927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
29027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
29127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// Returns True if the timestamp in the first pair is greater than the
29227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// timestamp in the latter. If used with std::sort() this will yield a
29327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// sequence of elements where newer (high timestamps) elements precede
29427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// older ones (low timestamps).
29527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenstatic bool MatchCompareFunc(const pair<FilePath, Time>& a,
29627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                             const pair<FilePath, Time>& b) {
29727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return a.second > b.second;
29827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
29927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
30027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenstring P2PManagerImpl::GetExt(Visibility visibility) {
30127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  string ext = string(".") + file_extension_ + kP2PExtension;
30227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  switch (visibility) {
30327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  case kVisible:
30427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    break;
30527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  case kNonVisible:
30627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    ext += kTmpExtension;
30727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    break;
30827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Don't add a default case to let the compiler warn about newly
30927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // added enum values.
31027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
31127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return ext;
31227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
31327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
31427a48bc3f2531166370c214f7a21e17fb1fc7af1David ZeuthenFilePath P2PManagerImpl::GetPath(const string& file_id, Visibility visibility) {
31527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return configuration_->GetP2PDir().Append(file_id + GetExt(visibility));
31627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
31727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
31841f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthenbool P2PManagerImpl::DeleteP2PFile(const FilePath& path,
31929b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo                                   const string& reason) {
32041f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  LOG(INFO) << "Deleting p2p file " << path.value()
32141f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen            << " (reason: " << reason << ")";
32241f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  if (unlink(path.value().c_str()) != 0) {
32341f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    PLOG(ERROR) << "Error deleting p2p file " << path.value();
32441f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    return false;
32541f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  }
32641f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  return true;
32741f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen}
32841f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen
32927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
33041f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthenbool P2PManagerImpl::PerformHousekeeping() {
33141f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // Open p2p dir.
332f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath p2p_dir = configuration_->GetP2PDir();
333454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  const string ext_visible = GetExt(kVisible);
334454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  const string ext_non_visible = GetExt(kNonVisible);
33527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
33641f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  bool deletion_failed = false;
33741f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  vector<pair<FilePath, Time>> matches;
33827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
339454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  base::FileEnumerator dir(p2p_dir, false, base::FileEnumerator::FILES);
340454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  // Go through all files and collect their mtime.
341454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  for (FilePath name = dir.Next(); !name.empty(); name = dir.Next()) {
342a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko    if (!(base::EndsWith(name.value(), ext_visible,
343a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko                         base::CompareCase::SENSITIVE) ||
344a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko          base::EndsWith(name.value(), ext_non_visible,
345a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko                         base::CompareCase::SENSITIVE))) {
34627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      continue;
347a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko    }
34827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
349454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo    Time time = dir.GetInfo().GetLastModifiedTime();
35041f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen
35141f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    // If instructed to keep only files younger than a given age
35241f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    // (|max_file_age_| != 0), delete files satisfying this criteria
35341f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    // right now. Otherwise add it to a list we'll consider for later.
35429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    if (clock_ != nullptr && max_file_age_ != TimeDelta() &&
35541f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen        clock_->GetWallclockTime() - time > max_file_age_) {
356454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo      if (!DeleteP2PFile(name, "file too old"))
35741f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen        deletion_failed = true;
35841f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    } else {
359454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo      matches.push_back(std::make_pair(name, time));
36041f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    }
36127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
36227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
36341f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // If instructed to only keep N files (|max_files_to_keep_ != 0),
36441f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // sort list of matches, newest (biggest time) to oldest (lowest
36541f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  // time). Then delete starting at element |num_files_to_keep_|.
36641f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  if (num_files_to_keep_ > 0) {
36741f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    std::sort(matches.begin(), matches.end(), MatchCompareFunc);
36841f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    vector<pair<FilePath, Time>>::const_iterator i;
36941f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen    for (i = matches.begin() + num_files_to_keep_; i < matches.end(); ++i) {
37041f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen      if (!DeleteP2PFile(i->first, "too many files"))
37141f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen        deletion_failed = true;
37227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    }
37327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
37427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
37541f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen  return !deletion_failed;
37627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
37727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
37827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen// Helper class for implementing LookupUrlForFile().
37927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenclass LookupData {
380d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko public:
381d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko  explicit LookupData(P2PManager::LookupCallback callback)
38229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    : callback_(callback) {}
38327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
38427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  ~LookupData() {
38529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    if (timeout_task_ != MessageLoop::kTaskIdNull)
38629b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo      MessageLoop::current()->CancelTask(timeout_task_);
387461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo    if (child_pid_)
388461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo      Subprocess::Get().KillExec(child_pid_);
38929b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  }
39029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo
39129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  void InitiateLookup(const vector<string>& cmd, TimeDelta timeout) {
39227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    // NOTE: if we fail early (i.e. in this method), we need to schedule
39327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    // an idle to report the error. This is because we guarantee that
39429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    // the callback is always called from the message loop (this
39527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    // guarantee is useful for testing).
39627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
39729b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    // We expect to run just "p2p-client" and find it in the path.
398461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo    child_pid_ = Subprocess::Get().ExecFlags(
399b108b608030bed6677cb86589a9df02a7df181c1Alex Deymo        cmd, Subprocess::kSearchPath, {},
400461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo        Bind(&LookupData::OnLookupDone, base::Unretained(this)));
40129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo
402461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo    if (!child_pid_) {
40329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo      LOG(ERROR) << "Error spawning " << utils::StringVectorToString(cmd);
40427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      ReportErrorAndDeleteInIdle();
40527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      return;
40627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    }
40727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
40829b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    if (timeout > TimeDelta()) {
40929b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo      timeout_task_ = MessageLoop::current()->PostDelayedTask(
41029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo          FROM_HERE,
41129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo          Bind(&LookupData::OnTimeout, base::Unretained(this)),
41229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo          timeout);
41327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    }
41427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
41527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
416d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko private:
41727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  void ReportErrorAndDeleteInIdle() {
41829b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    MessageLoop::current()->PostTask(FROM_HERE, Bind(
41929b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo        &LookupData::OnIdleForReportErrorAndDelete,
42029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo        base::Unretained(this)));
42127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
42227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
42329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  void OnIdleForReportErrorAndDelete() {
42429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    ReportError();
42529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    delete this;
42627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
42727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
42827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  void IssueCallback(const string& url) {
42927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    if (!callback_.is_null())
43027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      callback_.Run(url);
43127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
43227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
43327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  void ReportError() {
43427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    if (reported_)
43527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      return;
43627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    IssueCallback("");
43727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    reported_ = true;
43827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
43927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
44029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  void ReportSuccess(const string& output) {
44127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    if (reported_)
44227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      return;
44329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    string url = output;
44427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    size_t newline_pos = url.find('\n');
44527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    if (newline_pos != string::npos)
44627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      url.resize(newline_pos);
44727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
44827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    // Since p2p-client(1) is constructing this URL itself strictly
44927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    // speaking there's no need to validate it... but, anyway, can't
45027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    // hurt.
45127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    if (url.compare(0, 7, "http://") == 0) {
45227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      IssueCallback(url);
45327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    } else {
45427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      LOG(ERROR) << "p2p URL '" << url << "' does not look right. Ignoring.";
45527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      ReportError();
45627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    }
45727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    reported_ = true;
45827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
45927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
460461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo  void OnLookupDone(int return_code, const string& output) {
461461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo    child_pid_ = 0;
46229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    if (return_code != 0) {
46327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      LOG(INFO) << "Child exited with non-zero exit code "
46429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo                << return_code;
465461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo      ReportError();
46627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    } else {
467461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo      ReportSuccess(output);
46827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    }
469461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo    delete this;
47027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
47127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
47229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  void OnTimeout() {
47329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    timeout_task_ = MessageLoop::kTaskIdNull;
47429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    ReportError();
47529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    delete this;
47627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
47727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
47827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  P2PManager::LookupCallback callback_;
47929b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo
48029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  // The Subprocess tag of the running process. A value of 0 means that the
48129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  // process is not running.
482461b259af8815d782200782c5ba3599d8de4a66cAlex Deymo  pid_t child_pid_{0};
48329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo
48429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  // The timeout task_id we are waiting on, if any.
48529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  MessageLoop::TaskId timeout_task_{MessageLoop::kTaskIdNull};
48629b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo
48729b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  bool reported_{false};
48827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen};
48927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
49027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenvoid P2PManagerImpl::LookupUrlForFile(const string& file_id,
49127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                                      size_t minimum_size,
49227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                                      TimeDelta max_time_to_wait,
49327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                                      LookupCallback callback) {
49427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  LookupData *lookup_data = new LookupData(callback);
49527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  string file_id_with_ext = file_id + "." + file_extension_;
49627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  vector<string> args = configuration_->GetP2PClientArgs(file_id_with_ext,
49727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                                                         minimum_size);
49829b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  lookup_data->InitiateLookup(args, max_time_to_wait);
49927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
50027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
50127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenbool P2PManagerImpl::FileShare(const string& file_id,
50227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                               size_t expected_size) {
50327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Check if file already exist.
504f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath path = FileGetPath(file_id);
50527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (!path.empty()) {
50627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    // File exists - double check its expected size though.
50727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    ssize_t file_expected_size = FileGetExpectedSize(file_id);
50827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    if (file_expected_size == -1 ||
50927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen        static_cast<size_t>(file_expected_size) != expected_size) {
51027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      LOG(ERROR) << "Existing p2p file " << path.value()
51127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                 << " with expected_size=" << file_expected_size
51227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                 << " does not match the passed in"
51327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                 << " expected_size=" << expected_size;
51427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      return false;
51527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    }
51627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return true;
51727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
51827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
51927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Before creating the file, bail if statvfs(3) indicates that at
52027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // least twice the size is not available in P2P_DIR.
52127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  struct statvfs statvfsbuf;
522f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath p2p_dir = configuration_->GetP2PDir();
52327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (statvfs(p2p_dir.value().c_str(), &statvfsbuf) != 0) {
52427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    PLOG(ERROR) << "Error calling statvfs() for dir " << p2p_dir.value();
52527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return false;
52627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
52727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  size_t free_bytes =
52827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      static_cast<size_t>(statvfsbuf.f_bsize) * statvfsbuf.f_bavail;
52927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (free_bytes < 2 * expected_size) {
53027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    // This can easily happen and is worth reporting.
53127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    LOG(INFO) << "Refusing to allocate p2p file of " << expected_size
53227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen              << " bytes since the directory " << p2p_dir.value()
53327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen              << " only has " << free_bytes
53427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen              << " bytes available and this is less than twice the"
53527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen              << " requested size.";
53627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return false;
53727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
53827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
53927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Okie-dokey looks like enough space is available - create the file.
54027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  path = GetPath(file_id, kNonVisible);
54127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  int fd = open(path.value().c_str(), O_CREAT | O_RDWR, 0644);
54227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (fd == -1) {
54327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    PLOG(ERROR) << "Error creating file with path " << path.value();
54427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return false;
54527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
54627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  ScopedFdCloser fd_closer(&fd);
54727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
54827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // If the final size is known, allocate the file (e.g. reserve disk
54927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // space) and set the user.cros-p2p-filesize xattr.
55027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (expected_size != 0) {
55127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    if (fallocate(fd,
552d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko                  FALLOC_FL_KEEP_SIZE,  // Keep file size as 0.
55327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                  0,
55427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                  expected_size) != 0) {
555910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen      if (errno == ENOSYS || errno == EOPNOTSUPP) {
556910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        // If the filesystem doesn't support the fallocate, keep
557910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        // going. This is helpful when running unit tests on build
558910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        // machines with ancient filesystems and/or OSes.
559910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        PLOG(WARNING) << "Ignoring fallocate(2) failure";
560910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen      } else {
561910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        // ENOSPC can happen (funky race though, cf. the statvfs() check
562910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        // above), handle it gracefully, e.g. use logging level INFO.
563910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        PLOG(INFO) << "Error allocating " << expected_size
564910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen                   << " bytes for file " << path.value();
565910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        if (unlink(path.value().c_str()) != 0) {
566910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen          PLOG(ERROR) << "Error deleting file with path " << path.value();
567910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        }
568910ec5b95d98c81edc5a8d40bc0210b0559f371bDavid Zeuthen        return false;
56927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      }
57027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    }
57127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
572c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo    string decimal_size = std::to_string(expected_size);
57327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    if (fsetxattr(fd, kCrosP2PFileSizeXAttrName,
57427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                  decimal_size.c_str(), decimal_size.size(), 0) != 0) {
57527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      PLOG(ERROR) << "Error setting xattr " << path.value();
57627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      return false;
57727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    }
57827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
57927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
58027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return true;
58127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
58227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
58327a48bc3f2531166370c214f7a21e17fb1fc7af1David ZeuthenFilePath P2PManagerImpl::FileGetPath(const string& file_id) {
58427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  struct stat statbuf;
585f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath path;
58627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
58727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  path = GetPath(file_id, kVisible);
58827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (stat(path.value().c_str(), &statbuf) == 0) {
58927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return path;
59027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
59127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
59227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  path = GetPath(file_id, kNonVisible);
59327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (stat(path.value().c_str(), &statbuf) == 0) {
59427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return path;
59527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
59627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
59727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  path.clear();
59827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return path;
59927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
60027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
60127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenbool P2PManagerImpl::FileGetVisible(const string& file_id,
60227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                                    bool *out_result) {
603f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath path = FileGetPath(file_id);
60427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (path.empty()) {
60527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    LOG(ERROR) << "No file for id " << file_id;
60627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return false;
60727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
60888b591f24cb3f94f982d7024c2e8ed25c2cc26a2Alex Vakulenko  if (out_result != nullptr)
60927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    *out_result = path.MatchesExtension(kP2PExtension);
61027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return true;
61127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
61227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
61327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenbool P2PManagerImpl::FileMakeVisible(const string& file_id) {
614f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath path = FileGetPath(file_id);
61527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (path.empty()) {
61627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    LOG(ERROR) << "No file for id " << file_id;
61727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return false;
61827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
61927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
62027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  // Already visible?
62127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (path.MatchesExtension(kP2PExtension))
62227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return true;
62327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
62427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  LOG_ASSERT(path.MatchesExtension(kTmpExtension));
625f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath new_path = path.RemoveExtension();
62627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  LOG_ASSERT(new_path.MatchesExtension(kP2PExtension));
62727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (rename(path.value().c_str(), new_path.value().c_str()) != 0) {
62827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    PLOG(ERROR) << "Error renaming " << path.value()
62927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                << " to " << new_path.value();
63027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return false;
63127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
63227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
63327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return true;
63427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
63527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
63627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenssize_t P2PManagerImpl::FileGetSize(const string& file_id) {
637f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath path = FileGetPath(file_id);
63827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (path.empty())
63927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return -1;
64027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
641a77939e368597241fe0153bedce196d7152a5de5Gabe Black  return utils::FileSize(path.value());
64227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
64327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
64427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenssize_t P2PManagerImpl::FileGetExpectedSize(const string& file_id) {
645f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath path = FileGetPath(file_id);
64627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (path.empty())
64727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return -1;
64827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
64927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  char ea_value[64] = { 0 };
65027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  ssize_t ea_size;
65127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  ea_size = getxattr(path.value().c_str(), kCrosP2PFileSizeXAttrName,
65227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                     &ea_value, sizeof(ea_value) - 1);
65327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (ea_size == -1) {
65427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    PLOG(ERROR) << "Error calling getxattr() on file " << path.value();
65527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return -1;
65627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
65727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
65888b591f24cb3f94f982d7024c2e8ed25c2cc26a2Alex Vakulenko  char* endp = nullptr;
659d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko  long long int val = strtoll(ea_value, &endp, 0);  // NOLINT(runtime/int)
66027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  if (*endp != '\0') {
66127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    LOG(ERROR) << "Error parsing the value '" << ea_value
66227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen               << "' of the xattr " << kCrosP2PFileSizeXAttrName
66327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen               << " as an integer";
66427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen    return -1;
66527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
66627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
66727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return val;
66827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
66927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
67027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthenint P2PManagerImpl::CountSharedFiles() {
67127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  int num_files = 0;
67227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
673f329b933db41d26644a97afef928eb1b319d6d99Alex Deymo  FilePath p2p_dir = configuration_->GetP2PDir();
674454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  const string ext_visible = GetExt(kVisible);
675454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  const string ext_non_visible = GetExt(kNonVisible);
67627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
677454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  base::FileEnumerator dir(p2p_dir, false, base::FileEnumerator::FILES);
678454b798705352bcfbef19759f4dddfe3f0ac490cAlex Deymo  for (FilePath name = dir.Next(); !name.empty(); name = dir.Next()) {
679a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko    if (base::EndsWith(name.value(), ext_visible,
680a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko                       base::CompareCase::SENSITIVE) ||
681a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko        base::EndsWith(name.value(), ext_non_visible,
682a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko                       base::CompareCase::SENSITIVE)) {
68327a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen      num_files += 1;
684a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko    }
68527a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  }
68627a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
68727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return num_files;
68827a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
68927a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
6904a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnoldvoid P2PManagerImpl::ScheduleEnabledStatusChange() {
6914a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  if (waiting_for_enabled_status_change_)
6924a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    return;
693ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold
6944a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  Callback<void(EvalStatus, const bool&)> callback = Bind(
6954a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold      &P2PManagerImpl::OnEnabledStatusChange, base::Unretained(this));
6964a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  update_manager_->AsyncPolicyRequest(callback, &Policy::P2PEnabledChanged,
6974a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold                                      is_enabled_);
6984a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  waiting_for_enabled_status_change_ = true;
6994a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold}
700ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold
7014a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnoldvoid P2PManagerImpl::OnEnabledStatusChange(EvalStatus status,
7024a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold                                           const bool& result) {
7034a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  waiting_for_enabled_status_change_ = false;
7044a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
7054a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  if (status == EvalStatus::kSucceeded) {
7064a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    if (result == is_enabled_) {
7074a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold      LOG(WARNING) << "P2P enabled status did not change, which means that it "
7084a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold                      "is permanent; not scheduling further checks.";
7094a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold      waiting_for_enabled_status_change_ = true;
7104a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold      return;
7114a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    }
7124a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
7134a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    is_enabled_ = result;
7144a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
7154a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    // If P2P is running but shouldn't be, make sure it isn't.
7164a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    if (may_be_running_ && !is_enabled_ && !EnsureP2PNotRunning()) {
7174a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold      LOG(WARNING) << "Failed to stop P2P service.";
7184a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    }
7194a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  } else {
7204a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    LOG(WARNING)
7214a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold        << "P2P enabled tracking failed (possibly timed out); retrying.";
7224a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  }
7234a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold
7244a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold  ScheduleEnabledStatusChange();
725ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold}
726ccd0957b359136aca2d4d5c7728535d8a2e33c51Gilad Arnold
7274a0321b804524e001b482edea882bd1fc4af98a2Gilad ArnoldP2PManager* P2PManager::Construct(
7284a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    Configuration *configuration,
7294a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    ClockInterface *clock,
7304a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    UpdateManager* update_manager,
7314a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    const string& file_extension,
7324a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold    const int num_files_to_keep,
73329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    const TimeDelta& max_file_age) {
73427a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen  return new P2PManagerImpl(configuration,
73541f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen                            clock,
7364a0321b804524e001b482edea882bd1fc4af98a2Gilad Arnold                            update_manager,
73727a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen                            file_extension,
73841f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen                            num_files_to_keep,
73941f2cf52137dd94ef9115e27ec8729a126edb0ffDavid Zeuthen                            max_file_age);
74027a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}
74127a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen
74227a48bc3f2531166370c214f7a21e17fb1fc7af1David Zeuthen}  // namespace chromeos_update_engine
743