1//===--------------------- TildeExpressionResolver.cpp ----------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Utility/TildeExpressionResolver.h"
10
11#include <assert.h>
12#include <system_error>
13
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/Path.h"
18#include "llvm/Support/raw_ostream.h"
19
20#if !defined(_WIN32)
21#include <pwd.h>
22#endif
23
24using namespace lldb_private;
25using namespace llvm;
26
27namespace fs = llvm::sys::fs;
28namespace path = llvm::sys::path;
29
30TildeExpressionResolver::~TildeExpressionResolver() {}
31
32bool StandardTildeExpressionResolver::ResolveExact(
33    StringRef Expr, SmallVectorImpl<char> &Output) {
34  // We expect the tilde expression to be ONLY the expression itself, and
35  // contain no separators.
36  assert(!llvm::any_of(Expr, [](char c) { return path::is_separator(c); }));
37  assert(Expr.empty() || Expr[0] == '~');
38
39  return !fs::real_path(Expr, Output, true);
40}
41
42bool StandardTildeExpressionResolver::ResolvePartial(StringRef Expr,
43                                                     StringSet<> &Output) {
44  // We expect the tilde expression to be ONLY the expression itself, and
45  // contain no separators.
46  assert(!llvm::any_of(Expr, [](char c) { return path::is_separator(c); }));
47  assert(Expr.empty() || Expr[0] == '~');
48
49  Output.clear();
50#if defined(_WIN32) || defined(__ANDROID__)
51  return false;
52#else
53  if (Expr.empty())
54    return false;
55
56  SmallString<32> Buffer("~");
57  setpwent();
58  struct passwd *user_entry;
59  Expr = Expr.drop_front();
60
61  while ((user_entry = getpwent()) != nullptr) {
62    StringRef ThisName(user_entry->pw_name);
63    if (!ThisName.startswith(Expr))
64      continue;
65
66    Buffer.resize(1);
67    Buffer.append(ThisName);
68    Buffer.append(path::get_separator());
69    Output.insert(Buffer);
70  }
71
72  return true;
73#endif
74}
75
76bool TildeExpressionResolver::ResolveFullPath(
77    StringRef Expr, llvm::SmallVectorImpl<char> &Output) {
78  Output.clear();
79  if (!Expr.startswith("~")) {
80    Output.append(Expr.begin(), Expr.end());
81    return false;
82  }
83
84  namespace path = llvm::sys::path;
85  StringRef Left =
86      Expr.take_until([](char c) { return path::is_separator(c); });
87
88  if (!ResolveExact(Left, Output))
89    return false;
90
91  Output.append(Expr.begin() + Left.size(), Expr.end());
92  return true;
93}
94