* A failed full dump is now saved as a partial (incomplete) dump,
[BackupPC.git] / lib / BackupPC / Xfer / Smb.pm
index 124b6f0..3f88c3c 100644 (file)
@@ -11,7 +11,7 @@
 #   Craig Barratt  <cbarratt@users.sourceforge.net>
 #
 # COPYRIGHT
-#   Copyright (C) 2001  Craig Barratt
+#   Copyright (C) 2001-2003  Craig Barratt
 #
 #   This program is free software; you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@
 #
 #========================================================================
 #
-# Version 1.6.0_CVS, released 10 Dec 2002.
+# Version 2.1.0_CVS, released 3 Jul 2003.
 #
 # See http://backuppc.sourceforge.net.
 #
@@ -78,8 +78,9 @@ sub start
     my($t) = @_;
     my $bpc = $t->{bpc};
     my $conf = $t->{conf};
-    my $I_option = $t->{hostIP} eq $t->{host} ? "" : " -I $t->{hostIP}";
-    my($fileList, $optX, $smbClientCmd, $logMsg);
+    my $I_option = $t->{hostIP} eq $t->{host} ? [] : ['-I', $t->{hostIP}];
+    my(@fileList, $X_option, $smbClientCmd, $logMsg);
+    my($timeStampFile);
     local(*SMB);
 
     #
@@ -97,11 +98,7 @@ sub start
         return;
     }
     if ( $t->{type} eq "restore" ) {
-        $smbClientCmd =
-              "$conf->{SmbClientPath} '\\\\$t->{host}\\$t->{shareName}'"
-            . "$I_option -U '$conf->{SmbShareUserName}' -E -N -d 1"
-            . " $conf->{SmbClientArgs}"
-            . " -c 'tarmode full' -Tx -";
+        $smbClientCmd = $conf->{SmbClientRestoreCmd};
         $logMsg = "restore started for share $t->{shareName}";
     } else {
        #
@@ -124,45 +121,49 @@ sub start
                };
            }
        }
+       $t->{fileIncludeHash} = {};
         if ( defined($conf->{BackupFilesOnly}{$t->{shareName}}) ) {
             foreach my $file ( @{$conf->{BackupFilesOnly}{$t->{shareName}}} ) {
-                $file =~ s/'/\\'/g;
-                $fileList .= "'$file' ";
+               push(@fileList, $file);
+               $t->{fileIncludeHash}{$file} = 1;
             }
         } elsif ( defined($conf->{BackupFilesExclude}{$t->{shareName}}) ) {
             foreach my $file ( @{$conf->{BackupFilesExclude}{$t->{shareName}}} )
             {
-                $file =~ s/'/\\'/g;
-                $fileList .= "'$file' ";
+               push(@fileList, $file);
             }
            #
            # Allow simple wildcards in exclude list by specifying "r" option.
            #
-            $optX = "rX";
+            $X_option = "rX";
         }
         if ( $t->{type} eq "full" ) {
-            $smbClientCmd =
-                  "$conf->{SmbClientPath} '\\\\$t->{host}\\$t->{shareName}'"
-                . "$I_option -U '$conf->{SmbShareUserName}' -E -N -d 1"
-                . " $conf->{SmbClientArgs}"
-                . " -c 'tarmode full'"
-                . " -Tc$optX - $fileList";
+           $smbClientCmd = $conf->{SmbClientFullCmd};
             $logMsg = "full backup started for share $t->{shareName}";
         } else {
-            my $timeStampFile = "$t->{outDir}/timeStamp.level0";
-            open(LEV0, ">$timeStampFile") && close(LEV0);
+            $timeStampFile = "$t->{outDir}/timeStamp.level0";
+            open(LEV0, ">", $timeStampFile) && close(LEV0);
             utime($t->{lastFull} - 3600, $t->{lastFull} - 3600, $timeStampFile);
-            $smbClientCmd =
-                  "$conf->{SmbClientPath} '\\\\$t->{host}\\$t->{shareName}'"
-                . "$I_option -U '$conf->{SmbShareUserName}' -E -N -d 1"
-                . " $conf->{SmbClientArgs}"
-                . " -c 'tarmode full'"
-                . " -TcN$optX $timeStampFile - $fileList";
+           $smbClientCmd = $conf->{SmbClientIncrCmd};
             $logMsg = "incr backup started back to "
                         . $bpc->timeStamp($t->{lastFull} - 3600, 0)
                         . "for share $t->{shareName}";
         }
     }
+    my $args = {
+       smbClientPath => $conf->{SmbClientPath},
+       host          => $t->{host},
+       hostIP        => $t->{hostIP},
+       client        => $t->{client},
+       shareName     => $t->{shareName},
+       userName      => $conf->{SmbShareUserName},
+       fileList      => \@fileList,
+       I_option      => $I_option,
+       X_option      => $X_option,
+       timeStampFile => $timeStampFile,
+    };
+    $smbClientCmd = $bpc->cmdVarSubstitute($smbClientCmd, $args);
+
     if ( !defined($t->{xferPid} = open(SMB, "-|")) ) {
         $t->{_errStr} = "Can't fork to run smbclient";
         return;
@@ -194,14 +195,15 @@ sub start
             open(STDOUT, ">&$t->{pipeWH}");
         }
         #
-        # exec smbclient.
+        # Run smbclient.
         #
-        exec($smbClientCmd);
+        $bpc->cmdExecOrEval($smbClientCmd, $args);
         # should not be reached, but just in case...
         $t->{_errStr} = "Can't exec $conf->{SmbClientPath}";
         return;
     }
-    $t->{XferLOG}->write(\"Running: $smbClientCmd\n");
+    my $str = "Running: " . $bpc->execCmd2ShellCmd(@$smbClientCmd) . "\n";
+    $t->{XferLOG}->write(\$str);
     alarm($conf->{ClientTimeout});
     $t->{_errStr} = undef;
     return $logMsg;
@@ -257,8 +259,24 @@ sub readOutput
                     || /^Error: Looping in FIND_NEXT/i
                     || /^SUCCESS - 0/i
                     || /^Call timed out: server did not respond/i
+                   || /^tree connect failed: ERRDOS - ERRnoaccess \(Access denied\.\)/
+                   || /^tree connect failed: NT_STATUS_BAD_NETWORK_NAME/
                  ) {
-            $t->{hostError} ||= $_;
+           if ( $t->{hostError} eq "" ) {
+               $t->{XferLOG}->write(\"This backup will fail because: $_\n");
+               $t->{hostError} = $_;
+           }
+        } elsif ( /^NT_STATUS_ACCESS_DENIED listing (.*)/
+              || /^ERRDOS - ERRnoaccess \(Access denied\.\) listing (.*)/ ) {
+           my $badDir = $1;
+           $badDir =~ s{\\}{/}g;
+           $badDir =~ s{/+}{/}g;
+           $badDir =~ s{/\*$}{};
+           if ( $t->{hostError} eq ""
+                   && ($badDir eq "" || $t->{fileIncludeHash}{$badDir}) ) {
+               $t->{XferLOG}->write(\"This backup will fail because: $_\n");
+               $t->{hostError} ||= $_;
+           }
         } elsif ( /smb: \\>/
                 || /^added interface/i
                 || /^tarmode is now/i
@@ -297,7 +315,10 @@ sub readOutput
                 my $badFile = $1;
                 $badFile =~ s{\\}{/}g;
                 $badFile =~ s{^/}{};
-                push(@{$t->{badFiles}}, "$t->{shareName}/$badFile");
+                push(@{$t->{badFiles}}, {
+                       share => $t->{shareName},
+                       file  => $badFile
+                   });
             }
         }
     }
@@ -322,7 +343,7 @@ sub xferPid
 {
     my($t) = @_;
 
-    return $t->{xferPid};
+    return ($t->{xferPid});
 }
 
 sub logMsg