--- parser3/src/main/pa_common.C 2010/01/27 04:17:55 1.256 +++ parser3/src/main/pa_common.C 2012/03/03 00:22:04 1.265 @@ -1,7 +1,7 @@ /** @file Parser: commonly functions. - Copyright(c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com) + Copyright(c) 2001-2012 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) * BASE64 part @@ -26,7 +26,7 @@ * */ -static const char * const IDENT_COMMON_C="$Date: 2010/01/27 04:17:55 $"; +static const char * const IDENT_COMMON_C="$Date: 2012/03/03 00:22:04 $"; #include "pa_common.h" #include "pa_exception.h" @@ -102,7 +102,7 @@ void fix_line_breaks(char *str, size_t& while(char* eol=(char*)memchr(bol, '\r', eob -bol)) { size_t len=eol-bol; if(dest!=bol) - memcpy(dest, bol, len); + memmove(dest, bol, len); dest+=len; *dest++='\n'; @@ -114,7 +114,7 @@ void fix_line_breaks(char *str, size_t& } // last piece without \r if(dest!=bol) - memcpy(dest, bol, eob-bol); + memmove(dest, bol, eob-bol); str[length]=0; // terminating } @@ -200,9 +200,7 @@ File_read_result file_read(Request_chars if(params){ int valid_options=pa_get_valid_file_options_count(*params); if(valid_options!=params->count()) - throw Exception(PARSER_RUNTIME, - 0, - INVALID_OPTION_PASSED); + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); } File_read_action_info info={&result.str, &result.length, buf, offset, count}; @@ -213,23 +211,24 @@ File_read_result file_read(Request_chars if(as_text){ if(result.success){ + Charset* asked_charset=0; if(result.length>=3 && strncmp(result.str, "\xEF\xBB\xBF", 3)==0){ // skip UTF-8 signature (BOM code) result.str+=3; result.length-=3; + asked_charset=&UTF8_charset; } - if(result.length && transcode_text_result && params){ // must be checked because transcode returns CONST string in case length==0, which contradicts hacking few lines below - if(Value* vcharset_name=params->get(PA_CHARSET_NAME)){ - Charset asked_charset=::charsets.get(vcharset_name->as_string(). - change_case(charsets.source(), String::CC_UPPER)); + if(params) + if(Value* vcharset_name=params->get(PA_CHARSET_NAME)) + asked_charset=&::charsets.get(vcharset_name->as_string().change_case(charsets.source(), String::CC_UPPER)); + + if(result.length && transcode_text_result && asked_charset){ // length must be checked because transcode returns CONST string in case length==0, which contradicts hacking few lines below + String::C body=String::C(result.str, result.length); + body=Charset::transcode(body, *asked_charset, charsets.source()); - String::C body=String::C(result.str, result.length); - body=Charset::transcode(body, asked_charset, charsets.source()); - - result.str=const_cast(body.str); // hacking a little - result.length=body.length; - } + result.str=const_cast(body.str); // hacking a little + result.length=body.length; } } if(result.length) @@ -264,8 +263,9 @@ File_read_result file_load(Request& r, c return result; } + #ifdef PA_SAFE_MODE -void check_safe_mode(struct stat finfo, const String& file_spec, const char* fname) { +void check_safe_mode(struct stat finfo, const String& file_spec, const char* fname) { if(finfo.st_uid/*foreign?*/!=geteuid() && finfo.st_gid/*foreign?*/!=getegid()) throw Exception(PARSER_RUNTIME, @@ -277,9 +277,14 @@ void check_safe_mode(struct stat finfo, "fuid(%d)!=euid(%d) or fgid(%d)!=egid(%d)", fname, finfo.st_uid, geteuid(), - finfo.st_gid, getegid()); -} -#endif + finfo.st_gid, getegid()); +} +#else +void check_safe_mode(struct stat, const String&, const char*) { +} +#endif + + bool file_read_action_under_lock(const String& file_spec, const char* action_name, File_read_action action, void *context, @@ -312,9 +317,7 @@ bool file_read_action_under_lock(const S "stat failed: %s (%d), actual filename '%s'", strerror(errno), errno, fname); -#ifdef PA_SAFE_MODE check_safe_mode(finfo, file_spec, fname); -#endif action(finfo, f, file_spec, fname, as_text, context); } catch(...) { @@ -448,13 +451,62 @@ void file_write( do_append); } +static size_t get_dir(char* fname, size_t helper_length){ + bool dir=false; + size_t pos=0; + for(pos=helper_length; pos; pos--){ + char c=fname[pos-1]; + if(c=='/' || c=='\\'){ + fname[pos-1]=0; + dir=true; + } else if(dir) break; + } + return pos; +} + +static bool entry_readable(char* fname, bool need_dir) { + if(need_dir){ + size_t size=strlen(fname); + while(size) { + char c=fname[size-1]; + if(c=='/' || c=='\\') + fname[--size]=0; + else + break; + } + } + + struct stat finfo; + if(access(fname, R_OK)==0 && entry_exists(fname, &finfo)) { + bool is_dir=(finfo.st_mode&S_IFDIR) != 0; + return is_dir==need_dir; + } + return false; +} + +static bool entry_readable(const String& file_spec, bool need_dir) { + return entry_readable(file_spec.taint_cstrm(String::L_FILE_SPEC), need_dir); +} + // throws nothing! [this is required in file_move & file_delete] -static void rmdir(const String& file_spec, size_t pos_after) { - size_t pos_before; - if((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND) - rmdir(file_spec, pos_before+1); - - rmdir(file_spec.mid(0, pos_after-1/* / */).taint_cstr(String::L_FILE_SPEC)); +static void rmdir(const String& file_spec, size_t pos_after=0) { + char* dir_spec=file_spec.taint_cstrm(String::L_FILE_SPEC); + size_t length=strlen(dir_spec); + while( (length=get_dir(dir_spec, length)) && (length > pos_after) ){ +#ifdef WIN32 + if(!entry_readable(dir_spec, true)) + break; + DWORD attrs=GetFileAttributes(dir_spec); + if( + (attrs==INVALID_FILE_ATTRIBUTES) + || !(attrs & FILE_ATTRIBUTE_DIRECTORY) + || (attrs & FILE_ATTRIBUTE_REPARSE_POINT) + ) + break; +#endif + if( rmdir(dir_spec) ) + break; + }; } bool file_delete(const String& file_spec, bool fail_on_problem) { @@ -501,26 +553,6 @@ bool entry_exists(const String& file_spe return entry_exists(fname, 0); } -static bool entry_readable(const String& file_spec, bool need_dir) { - char* fname=file_spec.taint_cstrm(String::L_FILE_SPEC); - if(need_dir) { - size_t size=strlen(fname); - while(size) { - char c=fname[size-1]; - if(c=='/' || c=='\\') - fname[--size]=0; - else - break; - } - } - struct stat finfo; - if(access(fname, R_OK)==0 && entry_exists(fname, &finfo)) { - bool is_dir=(finfo.st_mode&S_IFDIR) != 0; - return is_dir==need_dir; - } - return false; -} - bool file_exist(const String& file_spec) { return entry_readable(file_spec, false); } @@ -726,7 +758,7 @@ enum EscapeState { }; // @todo prescan for reduce required size (unescaped sting in 1 byte charset requires less memory usually) -char* unescape_chars(const char* cp, int len, Charset* charset, bool ignore_plus){ +char* unescape_chars(const char* cp, int len, Charset* charset, bool js){ char* s=new(PointerFreeGC) char[len+1]; // must be enough (%uXXXX==6 bytes, max utf-8 char length==6 bytes) char* dst=s; EscapeState escapeState=EscapeRest; @@ -735,12 +767,12 @@ char* unescape_chars(const char* cp, int short int jsCnt=0; while(srcPos