6140571927e83a9ed4fab8e052e4f1aff39adf68
[debian/amanda] / perl / Amanda / Xfer.swg
1 /*
2  * Copyright (c) Zmanda, Inc.  All Rights Reserved.
3  *
4  * This library is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 2.1
6  * as published by the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
11  * License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
16  *
17  * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18  * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19  */
20
21 %module "Amanda::Xfer"
22 %include "amglue/amglue.swg"
23 %include "exception.i"
24 %import "Amanda/MainLoop.swg"
25 %import "Amanda/Device.swg"
26
27 %{
28 #include "glib-util.h"
29 #include "amxfer.h"
30 %}
31
32 %perlcode %{
33 =head1 NAME
34
35 Amanda::Xfer - the transfer architecture
36
37 =head1 SYNOPSIS
38
39   use Amanda::MainLoop;
40   use Amanda::Xfer qw( :constants );
41   use POSIX;
42
43   my $infd = POSIX::open("input", POSIX::O_RDONLY, 0);
44   my $outfd = POSIX::open("output", POSIX::O_CREAT|POSIX::O_WRONLY, 0640);
45   my $xfer = Amanda::Xfer->new([
46     Amanda::Xfer::Source::Fd->new($infd),
47     Amanda::Xfer::Dest::Fd->new($outfd)
48   ]);
49   $xfer->get_source()->set_callback(sub {
50       my ($src, $xmsg, $xfer) = @_;
51       print "Message from $xfer: $xmsg\n"; # use stringify operations
52       if ($xfer->get_status() == $XFER_DONE) {
53           $src->remove();
54           Amanda::MainLoop::quit();
55       }
56   });
57   $xfer->start();
58   Amanda::MainLoop::run();
59   
60 See L<http://wiki.zmanda.com/index.php/XFA> for background on the transfer
61 architecture.
62
63 =head1 API STATUS
64
65 Fluid.
66
67 =head1 Amanda::Xfer Objects
68
69 A new transfer is created with C<< Amanda::Xfer->new() >>, which takes an arrayref
70 giving the transfer elements which should compose the transfer.
71
72 The resulting object has the following methods:
73
74 =over
75
76 =item get_source()
77
78 Get the L<Amanda::MainLoop> event source through which messages will be
79 delivered for this transfer.  Use its C<set_callback> method to connect a perl
80 sub for processing events.  You I<must> C<release> the source when the
81 transfer is complete!
82
83 The callback from this event source receives three arguments: the event source,
84 the message, and a reference to the controlling transfer.  See the description of
85 C<Amanda::Xfer::Msg>, below, for details.
86
87 =item start()
88
89 Start this transfer.  Processing takes place asynchronously, and messages will
90 begin queueing up immediately.
91
92 =item cancel()
93
94 Stop transferring data.  The transfer will send an C<XMSG_CANCEL>, "drain" any
95 buffered data as best it can, and then complete normally with an C<XMSG_DONE>.
96
97 =item get_status()
98
99 Get the transfer's status.  The result will be one of C<$XFER_INIT>,
100 C<$XFER_START>, C<$XFER_RUNNING>, or C<$XFER_DONE>.  These symbols are
101 available for import with the tag C<:constants>.
102
103 =item repr()
104
105 Return a string representation of this transfer, suitable for use in debugging
106 messages.  This method is automatically invoked when a transfer is interpolated
107 into a string:
108   print "Starting $xfer\n";
109
110 =back
111
112 =head1 Amanda::Xfer::Element objects
113
114 The individual transfer elements that compose a transfer are instances of
115 subclasses of Amanda::Xfer::Element.  All such objects have a C<repr()> method,
116 similar to that for transfers, and support a similar kind of string
117 interpolation.
118
119 Note that the names of these classes contain the words "Source", "Filter", and
120 "Dest".  This is merely suggestive of their intended purpose -- there are no
121 such abstract classes.
122
123 =head2 Transfer Sources
124
125 =head3 Amanda::Xfer::Source::Device
126
127   Amanda::Xfer::Source::Device->new($device);
128
129 This source reads data from a device.  The device should already be queued up
130 for reading (C<$device->seek_file(..)>).  The element will read until the end
131 of the device file.
132
133 =head3 Amanda::Xfer::Source::Fd
134
135   Amanda::Xfer::Source::Fd->new(fileno($fh));
136
137 This source reads data from a file descriptor.  It reads until EOF, but does
138 not close the descriptor.  Be careful not to let Perl close the file for you!
139
140 =head3 Amanda::Xfer::Source::Random
141
142   Amanda::Xfer::Source::Random->new($length, $seed);
143
144 This source provides I<length> bytes of random data (or an unlimited amount
145 of data if I<length> is zero).  C<$seed> is the seed used
146 to generate the random numbers; this seed can be used in a destination to
147 check for correct output.
148
149 =head3 Amanda::Xfer::Source::Pattern
150
151   Amanda::Xfer::Source::Pattern->new($length, $pattern);
152
153 This source provides I<length> bytes containing copies of
154 I<pattern>. If I<length> is zero, the source provides an unlimited
155 number of bytes.
156
157 =head2 Transfer Filters
158
159 =head3 Amanda::Xfer::Filter:Xor
160
161   Amanda::Xfer::Filter::Xor->new($key);
162
163 This filter applies a bytewise XOR operation to the data flowing through it.
164
165 =head2 Transfer Destinations
166
167 =head3 Amanda::Xfer::Dest::Device
168
169   Amanda::Xfer::Dest::Device->new($device, $max_memory);
170
171 This source writes data to a device.  The device should already be queued up
172 for writing (C<$device->start_file(..)>).  No more than C<$max_memory> will be
173 used for buffers.  Use zero for the default buffer size.  On completion of the
174 transfer, the file will be finished.
175
176 =head3 Amanda::Xfer::Dest::Fd
177
178   Amanda::Xfer::Dest::Fd->new(fileno($fh));
179
180 This destination writes data to a file descriptor.  The file is not closed
181 after the transfer is completed.  Be careful not to let Perl close the file
182 for you!
183
184 =head3 Amanda::Xfer::Dest::Null
185
186   Amanda::Xfer::Dest::Null->new($seed);
187
188 This destination discards the data it receives.  If C<$seed> is nonzero, then
189 the element will validate that it receives the data that
190 C<Amanda::Xfer::Source::Random> produced with the same seed.  No validation is
191 performed if C<$seed> is zero.
192
193 =head1 Amanda::Xfer::Msg objects
194
195 Messages are simple hashrefs, with a few convenience methods.  Like transfers,
196 they have a C<repr()> method that formats the message nicely, and is available
197 through string interpolation:
198   print "Received message $msg\n";
199
200 Every message has the following keys:
201
202 =over
203
204 =item type
205
206 The message type -- one of the C<xmsg_type> constants available from the import
207 tag C<:constants>.
208
209 =item elt
210
211 The transfer element that sent the message.
212
213 =item version
214
215 The version of the message.  This is used to support extensibility of the protocol.
216
217 =back
218
219 The canonical description of the message types and keys is in C<xfer-src/xmsg.h>, and is
220 not duplicated here.
221
222 =cut
223 %}
224
225 /* The SWIGging of the transfer architecture.
226  *
227  * The C layer of the transfer architecture exposes some structs, which are
228  * arranged through GObject magic into a class hierarchy.  It also exposes
229  * regular C functions which are intended to act as methods on these structs.
230  * Furthermore, it exposes Perl callbacks (via Amanda::MainLoop) with
231  * parameters involving objects of these classes.
232  *
233  * SWIG doesn't support callbacks very well, and makes it particularly
234  * difficult to represent a GObject class hierarchy.  Rather than try to "make
235  * it fit" into SWIG, this module uses custom typemaps and perl/C conversions
236  * to get all of this stuff right in the first place.
237  *
238  * For Xfer objects, we define two functions, new_sv_for_xfer and xfer_from_sv,
239  * which create a new SV for an Xfer object, and subsequently extract a pointer
240  * to the object from the SV.  The SV is both blessed and tied to the
241  * Amanda::Xfer::Xfer class, in which all of the method calls are defined, and
242  * which defines a DESTROY method that calls xfer_unref.
243  *
244  * XferElements are similar, but we have the added challenge of representing
245  * subclasses with appropriate perl subclasses.  The solution is to tag each C
246  * class with a perl class name, and use that name when blessing a new SV.
247  *
248  * Finally, XMsgs are reflected entirely into perl hashrefs, in the interest of
249  * efficiency.
250  */
251
252 /*
253  * Initialization
254  */
255
256 %init %{
257     /* We need GType and GThread initialized to use xfers */
258     glib_init();
259 %}
260
261 /*
262  * Constants
263  */
264
265 amglue_add_enum_tag_fns(xfer_status);
266 amglue_add_constant(XFER_INIT, xfer_status);
267 amglue_add_constant(XFER_START, xfer_status);
268 amglue_add_constant(XFER_RUNNING, xfer_status);
269 amglue_add_constant(XFER_DONE, xfer_status);
270 amglue_copy_to_tag(xfer_status, constants);
271
272 amglue_add_enum_tag_fns(xmsg_type);
273 amglue_add_constant(XMSG_INFO, xmsg_type);
274 amglue_add_constant(XMSG_ERROR, xmsg_type);
275 amglue_add_constant(XMSG_DONE, xmsg_type);
276 amglue_add_constant(XMSG_CANCEL, xmsg_type);
277 amglue_copy_to_tag(xmsg_type, constants);
278
279 /*
280  * Wrapping machinery
281  */
282
283 %{
284 /* Return a new SV with refcount 1 representing the given C object
285  * with the given class.
286  *
287  * @param c_obj: the object to represent
288  * @param perl_class: the perl with which to bless and tie the SV
289  */
290 static SV *
291 new_sv_for_c_obj(
292     gpointer c_obj,
293     const char *perl_class)
294 {
295     SV *sv = newSV(0);
296
297     /* Make an SV that contains a pointer to the object, and bless it
298      * with the appropriate class. */
299     sv_setref_pv(sv, perl_class, c_obj);
300
301     return sv;
302 }
303
304 /* Return a new SV representing a transfer.
305  *
306  * @param xfer: the transfer to represent
307  */
308 static SV *
309 new_sv_for_xfer(
310     Xfer *xfer)
311 {
312     if (!xfer) return &PL_sv_undef;
313
314     xfer_ref(xfer);
315     return new_sv_for_c_obj(xfer, "Amanda::Xfer::Xfer");
316 }
317
318 /* Return a new SV representing a transfer element.
319  *
320  * @param xe: the transfer element to represent
321  */
322 static SV *
323 new_sv_for_xfer_element(
324     XferElement *xe)
325 {
326     const char *perl_class;
327
328     if (!xe) return &PL_sv_undef;
329
330     perl_class = XFER_ELEMENT_GET_CLASS(xe)->perl_class;
331     if (!perl_class) die("Attempt to wrap an XferElementClass with no perl class!");
332     g_object_ref(xe);
333     return new_sv_for_c_obj(xe, perl_class);
334 }
335
336 /* Return the C object buried in an SV, asserting that the perl SV is
337  * derived from derived_from.  Returns NULL for undefined perl values.
338  *
339  * This function is based on SWIG's SWIG_Perl_ConvertPtr.  The INT2PTR
340  * situation certainly looks strange, but is documented in perlxs.
341  *
342  * @param sv: the SV to convert
343  * @param derived_from: perl class from which the SV should be derived
344  * @return: underlying pointer
345  */
346 static gpointer
347 c_obj_from_sv(
348     SV *sv,
349     const char *derived_from)
350 {
351     SV *referent;
352     IV tmp;
353
354     if (!sv) return NULL;
355     if (!SvOK(sv)) return NULL;
356
357     /* Peel back the layers.  The sv should be a blessed reference to a PV,
358      * and we check the class against derived_from to ensure we have the right
359      * stuff. */
360     if (!sv_isobject(sv) || !sv_derived_from(sv, derived_from)) {
361         croak("Value is not an object of type %s", derived_from);
362         return NULL;
363     }
364
365     referent = (SV *)SvRV(sv);
366     tmp = SvIV(referent);
367     return INT2PTR(gpointer, tmp);
368 }
369
370 /* Convert an SV to an Xfer.  The Xfer's reference count is not
371  * incremented -- this is a "borrowed" reference.
372  *
373  * @param sv: the perl value
374  * @returns: pointer to the corresponding transfer, or NULL
375  */
376 static Xfer *
377 xfer_from_sv(
378     SV *sv)
379 {
380     return (Xfer *)c_obj_from_sv(sv, "Amanda::Xfer::Xfer");
381 }
382
383 /* Convert an SV to an XferElement.  The element's reference count is
384  * not incremented -- this is a "borrowed" reference.
385  *
386  * @param sv: the perl value
387  * @returns: pointer to the corresponding transfer element, or NULL.
388  */
389 static XferElement *
390 xfer_element_from_sv(
391     SV *sv)
392 {
393     return (XferElement *)c_obj_from_sv(sv, "Amanda::Xfer::Element");
394 }
395
396 /* Given an XMsg, return a hashref representing the message as a pure-perl
397  * object.  The object is new, has refcount 1, and is totally independent of
398  * the underlying XMsg.
399  *
400  * Reflecting the XMsg directly into Perl avoids the need to reference-count
401  * the XMsg objects themselves, which can simply be freed after a callback
402  * completes.  The overhead of creating a hash is likely equivalent to or
403  * less than the overhead that would be consumed with SWIG's swig_$field_get
404  * accessors, assuming that perl code examines most of the fields in a message.
405  *
406  * @param msg: the message to represent
407  * @returns: a perl SV
408  */
409 static SV *
410 new_sv_for_xmsg(
411     XMsg *msg)
412 {
413     static HV *amanda_xfer_msg_stash = NULL;
414     HV *hash = newHV();
415     SV *rv = newRV_noinc((SV *)hash);
416
417     /* bless the rv as an Amanda::Xfer::Msg object */
418     if (!amanda_xfer_msg_stash) {
419         amanda_xfer_msg_stash = gv_stashpv("Amanda::Xfer::Msg", GV_ADD);
420     }
421     sv_bless(rv, amanda_xfer_msg_stash);
422
423     /* TODO: consider optimizing by precomputing the hash values of
424      * the keys? */
425
426     /* elt */
427     hv_store(hash, "elt", 3, new_sv_for_xfer_element(msg->elt), 0);
428
429     /* type */
430     hv_store(hash, "type", 4, newSViv(msg->type), 0);
431
432     /* type */
433     hv_store(hash, "version", 7, newSViv(msg->version), 0);
434
435     /* message */
436     if (msg->message)
437         hv_store(hash, "message", 7, newSVpv(msg->message, 0), 0);
438
439     return rv;
440 }
441 %}
442
443 %typemap(in) Xfer * {
444     $1 = xfer_from_sv($input);
445 }
446
447 %typemap(in) XferElement * {
448     $1 = xfer_element_from_sv($input);
449 }
450
451 %typemap(out) Xfer * {
452     $result = sv_2mortal(new_sv_for_xfer($1));
453     argvi++;
454 }
455
456 %typemap(out) XferElement * {
457     $result = sv_2mortal(new_sv_for_xfer_element($1));
458     argvi++;
459 }
460
461 %typemap(newfree) Xfer * {
462     xfer_unref($1);
463 }
464
465 %typemap(newfree) XferElement * {
466     xfer_element_unref($1);
467 }
468
469 /*
470  * Xfer functions
471  */
472
473 /* A typemap for the input to the Xfer constructor, a.k.a. xfer_new */
474 %typemap(in,numinputs=1) (XferElement **elementlist, unsigned int nelements) {
475     AV *av;
476     unsigned int i;
477
478     /* check that it's an arrayref */
479     if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
480         SWIG_exception(SWIG_TypeError, "Expected an arrayref");
481     }
482     av = (AV *)SvRV($input);
483
484     /* allocate memory for $1 */
485     $2 = av_len(av)+1; /* av_len(av) is like $#av */
486     $1 = g_new(XferElement *, $2);
487
488     /* extract the underlying XferElement objects and add pointers to
489      * them, "borrowing" the caller's references for the moment. */
490     for (i = 0; i < $2; i++) {
491         SV **sv = av_fetch(av, i, 0);
492         XferElement *elt = sv? xfer_element_from_sv(*sv):NULL;
493
494         if (!elt) {
495             SWIG_exception(SWIG_TypeError, "Expected an arrayref of Amanda::Xfer::Element objects");
496         }
497         $1[i] = elt;
498     }
499 }
500
501 %typemap(freearg) (XferElement **elementlist, unsigned int nelements) {
502     /* free the element vector allocated in the (in) typemap */
503     g_free($1);
504 }
505
506 %newobject xfer_new;
507 Xfer *xfer_new(XferElement **elementlist, unsigned int nelements);
508 void xfer_unref(Xfer *);
509 xfer_status xfer_get_status(Xfer *xfer);
510 char *xfer_repr(Xfer *xfer);
511 void xfer_start(Xfer *xfer);
512 void xfer_cancel(Xfer *xfer);
513 /* xfer_get_source is implemented below */
514
515 %inline %{
516 /* SWIG wants to treat this as a function */
517 #define xfer_get_status(xfer) ((xfer)->status)
518 %}
519
520 /*
521  * XferElement functions
522  *
523  * Some of these methods are not intended to be used from Perl; they are annotated
524  * as "private".
525  */
526
527 void xfer_element_unref(XferElement *elt); /* (wrap the macro, above) */
528 /* xfer_element_link_to -- private */
529 char *xfer_element_repr(XferElement *elt);
530 /* xfer_element_start -- private */
531 /* xfer_element_cancel -- private */
532
533 /* subclass constructors */
534
535 /* N.B. When adding new classes, ensure that the class_init function
536  * sets perl_class to the appropriate value. */
537
538 %newobject xfer_source_device;
539 XferElement *xfer_source_device(
540     Device *device);
541
542 %newobject xfer_source_random;
543 XferElement *xfer_source_random(
544     guint64 length,
545     guint32 seed);
546
547 %typemap(in) (void * pattern, size_t pattern_length) {
548  size_t len;
549  char * pat;
550
551  pat = SvPV($input, len);
552  $1 = g_memdup(pat, len);
553  $2 = len;
554 }
555
556 %newobject xfer_source_random;
557 XferElement *xfer_source_pattern(
558     guint64 length,
559     void * pattern,
560     size_t pattern_length);
561
562 %newobject xfer_source_fd;
563 XferElement *xfer_source_fd(
564     int fd);
565
566 %newobject xfer_filter_xor;
567 XferElement *xfer_filter_xor(
568     unsigned char xor_key);
569
570 %newobject xfer_dest_device;
571 XferElement *xfer_dest_device(
572     Device *device,
573     size_t max_memory);
574
575 %newobject xfer_dest_null;
576 XferElement *xfer_dest_null(
577     guint32 prng_seed);
578
579 %newobject xfer_dest_fd;
580 XferElement *xfer_dest_fd(
581     int fd);
582
583 /*
584  * Callback handling
585  */
586
587 %types(amglue_Source *);
588 %{
589 static gboolean
590 xmsgsource_perl_callback(
591     gpointer data,
592     struct XMsg *msg,
593     Xfer *xfer)
594 {
595     dSP;
596     amglue_Source *src = (amglue_Source *)data;
597     SV *src_sv = NULL;
598
599     g_assert(src->callback_sv != NULL);
600
601     ENTER;
602     SAVETMPS;
603
604     /* create a new SV pointing to 'src', and increase its refcount
605      * accordingly.  The SV is mortal, so FREETMPS will decrease the 
606      * refcount, unless the callee keeps a copy of it somewhere */
607     amglue_source_ref(src);
608     src_sv = SWIG_NewPointerObj(src, SWIGTYPE_p_amglue_Source,
609                                  SWIG_OWNER | SWIG_SHADOW);
610
611     PUSHMARK(SP);
612     XPUSHs(src_sv);
613     XPUSHs(sv_2mortal(new_sv_for_xmsg(msg)));
614     XPUSHs(sv_2mortal(new_sv_for_xfer(xfer)));
615     PUTBACK;
616
617     call_sv(src->callback_sv, G_EVAL|G_DISCARD);
618
619     FREETMPS;
620     LEAVE;
621
622     /* these may have been freed, so don't use them after this point */
623     src_sv = NULL;
624     src = NULL;
625
626     /* check for an uncaught 'die'.  If we don't do this, then Perl will longjmp()
627      * over the GMainLoop mechanics, leaving GMainLoop in an inconsistent (locked)
628      * state. */
629     if (SvTRUE(ERRSV)) {
630         /* We handle this just the way the default 'die' handler in Amanda::Debug 
631          * does, but since Amanda's debug support may not yet be running, we back
632          * it up with an exit() */
633         g_critical("%s", SvPV_nolen(ERRSV));
634         exit(1);
635     }
636
637     return TRUE;
638 }
639 %}
640
641 %newobject xfer_get_amglue_source;
642 %inline %{
643 amglue_Source *
644 xfer_get_amglue_source(
645     Xfer *xfer)
646 {
647     return amglue_source_get(xfer_get_source(xfer),
648         (GSourceFunc)xmsgsource_perl_callback);
649 }
650 %}
651
652 /*
653  * XMsg and XMsgSource handling
654  */
655
656 /*
657  * The perl side
658  */
659
660 /* First, a few macros to generate decent Perl */
661
662 %define PACKAGE(PKG)
663 %perlcode {
664 package PKG;
665 }
666 %enddef
667
668 %define XFER_ELEMENT_SUBCLASS()
669 %perlcode {
670 use vars qw(@ISA);
671 @ISA = qw( Amanda::Xfer::Element );
672 }
673 %enddef
674
675 %define DECLARE_CONSTRUCTOR(C_CONSTRUCTOR)
676 %perlcode {
677 sub new { 
678     my $pkg = shift;
679     # The C function adds the proper blessing -- this function
680     # just gets $pkg out of the way.
681     Amanda::Xfer::C_CONSTRUCTOR(@_);
682 }
683 }
684 %enddef
685
686 %define OVERLOAD_REPR()
687 %perlcode {use overload '""' => sub { $_[0]->repr(); };
688 }
689 %enddef
690
691 %define DECLARE_METHOD(METHOD_NAME, C_FUNCTION)
692 %perlcode {*METHOD_NAME = *Amanda::Xfer::C_FUNCTION;
693 }
694 %enddef
695
696 /* And now define the required perl classes */
697
698 PACKAGE(Amanda::Xfer::Xfer)
699 DECLARE_CONSTRUCTOR(xfer_new);
700 DECLARE_METHOD(DESTROY, xfer_unref);
701 OVERLOAD_REPR()
702 DECLARE_METHOD(repr, xfer_repr);
703 DECLARE_METHOD(get_status, xfer_get_status);
704 DECLARE_METHOD(get_source, xfer_get_amglue_source);
705 DECLARE_METHOD(start, xfer_start);
706 DECLARE_METHOD(cancel, xfer_cancel);
707
708 /* ---- */
709
710 PACKAGE(Amanda::Xfer::Element)
711 DECLARE_METHOD(DESTROY, xfer_element_unref);
712 OVERLOAD_REPR()
713 DECLARE_METHOD(repr, xfer_element_repr);
714
715 /* ---- */
716
717 PACKAGE(Amanda::Xfer::Element::Glue)
718 XFER_ELEMENT_SUBCLASS()
719 /* no constructor -- internal use only */
720
721 /* ---- */
722
723 PACKAGE(Amanda::Xfer::Source::Device)
724 XFER_ELEMENT_SUBCLASS()
725 DECLARE_CONSTRUCTOR(xfer_source_device)
726
727 /* ---- */
728
729 PACKAGE(Amanda::Xfer::Source::Fd)
730 XFER_ELEMENT_SUBCLASS()
731 DECLARE_CONSTRUCTOR(xfer_source_fd)
732
733 /* ---- */
734
735 PACKAGE(Amanda::Xfer::Source::Random)
736 XFER_ELEMENT_SUBCLASS()
737 DECLARE_CONSTRUCTOR(xfer_source_random)
738
739 /* ---- */
740
741 PACKAGE(Amanda::Xfer::Source::Pattern)
742 XFER_ELEMENT_SUBCLASS()
743 DECLARE_CONSTRUCTOR(xfer_source_pattern)
744
745 /* ---- */
746
747 PACKAGE(Amanda::Xfer::Filter::Xor)
748 XFER_ELEMENT_SUBCLASS()
749 DECLARE_CONSTRUCTOR(xfer_filter_xor)
750
751 /* ---- */
752
753 PACKAGE(Amanda::Xfer::Dest::Device)
754 XFER_ELEMENT_SUBCLASS()
755 DECLARE_CONSTRUCTOR(xfer_dest_device)
756
757 /* ---- */
758
759 PACKAGE(Amanda::Xfer::Dest::Fd)
760 XFER_ELEMENT_SUBCLASS()
761 DECLARE_CONSTRUCTOR(xfer_dest_fd)
762
763 /* ---- */
764
765 PACKAGE(Amanda::Xfer::Dest::Null)
766 XFER_ELEMENT_SUBCLASS()
767 DECLARE_CONSTRUCTOR(xfer_dest_null)
768
769 /* ---- */
770
771 PACKAGE(Amanda::Xfer::Msg)
772 %perlcode %{
773 use Data::Dumper;
774 use overload '""' => sub { $_[0]->repr(); };
775
776 sub repr {
777     my ($self) = @_;
778     local $Data::Dumper::Indent = 0;
779     local $Data::Dumper::Terse = 1;
780     local $Data::Dumper::Useqq = 1;
781
782     my $typestr = Amanda::Xfer::xmsg_type_to_string($self->{'type'});
783     my $str = "{ type => \$$typestr, elt => $self->{'elt'}, version => $self->{'version'},";
784
785     my %skip = ( "type" => 1, "elt" => 1, "version" => 1 );
786     for my $k (keys %$self) {
787         next if $skip{$k};
788         $str .= " $k => " . Dumper($self->{$k}) . ",";
789     }
790
791     # strip the trailing comma and add a closing brace
792     $str =~ s/,$/ }/g;
793
794     return $str;
795 }
796 %}
797
798 /* ---- */
799
800 PACKAGE(Amanda::Xfer)
801 %perlcode %{
802 # make Amanda::Xfer->new equivalent to Amanda::Xfer::Xfer->new (don't
803 # worry, the blessings work out just fine)
804 *new = *Amanda::Xfer::Xfer::new;
805 %}