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