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