15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/self_cleaning_temp_dir.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/delete_after_reboot_helper.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace installer {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Populates |base_dir| with the topmost directory in the hierarchy of
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |temp_parent_dir| that does not exist.  If |temp_parent_dir| exists,
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |base_dir| is cleared.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SelfCleaningTempDir::GetTopDirToCreate(
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& temp_parent_dir,
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath* base_dir) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(base_dir);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (base::PathExists(temp_parent_dir)) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Empty base_dir means that we didn't create any extra directories.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base_dir->clear();
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath parent_dir(temp_parent_dir);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    do {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *base_dir = parent_dir;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_dir = parent_dir.DirName();
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } while (parent_dir != *base_dir && !base::PathExists(parent_dir));
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    LOG_IF(WARNING, !base::DirectoryExists(parent_dir))
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "A non-directory is at the base of the path leading to a desired "
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "temp directory location: " << parent_dir.value();
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelfCleaningTempDir::SelfCleaningTempDir() {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelfCleaningTempDir::~SelfCleaningTempDir() {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!path().empty() && !Delete())
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Failed to clean temp dir in dtor " << path().value();
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SelfCleaningTempDir::Initialize(const base::FilePath& parent_dir,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const StringType& temp_name) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parent_dir.IsAbsolute());
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!temp_name.empty());
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!path().empty()) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(DFATAL) << "Attempting to re-initialize a SelfSelfCleaningTempDir.";
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath temp_dir(parent_dir.Append(temp_name));
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath base_dir;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetTopDirToCreate(parent_dir, &base_dir);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (base::CreateDirectory(temp_dir)) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base_dir_ = base_dir;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    temp_dir_ = temp_dir;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SelfCleaningTempDir::Delete() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path().empty()) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(DFATAL) << "Attempting to Delete an uninitialized SelfCleaningTempDir.";
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath next_dir(path().DirName());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool schedule_deletes = false;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First try to recursively delete the leaf directory managed by our
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // base::ScopedTempDir.
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::DeleteFile(path(), true)) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // That failed, so schedule the temp dir and its contents for deletion after
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // reboot.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Failed to delete temporary directory " << path().value()
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << ". Scheduling for deletion at reboot.";
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    schedule_deletes = true;
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (!ScheduleDirectoryForDeletion(path()))
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;  // Entirely unexpected failure (Schedule logs the reason).
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now delete or schedule all empty directories up to and including our
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // base_dir_.  Any that can't be deleted are scheduled for deletion at reboot.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is safe since they'll only be deleted in that case if they're empty.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base_dir_.empty()) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    do {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!schedule_deletes && !RemoveDirectory(next_dir.value().c_str())) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PLOG_IF(WARNING, GetLastError() != ERROR_DIR_NOT_EMPTY)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << "Error removing directory " << next_dir.value().c_str();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        schedule_deletes = true;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (schedule_deletes) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Ignore the return code.  If we fail to schedule, go ahead and add the
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // other parent directories anyway.
10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        ScheduleFileSystemEntityForDeletion(next_dir);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (next_dir == base_dir_)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;  // We just processed the topmost directory we created.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_dir = next_dir.DirName();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } while (true);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base_dir_.clear();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  temp_dir_.clear();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace installer
119