| 1 | #!/usr/bin/env python2
 | 
| 2 | """Bool_stat.py.
 | 
| 3 | 
 | 
| 4 | Not translating this file directly.
 | 
| 5 | """
 | 
| 6 | from __future__ import print_function
 | 
| 7 | 
 | 
| 8 | import stat
 | 
| 9 | import posix_ as posix
 | 
| 10 | from posix_ import X_OK, R_OK, W_OK  # refers directly to C macro
 | 
| 11 | from _devbuild.gen.id_kind_asdl import Id, Id_t
 | 
| 12 | from _devbuild.gen.syntax_asdl import word_t, loc
 | 
| 13 | from core.error import e_die
 | 
| 14 | from core import ui
 | 
| 15 | 
 | 
| 16 | 
 | 
| 17 | def isatty(fd_str, blame_word):
 | 
| 18 |     # type: (str, word_t) -> bool
 | 
| 19 |     try:
 | 
| 20 |         fd = int(fd_str)
 | 
| 21 |     except ValueError:
 | 
| 22 |         e_die('Invalid file descriptor %r' % fd_str, loc.Word(blame_word))
 | 
| 23 | 
 | 
| 24 |     try:
 | 
| 25 |         return posix.isatty(fd)
 | 
| 26 |     # fd is user input, and causes this exception in the binding.
 | 
| 27 |     except OverflowError:
 | 
| 28 |         e_die('File descriptor %r is too big' % fd_str, loc.Word(blame_word))
 | 
| 29 | 
 | 
| 30 | 
 | 
| 31 | def DoUnaryOp(op_id, s):
 | 
| 32 |     # type: (Id_t, str) -> bool
 | 
| 33 | 
 | 
| 34 |     # Only use lstat if we're testing for a symlink.
 | 
| 35 |     if op_id in (Id.BoolUnary_h, Id.BoolUnary_L):
 | 
| 36 |         try:
 | 
| 37 |             mode = posix.lstat(s).st_mode
 | 
| 38 |         except OSError:
 | 
| 39 |             # TODO: simple_test_builtin should this as status=2.
 | 
| 40 |             #e_die("lstat() error: %s", e, word=node.child)
 | 
| 41 |             return False
 | 
| 42 | 
 | 
| 43 |         return stat.S_ISLNK(mode)
 | 
| 44 | 
 | 
| 45 |     try:
 | 
| 46 |         st = posix.stat(s)
 | 
| 47 |     except OSError as e:
 | 
| 48 |         # TODO: simple_test_builtin should this as status=2.
 | 
| 49 |         # Problem: we really need errno, because test -f / is bad argument,
 | 
| 50 |         # while test -f /nonexistent is a good argument but failed.  Gah.
 | 
| 51 |         # ENOENT vs. ENAMETOOLONG.
 | 
| 52 |         #e_die("stat() error: %s", e, word=node.child)
 | 
| 53 |         return False
 | 
| 54 |     mode = st.st_mode
 | 
| 55 | 
 | 
| 56 |     if op_id in (Id.BoolUnary_e, Id.BoolUnary_a):  # -a is alias for -e
 | 
| 57 |         return True
 | 
| 58 | 
 | 
| 59 |     if op_id == Id.BoolUnary_b:
 | 
| 60 |         return stat.S_ISBLK(mode)
 | 
| 61 | 
 | 
| 62 |     if op_id == Id.BoolUnary_c:
 | 
| 63 |         return stat.S_ISCHR(mode)
 | 
| 64 | 
 | 
| 65 |     if op_id == Id.BoolUnary_d:
 | 
| 66 |         return stat.S_ISDIR(mode)
 | 
| 67 | 
 | 
| 68 |     if op_id == Id.BoolUnary_f:
 | 
| 69 |         return stat.S_ISREG(mode)
 | 
| 70 | 
 | 
| 71 |     if op_id == Id.BoolUnary_g:
 | 
| 72 |         return bool(stat.S_IMODE(mode) & stat.S_ISGID)
 | 
| 73 | 
 | 
| 74 |     if op_id == Id.BoolUnary_k:
 | 
| 75 |         # need 'bool' for MyPy
 | 
| 76 |         return bool(stat.S_IMODE(mode) & stat.S_ISVTX)
 | 
| 77 | 
 | 
| 78 |     if op_id == Id.BoolUnary_p:
 | 
| 79 |         return stat.S_ISFIFO(mode)
 | 
| 80 | 
 | 
| 81 |     if op_id == Id.BoolUnary_r:
 | 
| 82 |         return posix.access(s, R_OK)
 | 
| 83 | 
 | 
| 84 |     if op_id == Id.BoolUnary_s:
 | 
| 85 |         return st.st_size != 0
 | 
| 86 | 
 | 
| 87 |     if op_id == Id.BoolUnary_u:
 | 
| 88 |         return bool(stat.S_IMODE(mode) & stat.S_ISUID)
 | 
| 89 | 
 | 
| 90 |     if op_id == Id.BoolUnary_w:
 | 
| 91 |         return posix.access(s, W_OK)
 | 
| 92 | 
 | 
| 93 |     if op_id == Id.BoolUnary_x:
 | 
| 94 |         return posix.access(s, X_OK)
 | 
| 95 | 
 | 
| 96 |     if op_id == Id.BoolUnary_G:
 | 
| 97 |         return st.st_gid == posix.getegid()
 | 
| 98 | 
 | 
| 99 |     if op_id == Id.BoolUnary_O:
 | 
| 100 |         return st.st_uid == posix.geteuid()
 | 
| 101 | 
 | 
| 102 |     if op_id == Id.BoolUnary_S:
 | 
| 103 |         return stat.S_ISSOCK(mode)
 | 
| 104 | 
 | 
| 105 |     e_die("%s isn't implemented" % ui.PrettyId(op_id), loc.Missing)
 | 
| 106 | 
 | 
| 107 | 
 | 
| 108 | def DoBinaryOp(op_id, s1, s2):
 | 
| 109 |     # type: (Id_t, str, str) -> bool
 | 
| 110 |     try:
 | 
| 111 |         st1 = posix.stat(s1)
 | 
| 112 |     except OSError:
 | 
| 113 |         st1 = None
 | 
| 114 |     try:
 | 
| 115 |         st2 = posix.stat(s2)
 | 
| 116 |     except OSError:
 | 
| 117 |         st2 = None
 | 
| 118 | 
 | 
| 119 |     if op_id in (Id.BoolBinary_nt, Id.BoolBinary_ot):
 | 
| 120 |         # pretend it's a very old file
 | 
| 121 |         m1 = 0 if st1 is None else st1.st_mtime
 | 
| 122 |         m2 = 0 if st2 is None else st2.st_mtime
 | 
| 123 |         if op_id == Id.BoolBinary_nt:
 | 
| 124 |             return m1 > m2
 | 
| 125 |         else:
 | 
| 126 |             return m1 < m2
 | 
| 127 | 
 | 
| 128 |     if op_id == Id.BoolBinary_ef:
 | 
| 129 |         if st1 is None:
 | 
| 130 |             return False
 | 
| 131 |         if st2 is None:
 | 
| 132 |             return False
 | 
| 133 |         return st1.st_dev == st2.st_dev and st1.st_ino == st2.st_ino
 | 
| 134 | 
 | 
| 135 |     raise AssertionError(op_id)
 |