--- parser3/src/classes/file.C 2012/06/08 11:44:01 1.220 +++ parser3/src/classes/file.C 2013/03/09 23:35:28 1.224 @@ -25,7 +25,7 @@ #include "pa_vregex.h" #include "pa_version.h" -volatile const char * IDENT_FILE_C="$Id: file.C,v 1.220 2012/06/08 11:44:01 misha Exp $"; +volatile const char * IDENT_FILE_C="$Id: file.C,v 1.224 2013/03/09 23:35:28 misha Exp $"; // defines @@ -33,6 +33,7 @@ volatile const char * IDENT_FILE_C="$Id: #define CHARSET_EXEC_PARAM_NAME "charset" #define NAME_NAME "name" +#define KEEP_EMPTY_DIRS_NAME "keep-empty-dirs" // externs @@ -128,19 +129,44 @@ static void _save(Request& r, MethodPara static void _delete(Request& r, MethodParams& params) { const String& file_name=params.as_string(0, FILE_NAME_MUST_NOT_BE_CODE); + bool keep_empty_dirs=false; + + if(params.count()>1) + if(HashStringValue* options=params.as_hash(1)){ + int valid_options=0; + if(Value* vkeep_empty_dirs=options->get(KEEP_EMPTY_DIRS_NAME)){ + keep_empty_dirs=r.process_to_value(*vkeep_empty_dirs).as_bool(); + valid_options++; + } + if(valid_options != options->count()) + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); + } // unlink - file_delete(r.absolute(file_name)); + file_delete(r.absolute(file_name), true/*fail on problem*/, keep_empty_dirs); } static void _move(Request& r, MethodParams& params) { Value& vfrom_file_name=params.as_no_junction(0, "from file name must not be code"); Value& vto_file_name=params.as_no_junction(1, "to file name must not be code"); + bool keep_empty_dirs=false; + + if(params.count()>2) + if(HashStringValue* options=params.as_hash(2)){ + int valid_options=0; + if(Value* vkeep_empty_dirs=options->get(KEEP_EMPTY_DIRS_NAME)){ + keep_empty_dirs=r.process_to_value(*vkeep_empty_dirs).as_bool(); + valid_options++; + } + if(valid_options != options->count()) + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); + } // move file_move( r.absolute(vfrom_file_name.as_string()), - r.absolute(vto_file_name.as_string())); + r.absolute(vto_file_name.as_string()), + keep_empty_dirs); } static void copy_process_source( @@ -234,11 +260,9 @@ static void _load(Request& r, MethodPara if(Value* remote_content_type=file.headers->get(HTTP_CONTENT_TYPE_UPPER)) vcontent_type=new VString(*new String(remote_content_type->as_string().cstr())); } - - VFile& self=GET_SELF(r, VFile); - self.set(true/*tainted*/, file.str, file.length, user_file_name, vcontent_type, &r); - self.set_mode(as_text); + VFile& self=GET_SELF(r, VFile); + self.set(true/*tainted*/, as_text, file.str, file.length, user_file_name, vcontent_type, &r); if(file.headers){ file.headers->for_each(_load_pass_param, &self.fields()); @@ -311,19 +335,13 @@ static void _create(Request& r, MethodPa String::Body body=content_str->cstr_to_string_body_untaint(String::L_AS_IS); // explode content, honor tainting changes if(asked_charset && is_text) body=Charset::transcode(body, r.charsets.source(), *asked_charset); - self.set(true/*tainted*/, body.cstr(), body.length()); - self.set_mode(is_text); + self.set(true/*tainted*/, is_text, body.cstrm(), body.length(), file_name, vcontent_type, &r); } else { if(asked_charset) throw Exception(PARSER_RUNTIME, 0, "charset option can not be used with file-content"); - self.set(*vcontent.as_vfile(String::L_AS_IS)); - if(mode) - self.set_mode(is_text); + self.set(*vcontent.as_vfile(String::L_AS_IS), is_text, file_name, vcontent_type, &r); } - self.set_name(file_name); - - self.set_content_type(vcontent_type, file_name, &r); } static void _stat(Request& r, MethodParams& params) { @@ -337,7 +355,7 @@ static void _stat(Request& r, MethodPara VFile& self=GET_SELF(r, VFile); - self.set(true/*tainted*/, 0/*no bytes*/, size, &lfile_name, 0, &r); + self.set_binary(true/*tainted*/, 0/*no bytes*/, size, &lfile_name, 0, &r); HashStringValue& ff=self.fields(); ff.put(adate_name, new VDate(atime)); ff.put(mdate_name, new VDate(mtime)); @@ -441,7 +459,7 @@ static void _exec_cgi(Request& r, Method if(eq_at[1]) // has value env.put( pa_strdup(pair, eq_at-pair), - pa_strdup(eq_at+1, 0)); + pa_strdup(eq_at+1)); } // const @@ -605,7 +623,7 @@ static void _exec_cgi(Request& r, Method file_out->length -= headersize; // $body - self.set(false/*not tainted*/, file_out->str, file_out->length); + self.set(false/*not tainted*/, is_text, file_out->str, file_out->length); // $fields << header if(header) { @@ -621,11 +639,9 @@ static void _exec_cgi(Request& r, Method } } else { // ^file::exec // $body - self.set(false/*not tainted*/, file_out->str, file_out->length); + self.set(false/*not tainted*/, is_text, file_out->str, file_out->length); } - self.set_mode(is_text); - // $status self.fields().put(file_status_name, new VInt(execution.status)); @@ -971,10 +987,9 @@ static void _sql(Request& r, MethodParam VFile& self=GET_SELF(r, VFile); - self.set(true/*tainted*/, handlers.value.str, handlers.value.length, handlers.user_file_name + self.set_binary(true/*tainted*/, handlers.value.str, handlers.value.length, handlers.user_file_name , handlers.user_content_type ? new VString(*handlers.user_content_type) : 0 , &r); - self.set_mode(false/*binary*/); } static void _base64(Request& r, MethodParams& params) { @@ -1025,13 +1040,7 @@ static void _base64(Request& r, MethodPa size_t length=0; pa_base64_decode(encoded, strlen(encoded), decoded, length, strict); - if(length && is_text) - fix_line_breaks(decoded, length); - - self.set(true/*tainted*/, decoded, length, user_file_name, vcontent_type, &r); - - if(params.count() > 1) - self.set_mode(is_text); + self.set(true/*tainted*/, is_text, decoded, length, user_file_name, vcontent_type, &r); } else { // encode: ^f.base64[] const char* encoded=pa_base64_encode(self.value_ptr(), self.value_size()); @@ -1136,10 +1145,12 @@ MFile::MFile(): Methoded("file") { add_native_method("save", Method::CT_DYNAMIC, _save, 2, 3); // ^file:delete[file-name] - add_native_method("delete", Method::CT_STATIC, _delete, 1, 1); + // ^file:delete[file-name;$.keep-empty-dir(true)] + add_native_method("delete", Method::CT_STATIC, _delete, 1, 2); // ^file:move[from-file-name;to-file-name] - add_native_method("move", Method::CT_STATIC, _move, 2, 2); + // ^file:move[from-file-name;to-file-name;$.keep-empty-dir(true)] + add_native_method("move", Method::CT_STATIC, _move, 2, 3); // ^file::load[mode;disk-name] // ^file::load[mode;disk-name;user-name]