diff --git a/src/Desc.cc b/src/Desc.cc index e49ec31a2f..454de549ef 100644 --- a/src/Desc.cc +++ b/src/Desc.cc @@ -174,15 +174,20 @@ void ODesc::AddBytes(const BroString* s) { if ( IsReadable() ) { - int render_style = BroString::EXPANDED_STRING; - if ( Style() == ALTERNATIVE_STYLE ) - // Only change NULs, since we can't in any case - // cope with them. - render_style = BroString::ESC_NULL; + if ( Style() == RAW_STYLE ) + AddBytes(reinterpret_cast(s->Bytes()), s->Len()); + else + { + int render_style = BroString::EXPANDED_STRING; + if ( Style() == ALTERNATIVE_STYLE ) + // Only change NULs, since we can't in any case + // cope with them. + render_style = BroString::ESC_NULL; - const char* str = s->Render(render_style); - Add(str); - delete [] str; + const char* str = s->Render(render_style); + Add(str); + delete [] str; + } } else { diff --git a/src/Desc.h b/src/Desc.h index f6e2756efc..a9758d764b 100644 --- a/src/Desc.h +++ b/src/Desc.h @@ -17,6 +17,7 @@ typedef enum { typedef enum { STANDARD_STYLE, ALTERNATIVE_STYLE, + RAW_STYLE, } desc_style; class BroFile; diff --git a/src/Expr.cc b/src/Expr.cc index c142026123..9e15395d54 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -319,6 +319,8 @@ void NameExpr::Assign(Frame* f, Val* v, Opcode op) id->SetVal(v, op); else f->SetElement(id->Offset(), v); + if ( v->Type()->Tag() == TYPE_FILE ) + v->AsFile()->SetAttrs(id->Attrs()); } int NameExpr::IsPure() const diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index ca534e00fc..a80157767f 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -2385,7 +2385,7 @@ bool RemoteSerializer::FlushPrintBuffer(Peer* p) return true; } -bool RemoteSerializer::SendPrintHookEvent(BroFile* f, const char* txt) +bool RemoteSerializer::SendPrintHookEvent(BroFile* f, const char* txt, size_t len) { loop_over_list(peers, i) { @@ -2398,8 +2398,6 @@ bool RemoteSerializer::SendPrintHookEvent(BroFile* f, const char* txt) if ( ! fname ) continue; // not a managed file. - size_t len = strlen(txt); - // We cut off everything after the max buffer size. That // makes the code a bit easier, and we shouldn't have such // long lines anyway. diff --git a/src/RemoteSerializer.h b/src/RemoteSerializer.h index 68e7dfa0c7..18284463a1 100644 --- a/src/RemoteSerializer.h +++ b/src/RemoteSerializer.h @@ -95,7 +95,7 @@ public: bool SendPing(PeerID peer, uint32 seq); // Broadcast remote print. - bool SendPrintHookEvent(BroFile* f, const char* txt); + bool SendPrintHookEvent(BroFile* f, const char* txt, size_t len); // Send a request to create a writer on a remote side. bool SendLogCreateWriter(PeerID peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const LogField* const * fields); diff --git a/src/Stmt.cc b/src/Stmt.cc index ee7c0784a4..80603a717b 100644 --- a/src/Stmt.cc +++ b/src/Stmt.cc @@ -277,16 +277,28 @@ Val* PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const bool ph = print_hook && f->IsPrintHookEnabled(); - desc_style style = f->IsRawOutput() ? ALTERNATIVE_STYLE : STANDARD_STYLE; + desc_style style = f->IsRawOutput() ? RAW_STYLE : STANDARD_STYLE; if ( ! (suppress_local_output && ph) ) { - ODesc d(DESC_READABLE, f); - d.SetFlush(0); - d.SetStyle(style); + if ( f->IsRawOutput() ) + { + ODesc d(DESC_READABLE); + d.SetFlush(0); + d.SetStyle(style); - PrintVals(&d, vals, offset); - f->Write("\n", 1); + PrintVals(&d, vals, offset); + f->Write(d.Description(), d.Len()); + } + else + { + ODesc d(DESC_READABLE, f); + d.SetFlush(0); + d.SetStyle(style); + + PrintVals(&d, vals, offset); + f->Write("\n", 1); + } } if ( ph ) @@ -300,14 +312,14 @@ Val* PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const val_list* vl = new val_list(2); ::Ref(f); vl->append(new Val(f)); - vl->append(new StringVal(d.Description())); + vl->append(new StringVal(d.Len(), d.Description())); // Note, this doesn't do remote printing. mgr.Dispatch(new Event(print_hook, vl), true); } if ( remote_serializer ) - remote_serializer->SendPrintHookEvent(f, d.Description()); + remote_serializer->SendPrintHookEvent(f, d.Description(), d.Len()); } return 0; diff --git a/src/Val.cc b/src/Val.cc index fe174b1544..ddec9b616d 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -3567,7 +3567,7 @@ void describe_vals(const val_list* vals, ODesc* d, int offset) for ( int i = offset; i < vals->length(); ++i ) { - if ( i > offset && d->IsReadable() ) + if ( i > offset && d->IsReadable() && d->Style() != RAW_STYLE ) d->Add(", "); (*vals)[i]->Describe(d); diff --git a/testing/btest/Baseline/bifs.enable_raw_output/output b/testing/btest/Baseline/bifs.enable_raw_output/output new file mode 100644 index 0000000000..bff6a72fd2 --- /dev/null +++ b/testing/btest/Baseline/bifs.enable_raw_output/output @@ -0,0 +1 @@ +helloXworldhi \ No newline at end of file diff --git a/testing/btest/Baseline/language.raw_output_attr-2/output b/testing/btest/Baseline/language.raw_output_attr-2/output new file mode 100644 index 0000000000..bff6a72fd2 --- /dev/null +++ b/testing/btest/Baseline/language.raw_output_attr-2/output @@ -0,0 +1 @@ +helloXworldhi \ No newline at end of file diff --git a/testing/btest/Baseline/language.raw_output_attr/output b/testing/btest/Baseline/language.raw_output_attr/output new file mode 100644 index 0000000000..bff6a72fd2 --- /dev/null +++ b/testing/btest/Baseline/language.raw_output_attr/output @@ -0,0 +1 @@ +helloXworldhi \ No newline at end of file diff --git a/testing/btest/bifs/enable_raw_output.test b/testing/btest/bifs/enable_raw_output.test new file mode 100644 index 0000000000..92e0037a04 --- /dev/null +++ b/testing/btest/bifs/enable_raw_output.test @@ -0,0 +1,23 @@ +# Files which enable raw output via the BiF shouldn't interpret NUL characters +# in strings that are `print`ed to it. + +# @TEST-EXEC: bro %INPUT +# @TEST-EXEC: tr '\000' 'X' output +# @TEST-EXEC: btest-diff output +# @TEST-EXEC: cmp myfile hookfile + +event bro_init() + { + local myfile: file; + myfile = open("myfile"); + enable_raw_output(myfile); + print myfile, "hello\x00world", "hi"; + close(myfile); + } + +event print_hook(f: file, s: string) + { + local hookfile = open("hookfile"); + write_file(hookfile, s); + close(hookfile); + } diff --git a/testing/btest/language/raw_output_attr.test b/testing/btest/language/raw_output_attr.test new file mode 100644 index 0000000000..2cf9e6f28a --- /dev/null +++ b/testing/btest/language/raw_output_attr.test @@ -0,0 +1,43 @@ +# Files with the &raw_output attribute shouldn't interpret NUL characters +# in strings that are `print`ed to it. + +# @TEST-EXEC: bro %INPUT +# @TEST-EXEC: tr '\000' 'X' output +# @TEST-EXEC: btest-diff output +# @TEST-EXEC: cmp myfile hookfile + +# first check local variable of file type w/ &raw_output + +event bro_init() + { + local myfile: file &raw_output; + myfile = open("myfile"); + print myfile, "hello\x00world", "hi"; + close(myfile); + } + +event print_hook(f: file, s: string) + { + local hookfile = open("hookfile"); + write_file(hookfile, s); + close(hookfile); + } + +# @TEST-START-NEXT +# now check global variables of file type w/ &raw_output + +global myfile: file &raw_output; + +event bro_init() + { + myfile = open("myfile"); + print myfile, "hello\x00world", "hi"; + close(myfile); + } + +event print_hook(f: file, s: string) + { + local hookfile = open("hookfile"); + write_file(hookfile, s); + close(hookfile); + }