Index: /trunk/PS-IPP-Config/lib/PS/IPP/Config.pm
===================================================================
--- /trunk/PS-IPP-Config/lib/PS/IPP/Config.pm	(revision 29890)
+++ /trunk/PS-IPP-Config/lib/PS/IPP/Config.pm	(revision 29891)
@@ -1087,4 +1087,128 @@
 }
 
+sub prepare_output
+{
+    my $self = shift;             # Configuration object
+    my $name = shift;             # Name of the filerule
+    my $outroot = shift;          # For replacing {OUTPUT}
+    my $component = shift;        # For replacing {CHIP.NAME} and {CELL.NAME}
+    my $delete_existing = shift;  # if file exists delete it
+    my $r_error = shift;          # reference to error code
+
+    die "prepare_output: invalid number of arguments" if !defined $r_error;
+
+    $$r_error = 0;
+
+    my $output = $self->filename($name, $outroot, $component);
+    if (!$output) {
+        # error message emitted by filename should be sufficient
+        $$r_error = $PS_EXIT_CONFIG_ERROR;
+        return undef;
+    }
+
+    if (file_scheme($output) ne 'neb') {
+        # non-nebulous file we're done
+        if ($delete_existing) {
+            if (!$self->file_delete($output)) {
+                carp "failed to delete $output";
+                $$r_error = $PS_EXIT_SYS_ERROR;
+                $output = undef;
+            }
+        }
+        return $output;
+    }
+
+    my $neb = $self->nebulous;
+    if ($neb->storage_object_exists($output)) {
+        if ($delete_existing) {
+            # avoid dead instances by moving the file before deleting it.
+            # append current time to form new name
+            my $todelete;
+            eval {
+                # parse the key so that we can compute the new name
+                require Nebulous::Key;
+            };
+            if ($@) {
+                carp "Can't find Nebulous::Key";
+                $$r_error = $PS_EXIT_CONFIG_ERROR;
+                return undef;
+            }
+            eval {
+                # parse the key so that we can compute the new name
+                my $neb_key = Nebulous::Key::parse_neb_key($output);
+                die "parse_neb_key failed" if !$neb_key;
+                my $path = $neb_key->path;
+                die "neb_key has no path" if !$path;
+                my $ticks = time();
+                $todelete = "ipp_trash/$path.$ticks";
+                $neb->move($output, $todelete);
+            };
+            if ($@) {
+                carp "nebulous move failed for $output";
+                $output = undef;
+                $$r_error = $PS_EXIT_SYS_ERROR;
+            }
+            if ($todelete) {
+                eval {
+                    $neb->delete($todelete);
+                };
+                if ($@) {
+                    carp "nebulous delete for $todelete failed. Ignoring.\n";
+                    $$r_error = $PS_EXIT_SYS_ERROR;
+                }
+            }
+        } else {
+            # Make sure that there is only 1 instance.
+
+            eval {
+                $neb->there_can_be_only_one($output);
+            };
+            if ($@) {
+                carp "nebulous there_can_be_only_one() failed for $output";
+                $output = undef;
+                $$r_error = $PS_EXIT_SYS_ERROR;
+            }
+        }
+    }
+    return $output;
+}
+
+# Cause a nebulous file to be replicated setting the user.copies value
+sub replicate_file
+{
+    my $self = shift;
+    my $file = shift;
+    my $copies = shift;
+
+    if (file_scheme($file) ne 'neb') {
+        carp "cannot replicate non-neulous file: $file";
+        return 0;
+    }
+
+    if (!$copies) {
+        $copies = 2;
+    }
+
+    my $neb = $self->nebulous;
+    eval {
+        $neb->setxattr($file, 'user.copies', $copies, 'replace');
+    };
+    if ($@) {
+        carp "failed to set user.copies for $file";
+        return 0;
+    }
+
+    # XXX: if copies > 2 should we make more replicants here ?
+    eval {
+        $neb->replicate($file);
+    };
+    if ($@) {
+        carp "failed to replicate $file";
+        return 0;
+    }
+    return 1;
+}
+
+
 # Return catdir for tessellation, from TESSELLATIONS within the site configuration
 sub tessellation_catdir
