cpp

Coverage Report

Created: 2022-07-20 01:16

/home/uke/oil/cpp/leaky_osh.cc
Line
Count
Source (jump to first uncovered line)
1
// leaky_osh.cc
2
3
#include "leaky_osh.h"
4
5
#include <fcntl.h>  // AT_* Constants
6
#include <sys/stat.h>
7
#include <unistd.h>
8
9
#include "leaky_core_error.h"
10
#include "leaky_core_pyerror.h"
11
12
namespace arith_parse {
13
14
tdop::ParserSpec kArithSpec;
15
16
}  // namespace arith_parse
17
18
namespace Id = id_kind_asdl::Id;  // used below
19
20
namespace bool_stat {
21
22
2
bool isatty(Str* fd_str, word_t* blame_word) {
23
2
  int fd;
24
2
  try {
25
2
    fd = to_int(fd_str);
26
2
  } catch (ValueError* e) {
27
    // Note we don't have printf formatting here
28
1
    e_die(new Str("Invalid file descriptor TODO"), blame_word);
29
1
  }
30
  // note: we don't check errno
31
2
  int result = ::isatty(fd);
32
1
  return result;
33
2
}
34
35
0
bool DoUnaryOp(Id_t op_id, Str* s) {
36
0
  mylib::Str0 path(s);
37
38
0
  const char* zPath = path.Get();
39
40
0
  if (op_id == Id::BoolUnary_h || op_id == Id::BoolUnary_L) {
41
0
    struct stat st;
42
0
    if (lstat(zPath, &st) < 0) {
43
0
      return false;
44
0
    }
45
46
0
    return S_ISLNK(st.st_mode);
47
0
  } else {
48
0
    struct stat st;
49
0
    if (stat(zPath, &st) < 0) {
50
0
      return false;
51
0
    }
52
53
0
    auto mode = st.st_mode;
54
55
0
    switch (op_id) {
56
    // synonyms for existence
57
0
    case Id::BoolUnary_a:
58
0
    case Id::BoolUnary_e:
59
0
      return true;
60
61
0
    case Id::BoolUnary_s:
62
0
      return st.st_size != 0;
63
64
0
    case Id::BoolUnary_d:
65
0
      return S_ISDIR(mode);
66
67
0
    case Id::BoolUnary_f:
68
0
      return S_ISREG(mode);
69
70
0
    case Id::BoolUnary_k:
71
0
      return (mode & S_ISVTX) != 0;
72
73
0
    case Id::BoolUnary_p:
74
0
      return S_ISFIFO(mode);
75
76
0
    case Id::BoolUnary_O:
77
0
      return st.st_uid == geteuid();
78
79
0
    case Id::BoolUnary_G:
80
0
      return st.st_gid == getegid();
81
82
0
    case Id::BoolUnary_u:
83
0
      return mode & S_ISUID;
84
85
0
    case Id::BoolUnary_g:
86
0
      return mode & S_ISGID;
87
88
      // NOTE(Jesse): This implementation MAY have a bug.  On my system (Ubuntu
89
      // 20.04) it returns a correct result if the user is root (elevated with
90
      // sudo) and no execute bits are set for a file.
91
      //
92
      // A bug worked around in the python `posix` module here is that the above
93
      // (working) scenario is not always the case.
94
      //
95
      // https://github.com/python/cpython/blob/8d999cbf4adea053be6dbb612b9844635c4dfb8e/Modules/posixmodule.c#L2547
96
      //
97
      // As well as the dash source code found here (relative to this repo
98
      // root):
99
      //
100
      // _cache/spec-bin/dash-0.5.10.2/src/bltin/test.c
101
      // See `test_file_access()`
102
      //
103
      // We could also use the `stat` struct to manually compute the
104
      // permissions, as shown in the above `test.c`, though the code is
105
      // somewhat obtuse.
106
      //
107
      // There is further discussion of this issue in:
108
      // https://github.com/oilshell/oil/pull/1168
109
      //
110
      // And a bug filed for it at:
111
      //
112
      // https://github.com/oilshell/oil/issues/1170
113
      //
114
0
    case Id::BoolUnary_x:
115
0
      return faccessat(AT_FDCWD, zPath, X_OK, AT_EACCESS) == 0;
116
      //
117
118
0
    case Id::BoolUnary_r:
119
0
      return faccessat(AT_FDCWD, zPath, R_OK, AT_EACCESS) == 0;
120
121
0
    case Id::BoolUnary_w:
122
0
      return faccessat(AT_FDCWD, zPath, W_OK, AT_EACCESS) == 0;
123
0
    }
124
0
  }
125
126
0
  InvalidCodePath();
127
128
0
  return false;
129
0
}
130
131
0
bool DoBinaryOp(Id_t op_id, Str* s1, Str* s2) {
132
0
  mylib::Str0 left0(s1);
133
0
  mylib::Str0 right0(s2);
134
135
0
  int m1 = 0;
136
0
  struct stat st1;
137
0
  if (stat(left0.Get(), &st1) == 0) {
138
0
    m1 = st1.st_mtime;
139
0
  }
140
141
0
  int m2 = 0;
142
0
  struct stat st2;
143
0
  if (stat(right0.Get(), &st2) == 0) {
144
0
    m2 = st2.st_mtime;
145
0
  }
146
147
0
  switch (op_id) {
148
0
  case Id::BoolBinary_nt:
149
0
    return m1 > m2;
150
0
  case Id::BoolBinary_ot:
151
0
    return m1 < m2;
152
0
  case Id::BoolBinary_ef:
153
0
    return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
154
0
  }
155
156
0
  InvalidCodePath();
157
0
}
158
159
}  // namespace bool_stat