/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_dirent.h" #include #include "gtm_stat.h" #include "io.h" #include "iosp.h" #include "parse_file.h" #include "patcode.h" #include "compiler.h" #include "lv_val.h" #include "stringpool.h" #include "stp_parms.h" #include "error.h" #include "eintr_wrappers.h" #include "op.h" #include "zroutines.h" #include "mvalconv.h" #include "gtmctype.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" GBLREF symval *curr_symval; GBLREF boolean_t gtm_utf8_mode; GBLREF spdesc stringpool; LITREF mval literal_null; STATICFNDCL CONDITION_HANDLER(fnzsrch_ch); STATICFNDCL CONDITION_HANDLER(dir_ch); STATICFNDCL int pop_top(lv_val *src, mval *res); void dir_srch(parse_blk *pfil); error_def(ERR_ASSERT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_INVSTRLEN); error_def(ERR_MEMORY); error_def(ERR_STACKOFLOW); int op_fnzsearch(mval *file, mint indx, mval *ret) { struct stat statbuf; int stat_res; parse_blk pblk; plength *plen, pret; char buf1[MAX_FBUFF + 1]; /* buffer to hold translated name */ mval sub; mstr tn; lv_val *ind_tmp; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ESTABLISH_RET(fnzsrch_ch, -1); TREF(fnzsearch_nullsubs_sav) = TREF(lv_null_subs); TREF(lv_null_subs) = LVNULLSUBS_OK; /* $ZSearch processing depends on this */ MV_FORCE_STR(file); if (file->str.len > MAX_FBUFF) rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, file->str.len, MAX_FBUFF); MV_FORCE_MVAL(((mval *)TADR(fnzsearch_sub_mval)), indx); TREF(fnzsearch_lv_vars) = op_srchindx(VARLSTCNT(2) TREF(zsearch_var), (mval *)TADR(fnzsearch_sub_mval)); if (TREF(fnzsearch_lv_vars)) { assert((TREF(fnzsearch_lv_vars))->v.mvtype & MV_STR); if ((file->str.len != (TREF(fnzsearch_lv_vars))->v.str.len) || memcmp(file->str.addr, (TREF(fnzsearch_lv_vars))->v.str.addr, file->str.len)) { op_kill(TREF(fnzsearch_lv_vars)); TREF(fnzsearch_lv_vars) = NULL; } } if (TREF(fnzsearch_lv_vars)) { for (;;) { pret.p.pint = pop_top(TREF(fnzsearch_lv_vars), ret); /* get next element off the top */ if (!ret->str.len) break; memcpy(buf1, ret->str.addr, ret->str.len); buf1[ret->str.len] = 0; STAT_FILE(buf1, &statbuf, stat_res); if (-1 == stat_res) { if (errno == ENOENT) continue; rts_error(VARLSTCNT(1) errno); } break; } } else { memset(&pblk, 0, SIZEOF(pblk)); pblk.buffer = buf1; pblk.buff_size = MAX_FBUFF; if (!(parse_file(&file->str, &pblk) & 1)) { ret->mvtype = MV_STR; ret->str.len = 0; } else { assert(!TREF(fnzsearch_lv_vars)); buf1[pblk.b_esl] = 0; /* establish new search context */ TREF(fnzsearch_lv_vars) = op_putindx(VARLSTCNT(2) TREF(zsearch_var), TADR(fnzsearch_sub_mval)); (TREF(fnzsearch_lv_vars))->v = *file; /* zsearch_var(indx)=original spec */ if (!(pblk.fnb & F_WILD)) { sub.mvtype = MV_STR; sub.str.len = pblk.b_esl; sub.str.addr = buf1; s2pool(&sub.str); ind_tmp = op_putindx(VARLSTCNT(2) TREF(fnzsearch_lv_vars), &sub); ind_tmp->v.mvtype = MV_STR; ind_tmp->v.str.len = 0; plen = (plength *)&ind_tmp->v.m[1]; plen->p.pblk.b_esl = pblk.b_esl; plen->p.pblk.b_dir = pblk.b_dir; plen->p.pblk.b_name = pblk.b_name; plen->p.pblk.b_ext = pblk.b_ext; } else dir_srch(&pblk); for (;;) { pret.p.pint = pop_top(TREF(fnzsearch_lv_vars), ret); /* get next element off the top */ if (!ret->str.len) break; memcpy(buf1, ret->str.addr, ret->str.len); buf1[ret->str.len] = 0; STAT_FILE(buf1, &statbuf, stat_res); if (-1 == stat_res) { if (errno == ENOENT) continue; rts_error(VARLSTCNT(1) errno); } break; } } } assert((0 == ret->str.len) || (pret.p.pblk.b_esl == ret->str.len)); TREF(lv_null_subs) = TREF(fnzsearch_nullsubs_sav); REVERT; return pret.p.pint; } void dir_srch(parse_blk *pfil) { struct stat statbuf; int stat_res; lv_val *dir1, *dir2, *tmp; mstr tn; short p2_len; char filb[MAX_FBUFF + 1], patb[SIZEOF(ptstr)], *c, *lastd, *top, *p2, *c1, ch; mval pat_mval, sub, compare; boolean_t wildname, seen_wd; struct dirent *dent; DIR *dp; plength *plen; int closedir_res; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; op_kill(TREF(zsearch_dir1)); op_kill(TREF(zsearch_dir2)); if (!pfil->b_name) return; /* nothing to search for */ ESTABLISH(dir_ch); pat_mval.mvtype = MV_STR; pat_mval.str.addr = patb; /* patb should be SIZEOF(ptstr.buff) but instead is SIZEOF(ptstr) since the C compiler * complains about the former and the latter is just 4 bytes more */ pat_mval.str.len = 0; sub.mvtype = MV_STR; sub.str.len = 0; compare.mvtype = MV_STR; compare.str.len = 0; wildname = (pfil->fnb & F_WILD_NAME) != 0; dir1 = TREF(zsearch_dir1); dir2 = TREF(zsearch_dir2); if (pfil->fnb & F_WILD_DIR) { seen_wd = FALSE; for (c = pfil->l_dir, lastd = c, top = c + pfil->b_dir; c < top;) { ch = *c++; if (ch == '/') /* note the start of each directory segment */ { if (seen_wd) break; lastd = c; } if (ch == '?' || ch == '*') seen_wd = TRUE; } assert(c <= top); sub.str.addr = pfil->l_dir; sub.str.len = INTCAST(lastd - sub.str.addr); tmp = op_putindx(VARLSTCNT(2) dir1, &sub); tmp->v.mvtype = MV_STR; tmp->v.str.len = 0; for (;;) { tn.addr = lastd; /* wildcard segment */ tn.len = INTCAST(c - lastd - 1); lastd = c; genpat(&tn, &pat_mval); seen_wd = FALSE; p2 = c - 1; for (; c < top;) { ch = *c++; if (ch == '/') /* note the start of each directory segment */ { if (seen_wd) break; lastd = c; } if (ch == '?' || ch == '*') seen_wd = TRUE; } p2_len = lastd - p2; /* length of non-wild segment after wild section */ for (;;) { pop_top(dir1, &sub); /* get next item off the top */ if (!sub.str.len) break; memcpy(filb, sub.str.addr, sub.str.len); filb[sub.str.len] = 0; sub.str.addr = filb; dp = OPENDIR(filb); if (!dp) continue; while (READDIR(dp, dent)) { compare.str.addr = &dent->d_name[0]; compare.str.len = STRLEN(&dent->d_name[0]); UNICODE_ONLY( if (gtm_utf8_mode) compare.mvtype &= ~MV_UTF_LEN; /* to force "char_len" to be recomputed * in do_pattern */ ) assert(compare.str.len); if (('.' == dent->d_name[0]) && ((1 == compare.str.len) || ((2 == compare.str.len) && ('.' == dent->d_name[1])))) continue; /* don't want to read . and .. */ if (compare.str.len + sub.str.len + p2_len > MAX_FBUFF) continue; if (do_pattern(&compare, &pat_mval)) { /* got a hit */ ENSURE_STP_FREE_SPACE(compare.str.len + sub.str.len + p2_len + 1); /* concatenate directory and name */ c1 = (char *)stringpool.free; tn = sub.str; s2pool(&tn); tn = compare.str; s2pool(&tn); tn.addr = p2; tn.len = p2_len; s2pool(&tn); *stringpool.free++ = 0; compare.str.addr = c1; compare.str.len += sub.str.len + p2_len; STAT_FILE(compare.str.addr, &statbuf, stat_res); if (-1 == stat_res) continue; if (!(statbuf.st_mode & S_IFDIR)) continue; /* put in results tree */ tmp = op_putindx(VARLSTCNT(2) dir2, &compare); tmp->v.mvtype = MV_STR; tmp->v.str.len = 0; } } CLOSEDIR(dp, closedir_res); } tmp = dir1; dir1 = dir2; dir2 = tmp; if (c >= top) break; } } else { sub.str.addr = pfil->l_dir; sub.str.len = pfil->b_dir; tmp = op_putindx(VARLSTCNT(2) dir1, &sub); tmp->v.mvtype = MV_STR; tmp->v.str.len = 0; } if (wildname) { tn.addr = pfil->l_name; tn.len = pfil->b_name + pfil->b_ext; genpat(&tn, &pat_mval); } for (;;) { pop_top(dir1, &sub); /* get next item off the top */ if (!sub.str.len) break; if (wildname) { memcpy(filb, sub.str.addr, sub.str.len); filb[sub.str.len] = 0; sub.str.addr = filb; dp = OPENDIR(filb); if (!dp) continue; while (READDIR(dp, dent)) { compare.str.addr = &dent->d_name[0]; compare.str.len = STRLEN(&dent->d_name[0]); UNICODE_ONLY( if (gtm_utf8_mode) compare.mvtype &= ~MV_UTF_LEN;/* force "char_len" to be recomputed in do_pattern */ ) if (('.' == dent->d_name[0]) && ((1 == compare.str.len) || ((2 == compare.str.len) && ('.' == dent->d_name[1])))) { continue; /* don't want to read . and .. */ } if (compare.str.len + sub.str.len > MAX_FBUFF) continue; if (do_pattern(&compare, &pat_mval)) { /* got a hit */ ENSURE_STP_FREE_SPACE(compare.str.len + sub.str.len); /* concatenate directory and name */ c = (char *)stringpool.free; tn = sub.str; s2pool(&tn); tn = compare.str; s2pool(&tn); compare.str.addr = c; compare.str.len += sub.str.len; /* put in results tree */ tmp = op_putindx(VARLSTCNT(2) TREF(fnzsearch_lv_vars), &compare); tmp->v.mvtype = MV_STR; tmp->v.str.len = 0; plen = (plength *)&tmp->v.m[1]; plen->p.pblk.b_esl = compare.str.len; plen->p.pblk.b_dir = sub.str.len; for (c = &compare.str.addr[sub.str.len], c1 = top = &compare.str.addr[compare.str.len]; c < top;) { if (*c++ != '.') break; } for (; c < top;) { if (*c++ == '.') c1 = c - 1; } plen->p.pblk.b_ext = top - c1; plen->p.pblk.b_name = plen->p.pblk.b_esl - plen->p.pblk.b_dir - plen->p.pblk.b_ext; } } CLOSEDIR(dp, closedir_res); } else { assert(pfil->fnb & F_WILD_DIR); compare.str.addr = pfil->l_name; compare.str.len = pfil->b_name + pfil->b_ext; if (compare.str.len + sub.str.len > MAX_FBUFF) continue; memcpy(filb, sub.str.addr, sub.str.len); filb[sub.str.len] = 0; sub.str.addr = filb; ENSURE_STP_FREE_SPACE(compare.str.len + sub.str.len); /* concatenate directory and name */ c1 = (char *)stringpool.free; tn = sub.str; s2pool(&tn); tn = compare.str; s2pool(&tn); compare.str.addr = c1; compare.str.len += sub.str.len; /* put in results tree */ tmp = op_putindx(VARLSTCNT(2) TREF(fnzsearch_lv_vars), &compare); tmp->v.mvtype = MV_STR; tmp->v.str.len = 0; plen = (plength *)&tmp->v.m[1]; plen->p.pblk.b_esl = compare.str.len; plen->p.pblk.b_dir = sub.str.len; plen->p.pblk.b_name = pfil->b_name; plen->p.pblk.b_ext = pfil->b_ext; } } op_kill(TREF(zsearch_dir1)); op_kill(TREF(zsearch_dir2)); REVERT; } STATICFNDEF CONDITION_HANDLER(fnzsrch_ch) { int dummy1, dummy2; START_CH; TREF(lv_null_subs) = TREF(fnzsearch_nullsubs_sav); NEXTCH; } STATICFNDEF CONDITION_HANDLER(dir_ch) { int dummy1, dummy2; START_CH; if (DUMP) { NEXTCH; } op_kill(TREF(zsearch_dir1)); op_kill(TREF(zsearch_dir2)); op_kill(TREF(fnzsearch_lv_vars)); TREF(fnzsearch_lv_vars) = op_putindx(VARLSTCNT(2) TREF(zsearch_var), TADR(fnzsearch_sub_mval)); (TREF(fnzsearch_lv_vars))->v.mvtype = MV_STR; (TREF(fnzsearch_lv_vars))->v.str.len = 0; UNWIND(dummy1, dummy2); } void zsrch_clr(int indx) { lv_val *tmp; mval x; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; MV_FORCE_MVAL(&x, indx); op_kill(TREF(zsearch_dir1)); op_kill(TREF(zsearch_dir2)); tmp = op_srchindx(VARLSTCNT(2) TREF(zsearch_var), &x); op_kill(tmp); } /* pop_top() - routine scans the specified local variable (in this case, special locals used by $ZSEARCH), taking the top * subscript out of the array, and putting it in the result mval. Subscripts longer than the parse_file() maximum are ignored. */ STATICFNDEF int pop_top(lv_val *src, mval *res) { lv_val *tmp; plength pret; for (;;) { /* get next element off the top */ op_fnorder(src, (mval *)&literal_null, res); if (!res->str.len) { pret.p.pint = 0; op_kill(src); break; } tmp = op_getindx(VARLSTCNT(2) src, res); pret.p.pint = tmp->v.m[1]; op_kill(tmp); /* remove this element from tree */ if (res->str.len > MAX_FBUFF) continue; break; } return pret.p.pint; }