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