static int filstat(char *nm, enum token mode) { struct stat s; int i; if (mode == FILSYM) { #ifdef S_IFLNK if (lstat(nm, &s) == 0) { i = S_IFLNK; goto filetype; } #endif return 0; } if (stat(nm, &s) != 0) return 0; if (mode == FILEXIST) return 1; if (is_file_access(mode)) { if (mode == FILRD) i = R_OK; if (mode == FILWR) i = W_OK; if (mode == FILEX) i = X_OK; return test_eaccess(nm, i) == 0; } if (is_file_type(mode)) { if (mode == FILREG) i = S_IFREG; if (mode == FILDIR) i = S_IFDIR; if (mode == FILCDEV) i = S_IFCHR; if (mode == FILBDEV) i = S_IFBLK; if (mode == FILFIFO) { #ifdef S_IFIFO i = S_IFIFO; #else return 0; #endif } if (mode == FILSOCK) { #ifdef S_IFSOCK i = S_IFSOCK; #else return 0; #endif } filetype: return ((s.st_mode & S_IFMT) == i); } if (is_file_bit(mode)) { if (mode == FILSUID) i = S_ISUID; if (mode == FILSGID) i = S_ISGID; if (mode == FILSTCK) i = S_ISVTX; return ((s.st_mode & i) != 0); } if (mode == FILGZ) return s.st_size > 0L; if (mode == FILUID) return s.st_uid == geteuid(); if (mode == FILGID) return s.st_gid == getegid(); return 1; /* NOTREACHED */ }
int test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2, int do_eval) { int res; int not; struct stat b1, b2; if (!do_eval) return 0; switch ((int) op) { /* * Unary Operators */ case TO_STNZE: /* -n */ return *opnd1 != '\0'; case TO_STZER: /* -z */ return *opnd1 == '\0'; case TO_OPTION: /* -o */ if ((not = *opnd1 == '!')) opnd1++; if ((res = option(opnd1)) < 0) res = 0; else { res = Flag(res); if (not) res = !res; } return res; case TO_FILRD: /* -r */ return test_eaccess(opnd1, R_OK) == 0; case TO_FILWR: /* -w */ return test_eaccess(opnd1, W_OK) == 0; case TO_FILEX: /* -x */ return test_eaccess(opnd1, X_OK) == 0; case TO_FILAXST: /* -a */ return test_stat(opnd1, &b1) == 0; case TO_FILEXST: /* -e */ /* at&t ksh does not appear to do the /dev/fd/ thing for * this (unless the os itself handles it) */ return stat(opnd1, &b1) == 0; case TO_FILREG: /* -r */ return test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode); case TO_FILID: /* -d */ return test_stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode); case TO_FILCDEV: /* -c */ return test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode); case TO_FILBDEV: /* -b */ return test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode); case TO_FILFIFO: /* -p */ return test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode); case TO_FILSYM: /* -h -L */ return lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode); case TO_FILSOCK: /* -S */ return test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode); case TO_FILCDF:/* -H HP context dependent files (directories) */ return 0; case TO_FILSETU: /* -u */ return test_stat(opnd1, &b1) == 0 && (b1.st_mode & S_ISUID) == S_ISUID; case TO_FILSETG: /* -g */ return test_stat(opnd1, &b1) == 0 && (b1.st_mode & S_ISGID) == S_ISGID; case TO_FILSTCK: /* -k */ return test_stat(opnd1, &b1) == 0 && (b1.st_mode & S_ISVTX) == S_ISVTX; case TO_FILGZ: /* -s */ return test_stat(opnd1, &b1) == 0 && b1.st_size > 0L; case TO_FILTT: /* -t */ if (opnd1 && !bi_getn(opnd1, &res)) { te->flags |= TEF_ERROR; res = 0; } else { /* generate error if in FPOSIX mode? */ res = isatty(opnd1 ? res : 0); } return res; case TO_FILUID: /* -O */ return test_stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid; case TO_FILGID: /* -G */ return test_stat(opnd1, &b1) == 0 && b1.st_gid == getegid(); /* * Binary Operators */ case TO_STEQL: /* = */ if (te->flags & TEF_DBRACKET) return gmatch(opnd1, opnd2, false); return strcmp(opnd1, opnd2) == 0; case TO_STNEQ: /* != */ if (te->flags & TEF_DBRACKET) return !gmatch(opnd1, opnd2, false); return strcmp(opnd1, opnd2) != 0; case TO_STLT: /* < */ return strcmp(opnd1, opnd2) < 0; case TO_STGT: /* > */ return strcmp(opnd1, opnd2) > 0; case TO_INTEQ: /* -eq */ case TO_INTNE: /* -ne */ case TO_INTGE: /* -ge */ case TO_INTGT: /* -gt */ case TO_INTLE: /* -le */ case TO_INTLT: /* -lt */ { long v1, v2; if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR, false) || !evaluate(opnd2, &v2, KSH_RETURN_ERROR, false)) { /* error already printed.. */ te->flags |= TEF_ERROR; return 1; } switch ((int) op) { case TO_INTEQ: return v1 == v2; case TO_INTNE: return v1 != v2; case TO_INTGE: return v1 >= v2; case TO_INTGT: return v1 > v2; case TO_INTLE: return v1 <= v2; case TO_INTLT: return v1 < v2; } } case TO_FILNT: /* -nt */ { int s2; /* ksh88/ksh93 succeed if file2 can't be stated * (subtly different from `does not exist'). */ return stat(opnd1, &b1) == 0 && (((s2 = stat(opnd2, &b2)) == 0 && b1.st_mtime > b2.st_mtime) || s2 < 0); } case TO_FILOT: /* -ot */ { int s1; /* ksh88/ksh93 succeed if file1 can't be stated * (subtly different from `does not exist'). */ return stat(opnd2, &b2) == 0 && (((s1 = stat(opnd1, &b1)) == 0 && b1.st_mtime < b2.st_mtime) || s1 < 0); } case TO_FILEQ: /* -ef */ return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 && b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino; } (*te->error)(te, 0, "internal error: unknown op"); return 1; }
static int filstat(char *nm, enum token mode) { struct stat s; unsigned int i; if (mode == FILSYM) { #ifdef S_IFLNK if (lstat(nm, &s) == 0) { i = S_IFLNK; goto filetype; } #endif return 0; } if (stat(nm, &s) != 0) return 0; switch (mode) { case FILRD: return test_eaccess(nm, R_OK) == 0; case FILWR: return test_eaccess(nm, W_OK) == 0; case FILEX: return test_eaccess(nm, X_OK) == 0; case FILEXIST: return 1; case FILREG: i = S_IFREG; goto filetype; case FILDIR: i = S_IFDIR; goto filetype; case FILCDEV: i = S_IFCHR; goto filetype; case FILBDEV: i = S_IFBLK; goto filetype; case FILFIFO: #ifdef S_IFIFO i = S_IFIFO; goto filetype; #else return 0; #endif case FILSOCK: #ifdef S_IFSOCK i = S_IFSOCK; goto filetype; #else return 0; #endif case FILSUID: i = S_ISUID; goto filebit; case FILSGID: i = S_ISGID; goto filebit; case FILSTCK: i = S_ISVTX; goto filebit; case FILGZ: return s.st_size > 0L; case FILUID: return s.st_uid == geteuid(); case FILGID: return s.st_gid == getegid(); default: return 1; } filetype: return ((s.st_mode & S_IFMT) == i); filebit: return ((s.st_mode & i) != 0); }