/* NETWOX Network toolbox Copyright(c) 1999-2006 Laurent Constantin ----- Main server : http://www.laurentconstantin.com/ Backup servers : http://go.to/laurentconstantin/ http://laurentconstantin.est-la.com/ http://laurentconstantin.free.fr/ http://membres.lycos.fr/lauconstantin/ [my current email address is on the web servers] ----- This file is part of Netwox. Netwox is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Netwox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (http://www.gnu.org/). ------------------------------------------------------------------------ */ /*-------------------------------------------------------------*/ #include "../../netwox.h" /*-------------------------------------------------------------*/ typedef enum { NETWOX_SMBSERGLOB_RE_STATE_BEGIN = 1, NETWOX_SMBSERGLOB_RE_STATE_END = 2, NETWOX_SMBSERGLOB_RE_STATE_BEFOREDOT = 3, NETWOX_SMBSERGLOB_RE_STATE_AFTERDOT = 4, NETWOX_SMBSERGLOB_RE_STATE_CHAR = 5, NETWOX_SMBSERGLOB_RE_STATE_QUESTION = 6, NETWOX_SMBSERGLOB_RE_STATE_SUP = 7, NETWOX_SMBSERGLOB_RE_STATE_STAR = 8 } netwox_smbserglob_re_state; /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_re(netwib_constbuf *pglob, netwib_buf *pre) { netwib_data datain, dataout, dataoutori, pc; netwib_uint32 datainsize; netwox_smbserglob_re_state state, nextstate; netwib_uint32 statequestioncount; netwib_char c; netwib_bool dotseen, specialcase, seenotherchars; datain = netwib__buf_ref_data_ptr(pglob); datainsize = netwib__buf_ref_data_size(pglob); /* in the worse case, dataoutsize is 4 times greater */ netwib_er(netwib_buf_wantspace(pre, 4*datainsize+5, &dataout)); dataoutori = dataout; /* create the regular expression: > or ? : "." for first ".*" for next, until end (or dot for is83) "...." for next, until another character " or . : "[.]" < or * : ".*" for first nothing for next empty : ".*" */ state = NETWOX_SMBSERGLOB_RE_STATE_BEGIN; statequestioncount = 0; c = '\0'; dotseen = NETWIB_FALSE; seenotherchars = NETWIB_FALSE; while(NETWIB_TRUE) { /* obtain nextstate (current character) */ nextstate = NETWOX_SMBSERGLOB_RE_STATE_END; if (datainsize != 0) { nextstate = NETWOX_SMBSERGLOB_RE_STATE_CHAR; c = *datain++; datainsize--; if (c == '.' || c == '"') { nextstate = NETWOX_SMBSERGLOB_RE_STATE_BEFOREDOT; dotseen = NETWIB_TRUE; } else if (c == '*' || c == '<') { nextstate = NETWOX_SMBSERGLOB_RE_STATE_STAR; } else if (c == '?') { nextstate = NETWOX_SMBSERGLOB_RE_STATE_QUESTION; } else if (c == '>') { nextstate = NETWOX_SMBSERGLOB_RE_STATE_SUP; } } /* a change of state from QUESTION implies to add the dots or .* */ if ((state == NETWOX_SMBSERGLOB_RE_STATE_QUESTION && nextstate != NETWOX_SMBSERGLOB_RE_STATE_QUESTION) || (state == NETWOX_SMBSERGLOB_RE_STATE_SUP && nextstate != NETWOX_SMBSERGLOB_RE_STATE_SUP)) { if (nextstate == NETWOX_SMBSERGLOB_RE_STATE_END || nextstate == NETWOX_SMBSERGLOB_RE_STATE_BEFOREDOT) { /* first, try to detect the >>>>>>>> or >>> special case */ specialcase = NETWIB_FALSE; if ((state == NETWOX_SMBSERGLOB_RE_STATE_SUP) && !seenotherchars) { if ((statequestioncount == 7) || (nextstate == NETWOX_SMBSERGLOB_RE_STATE_END && statequestioncount == 2)) { specialcase = NETWIB_TRUE; *dataout++ = '*'; /* there is already the dot of ".*" */ } } /* now, do the normal case if the special case was not done */ if (!specialcase) { if (statequestioncount > 9) { /* we should add the range, but overflow so this should be ok */ *dataout++ = '.'; *dataout++ = '*'; } else if (statequestioncount) { /* add the range */ *dataout++ = '.'; *dataout++ = '{'; *dataout++ = '0'; *dataout++ = ','; *dataout++ = netwib_c2_9toc(statequestioncount); *dataout++ = '}'; } } } else { /* simply add the exact number of dots */ while (statequestioncount--) { *dataout++ = '.'; } } } /* a change of state from BEGIN or AFTERDOT to END or BEFOREDOT implies to add ".*" */ if ((state == NETWOX_SMBSERGLOB_RE_STATE_BEGIN || state == NETWOX_SMBSERGLOB_RE_STATE_AFTERDOT) && (nextstate == NETWOX_SMBSERGLOB_RE_STATE_END || nextstate == NETWOX_SMBSERGLOB_RE_STATE_BEFOREDOT)) { *dataout++ = '.'; *dataout++ = '*'; } /* check for end of string */ if (nextstate == NETWOX_SMBSERGLOB_RE_STATE_END) { if (!dotseen) { *dataout++ = '['; *dataout++ = '.'; *dataout++ = ']'; *dataout++ = '?'; *dataout++ = '.'; *dataout++ = '*'; } break; } /* manage states */ switch(nextstate) { case NETWOX_SMBSERGLOB_RE_STATE_CHAR : seenotherchars = NETWIB_TRUE; if (netwib_c2_isdigit(c)) { *dataout++ = c; } else if (netwib_c2_isalpha(c)) { *dataout++ = '['; *dataout++ = netwib_c2_lc(c); *dataout++ = netwib_c2_uc(c); *dataout++ = ']'; } else { /* protect reserved characters */ *dataout++ = '['; *dataout++ = c; *dataout++ = ']'; } state = NETWOX_SMBSERGLOB_RE_STATE_CHAR; break; case NETWOX_SMBSERGLOB_RE_STATE_QUESTION : seenotherchars = NETWIB_TRUE; /*no break*/ case NETWOX_SMBSERGLOB_RE_STATE_SUP : if (state == NETWOX_SMBSERGLOB_RE_STATE_QUESTION || state == NETWOX_SMBSERGLOB_RE_STATE_SUP) { statequestioncount++; } else { *dataout++ = '.'; if (nextstate == NETWOX_SMBSERGLOB_RE_STATE_QUESTION) { state = NETWOX_SMBSERGLOB_RE_STATE_QUESTION; } else { state = NETWOX_SMBSERGLOB_RE_STATE_SUP; } statequestioncount = 0; } break; case NETWOX_SMBSERGLOB_RE_STATE_STAR : seenotherchars = NETWIB_TRUE; if (state != NETWOX_SMBSERGLOB_RE_STATE_STAR) { *dataout++ = '.'; *dataout++ = '*'; state = NETWOX_SMBSERGLOB_RE_STATE_STAR; } break; case NETWOX_SMBSERGLOB_RE_STATE_BEFOREDOT : *dataout++ = '['; *dataout++ = '.'; *dataout++ = ']'; state = NETWOX_SMBSERGLOB_RE_STATE_AFTERDOT; seenotherchars = NETWIB_FALSE; break; default: return(NETWOX_ERR_INTERNALERROR); } } /* special case of "file.*" and "file." which are "file[.].*" instead of "file[.]?.*" */ if (dataout - dataoutori >= 5) { pc = dataout - 5; if (!netwib_c_memcmp(pc, (netwib_constdata)"[.].*", 5)) { dataout = pc + 3; /* will only set "?.*" because start is ok */ *dataout++ = '?'; *dataout++ = '.'; *dataout++ = '*'; } } /* special case of "*.*" which is ".*[.]?.*" instead of ".*" */ if (dataout - dataoutori >= 8) { pc = dataout - 8; if (!netwib_c_memcmp(pc, (netwib_constdata)".*[.]?.*", 8)) { dataout = pc + 2; /* truncate before the [ */ } } pre->endoffset += dataout - dataoutori; return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ static netwib_err netwox_smbserglob_re_test2(netwib_conststring glob, netwib_conststring re) { netwib_buf bufglob, bufre; netwib_er(netwib_buf_init_mallocdefault(&bufre)); netwib_er(netwib_fmt_display("=> %s\n", glob)); netwib_er(netwib_buf_init_ext_string(glob, &bufglob)); netwib_er(netwox_smbserglob_re(&bufglob, &bufre)); netwib_er(netwox_buf_check_strtxt(&bufre, re)); netwib_er(netwib_buf_close(&bufre)); return(NETWIB_ERR_OK); } netwib_err netwox_smbserglob_re_test(void) { /* This behavior was tested with msdos dir c:\*.*, etc. This is sometimes different from the documented way. */ /* these 5 means to list all files */ netwib_er(netwox_smbserglob_re_test2("", ".*")); /* from doc */ netwib_er(netwox_smbserglob_re_test2("*", ".*")); netwib_er(netwox_smbserglob_re_test2("*.*", ".*")); netwib_er(netwox_smbserglob_re_test2(">>>>>>>>", ".*")); netwib_er(netwox_smbserglob_re_test2(">>>>>>>>\">>>", ".*")); /* list files with a requested extension */ netwib_er(netwox_smbserglob_re_test2("*.txt", ".*[.][tT][xX][tT]")); netwib_er(netwox_smbserglob_re_test2("<.c", ".*[.][cC]")); netwib_er(netwox_smbserglob_re_test2(".ext", ".*[.][eE][xX][tT]")); netwib_er(netwox_smbserglob_re_test2(">>>>>>>>\"TXT", ".*[.][tT][xX][tT]")); /* list files with an optional extension */ netwib_er(netwox_smbserglob_re_test2("file\"*", "[fF][iI][lL][eE][.]?.*")); netwib_er(netwox_smbserglob_re_test2("file.", "[fF][iI][lL][eE][.]?.*")); netwib_er(netwox_smbserglob_re_test2("file\">>>", "[fF][iI][lL][eE][.]?.*")); netwib_er(netwox_smbserglob_re_test2("file", "[fF][iI][lL][eE][.]?.*")); /* This behavior was not tested, but is supposed to be correct. This is the documented way. */ netwib_er(netwox_smbserglob_re_test2("file.ext", "[fF][iI][lL][eE][.][eE][xX][tT]")); netwib_er(netwox_smbserglob_re_test2("A>>>>>>>>", "[aA]..{0,7}[.]?.*")); netwib_er(netwox_smbserglob_re_test2("A>>>>>>>>.B>>>", "[aA]..{0,7}[.][bB]..{0,2}")); netwib_er(netwox_smbserglob_re_test2(">>>>>>>>A.>>>B", "........[aA][.]...[bB]")); netwib_er(netwox_smbserglob_re_test2("????????", "..{0,7}[.]?.*")); netwib_er(netwox_smbserglob_re_test2("????????\"???", "..{0,7}[.]..{0,2}")); netwib_er(netwox_smbserglob_re_test2("????????\"TXT", "..{0,7}[.][tT][xX][tT]")); netwib_er(netwox_smbserglob_re_test2("file*", "[fF][iI][lL][eE].*")); netwib_er(netwox_smbserglob_re_test2("file.???", "[fF][iI][lL][eE][.]..{0,2}")); netwib_er(netwox_smbserglob_re_test2("?*.TXT", "..*[.][tT][xX][tT]")); netwib_er(netwox_smbserglob_re_test2(">\"txt", ".[.][tT][xX][tT]")); netwib_er(netwox_smbserglob_re_test2("?.TXT", ".[.][tT][xX][tT]")); netwib_er(netwox_smbserglob_re_test2("?A.*A", ".[aA][.].*[aA]")); netwib_er(netwox_smbserglob_re_test2("??A.**A", "..[aA][.].*[aA]")); netwib_er(netwox_smbserglob_re_test2("A?.A*", "[aA].[.][aA].*")); netwib_er(netwox_smbserglob_re_test2("A??.A**", "[aA]..{0,1}[.][aA].*")); netwib_er(netwox_smbserglob_re_test2(">A\">A\"<\"A<", "[aA].[.][aA].*")); netwib_er(netwox_smbserglob_re_test2("A>>\"A<<", "[aA]..{0,1}[.][aA].*")); /* this one is invalid for 8.3, but it should be ok */ netwib_er(netwox_smbserglob_re_test2("??A.*A.*A", "..[aA][.].*[aA][.].*[aA]")); return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_item_init(netwib_bufpool *pbufpool, netwox_smbserglob_item *pitem) { pitem->pbufpool = pbufpool; pitem->searchattributes = 0; netwib_er(netwib_bufpool_buf_init(pbufpool, &pitem->prealdirname)); netwib_er(netwib_bufpool_buf_init(pbufpool, &pitem->pfilere)); netwib_er(netwib_bufpool_buf_init(pbufpool, &pitem->psaved)); pitem->volumegiven = NETWIB_FALSE; pitem->pdir = NULL; return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_item_set(netwox_smbserglob_item *pitem, netwox_smbcmdcmn_fileattr32 searchattributes, netwib_constbuf *prealdirname, netwib_constbuf *pfileglob) { pitem->searchattributes = searchattributes; netwib_er(netwib_buf_append_buf(prealdirname, pitem->prealdirname)); netwib_er(netwib_buf_append_byte('^', pitem->pfilere)); netwib_er(netwox_smbserglob_re(pfileglob, pitem->pfilere)); netwib_er(netwib_buf_append_byte('$', pitem->pfilere)); netwib_er(netwib_dir_init(prealdirname, &pitem->pdir)); return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_item_close(netwox_smbserglob_item *pitem) { if (pitem->pdir != NULL) { netwib_er(netwib_dir_close(&pitem->pdir)); } netwib_er(netwib_bufpool_buf_close(pitem->pbufpool, &pitem->psaved)); netwib_er(netwib_bufpool_buf_close(pitem->pbufpool, &pitem->pfilere)); netwib_er(netwib_bufpool_buf_close(pitem->pbufpool, &pitem->prealdirname)); return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_item_next(netwox_smbser83 *psmbser83, netwox_smbserglob_item *pitem, netwib_buf *prealpathname) { netwib_buf *ptmp, *ptmp2, *pfile, buffound; netwib_pathstat pathstat; netwib_err ret; /* check if there is a saved value */ if (netwib__buf_ref_data_size(pitem->psaved)) { netwib_er(netwib_buf_append_buf(pitem->psaved, prealpathname)); netwib__buf_reinit(pitem->psaved); return(NETWIB_ERR_OK); } /* special case of volume id */ if (pitem->searchattributes & NETWOX_SMBCMDCMN_FILEATTR32_VOLUME) { if (pitem->volumegiven) { ret = NETWIB_ERR_DATAEND; } else { netwib_er(netwib_buf_append_string(NETWOX_SMBSER_FAKE_FS_LABEL, prealpathname)); pitem->volumegiven = NETWIB_TRUE; ret = NETWIB_ERR_OK; } return(ret); } netwib_er(netwib_bufpool_buf_init(pitem->pbufpool, &pfile)); netwib_er(netwib_bufpool_buf_init(pitem->pbufpool, &ptmp)); netwib_er(netwib_bufpool_buf_init(pitem->pbufpool, &ptmp2)); ret = NETWIB_ERR_OK; while(NETWIB_TRUE) { /* find next entry */ netwib__buf_reinit(pfile); ret = netwib_dir_next(pitem->pdir, pfile); if (ret != NETWIB_ERR_OK) { break; } /* construct the candidate */ netwib__buf_reinit(ptmp); netwib_eg(netwib_path_init_concat(pitem->prealdirname, pfile, ptmp)); /* check if matches our type criteria */ netwib_eg(netwib_pathstat_init(ptmp, &pathstat)); if (pathstat.type != NETWIB_PATHSTAT_TYPE_DIR && pathstat.type != NETWIB_PATHSTAT_TYPE_REG) { /* don't add links, sockets, etc. */ continue; } if (pathstat.type == NETWIB_PATHSTAT_TYPE_DIR && !(pitem->searchattributes & NETWOX_SMBCMDCMN_FILEATTR32_DIR)) { continue; } /* check if matches our name criteria. We use both 8.3 and long. This return too many entries, but we have to be coherent. For example, a "DIR file*" has to return the same files as "MOVE file* d". Msdos under Windows 98 does this, so I think returning too many entries is not a bad thing. */ ret = netwib_buf_search_re(pfile, pitem->pfilere, NETWIB_FALSE, &buffound); if (ret != NETWIB_ERR_OK) { netwib__buf_reinit(ptmp2); ret = netwox_smbser83_longto83(psmbser83, pathstat.type, pfile, ptmp2); if (ret == NETWIB_ERR_OK) { ret = netwib_buf_search_re(ptmp2, pitem->pfilere, NETWIB_FALSE, &buffound); } } if (ret != NETWIB_ERR_OK) { continue; } /* if we are here, the file is a good one */ netwib_eg(netwib_buf_append_buf(ptmp, prealpathname)); break; } netwib_gotolabel: netwib_er(netwib_bufpool_buf_close(pitem->pbufpool, &ptmp2)); netwib_er(netwib_bufpool_buf_close(pitem->pbufpool, &ptmp)); netwib_er(netwib_bufpool_buf_close(pitem->pbufpool, &pfile)); return(ret); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_item_save(netwox_smbserglob_item *pitem, netwib_constbuf *prealpathname) { if (netwib__buf_ref_data_size(pitem->psaved)) { return(NETWOX_ERR_INTERNALERROR); } netwib_er(netwib_buf_append_buf(prealpathname, pitem->psaved)); return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_itemptr_erase(netwib_ptr ptr) { netwib_er(netwox_smbserglob_item_close((netwox_smbserglob_item *)ptr)); netwib_er(netwib_ptr_free(&ptr)); return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_itemptr_duplicate(netwib_constptr ptr, netwib_ptr *pptrdup) { const netwox_smbserglob_item *pitem = (const netwox_smbserglob_item *)ptr; netwox_smbserglob_item *pitemdup; netwib_ptr ptrdup; netwib_er(netwox_smbserglob_itemptr_malloc(&ptrdup)); pitemdup = (netwox_smbserglob_item *)ptrdup; *pptrdup = ptrdup; netwib_er(netwox_smbserglob_item_init(pitem->pbufpool, pitemdup)); pitemdup->pbufpool = pitem->pbufpool; pitemdup->searchattributes = pitem->searchattributes; netwib_er(netwib_buf_append_buf(pitem->prealdirname, pitemdup->prealdirname)); netwib_er(netwib_buf_append_buf(pitem->pfilere, pitemdup->pfilere)); /* no dir dup */ return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_init(netwib_bufpool *pbufpool, netwox_smbserglob *psmbserglob) { psmbserglob->pbufpool = pbufpool; psmbserglob->nextnumber = 1; netwib_er(netwox_smbserglob_item_hash_init(&psmbserglob->phash)); return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_close(netwox_smbserglob *psmbserglob) { netwib_er(netwox_smbserglob_item_hash_close(&psmbserglob->phash)); return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_new(netwox_smbserglob *psmbserglob, netwib_uint32 *pid, netwox_smbserglob_item **ppitem) { netwib_byte keyarray[NETWOX_BUFSTORE_HASH_KEY_SIZE]; netwox_smbserglob_item *pitem; netwib_ptr ptr; netwib_buf key; netwib_er(netwox_bufstore_hash_key(keyarray, psmbserglob->nextnumber, &key)); netwib_er(netwox_smbserglob_itemptr_malloc(&ptr)); pitem = (netwox_smbserglob_item *)ptr; netwib_er(netwox_smbserglob_item_init(psmbserglob->pbufpool, pitem)); netwib_er(netwib_hash_add(psmbserglob->phash, &key, ptr, NETWIB_TRUE)); *pid = psmbserglob->nextnumber; *ppitem = (netwox_smbserglob_item *)ptr; psmbserglob->nextnumber++; return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_search(netwox_smbserglob *psmbserglob, netwib_uint32 id, netwox_smbserglob_item **ppitem) { netwib_byte keyarray[NETWOX_BUFSTORE_HASH_KEY_SIZE]; netwib_buf key; netwib_ptr ptr; netwib_er(netwox_bufstore_hash_key(keyarray, id, &key)); netwib_er(netwib_hash_value(psmbserglob->phash, &key, &ptr)); *ppitem = (netwox_smbserglob_item *)ptr; return(NETWIB_ERR_OK); } /*-------------------------------------------------------------*/ netwib_err netwox_smbserglob_del(netwox_smbserglob *psmbserglob, netwib_uint32 id) { netwib_byte keyarray[NETWOX_BUFSTORE_HASH_KEY_SIZE]; netwib_buf key; netwib_er(netwox_bufstore_hash_key(keyarray, id, &key)); netwib_er(netwib_hash_del(psmbserglob->phash, &key, NETWIB_TRUE)); return(NETWIB_ERR_OK); }