1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/file_manager/path_util.h"
6
7#include "base/files/file_path.h"
8#include "base/logging.h"
9#include "base/sys_info.h"
10#include "chrome/browser/chromeos/drive/file_system_util.h"
11#include "chrome/browser/chromeos/profiles/profile_helper.h"
12#include "chrome/browser/download/download_prefs.h"
13#include "chrome/browser/profiles/profile.h"
14#include "components/user_manager/user.h"
15#include "components/user_manager/user_manager.h"
16#include "net/base/escape.h"
17
18namespace file_manager {
19namespace util {
20
21namespace {
22
23const char kDownloadsFolderName[] = "Downloads";
24const base::FilePath::CharType kOldDownloadsFolderPath[] =
25    FILE_PATH_LITERAL("/home/chronos/user/Downloads");
26const base::FilePath::CharType kOldDriveFolderPath[] =
27    FILE_PATH_LITERAL("/special/drive");
28// Unintended path introduced in crbug.com/363026.
29const base::FilePath::CharType kBuggyDriveFolderPath[] =
30    FILE_PATH_LITERAL("/special/drive-user");
31
32}  // namespace
33
34base::FilePath GetDownloadsFolderForProfile(Profile* profile) {
35  // On non-ChromeOS system (test+development), the primary profile uses
36  // $HOME/Downloads for ease for accessing local files for debugging.
37  if (!base::SysInfo::IsRunningOnChromeOS() &&
38      user_manager::UserManager::IsInitialized()) {
39    const user_manager::User* const user =
40        chromeos::ProfileHelper::Get()->GetUserByProfile(
41            profile->GetOriginalProfile());
42    const user_manager::User* const primary_user =
43        user_manager::UserManager::Get()->GetPrimaryUser();
44    if (user == primary_user)
45      return DownloadPrefs::GetDefaultDownloadDirectory();
46  }
47  return profile->GetPath().AppendASCII(kDownloadsFolderName);
48}
49
50bool MigratePathFromOldFormat(Profile* profile,
51                              const base::FilePath& old_path,
52                              base::FilePath* new_path) {
53  // M34:
54  // /home/chronos/user/Downloads/xxx => /home/chronos/u-hash/Downloads/xxx
55  // /special/drive => /special/drive-xxx
56  //
57  // Old path format comes either from stored old settings or from the initial
58  // default value set in DownloadPrefs::RegisterProfilePrefs in profile-unaware
59  // code location. In the former case it is "/home/chronos/user/Downloads",
60  // and in the latter case it is DownloadPrefs::GetDefaultDownloadDirectory().
61  // Those two paths coincides as long as $HOME=/home/chronos/user, but the
62  // environment variable is phasing out (crbug.com/333031) so we care both.
63
64  const base::FilePath downloads = GetDownloadsFolderForProfile(profile);
65  const base::FilePath drive = drive::util::GetDriveMountPointPath(profile);
66
67  std::vector<std::pair<base::FilePath, base::FilePath> > bases;
68  bases.push_back(std::make_pair(base::FilePath(kOldDownloadsFolderPath),
69                                 downloads));
70  bases.push_back(std::make_pair(DownloadPrefs::GetDefaultDownloadDirectory(),
71                                 downloads));
72  bases.push_back(std::make_pair(base::FilePath(kOldDriveFolderPath), drive));
73  bases.push_back(std::make_pair(base::FilePath(kBuggyDriveFolderPath), drive));
74
75  // Trying migrating u-<hash>/Downloads to the current download path. This is
76  // no-op when multi-profile is enabled. This is necessary for (1) back
77  // migration when multi-profile flag is enabled and then disabled, or (2) in
78  // some edge cases (crbug.com/356322) that u-<hash> path is temporarily used.
79  if (user_manager::UserManager::IsInitialized()) {
80    const user_manager::User* const user =
81        chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
82    if (user) {
83      const base::FilePath hashed_downloads =
84          chromeos::ProfileHelper::GetProfilePathByUserIdHash(
85              user->username_hash()).AppendASCII(kDownloadsFolderName);
86      bases.push_back(std::make_pair(hashed_downloads, downloads));
87    }
88  }
89
90  for (size_t i = 0; i < bases.size(); ++i) {
91    const base::FilePath& old_base = bases[i].first;
92    const base::FilePath& new_base = bases[i].second;
93    base::FilePath relative;
94    if (old_path == old_base ||
95        old_base.AppendRelativePath(old_path, &relative)) {
96      *new_path = new_base.Append(relative);
97      return old_path != *new_path;
98    }
99  }
100
101  return false;
102}
103
104std::string GetDownloadsMountPointName(Profile* profile) {
105  // To distinguish profiles in multi-profile session, we append user name hash
106  // to "Downloads". Note that some profiles (like login or test profiles)
107  // are not associated with an user account. In that case, no suffix is added
108  // because such a profile never belongs to a multi-profile session.
109  user_manager::User* const user =
110      user_manager::UserManager::IsInitialized()
111          ? chromeos::ProfileHelper::Get()->GetUserByProfile(
112                profile->GetOriginalProfile())
113          : NULL;
114  const std::string id = user ? "-" + user->username_hash() : "";
115  return net::EscapeQueryParamValue(kDownloadsFolderName + id, false);
116}
117
118}  // namespace util
119}  // namespace file_manager
120