-
-
Save sahidursuman/1ff21e85d6a60a6cfee3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
HELP=" | |
Created on: 20/01/2010 | |
By: Zachary Klippenstein | |
This script takes a local directory and a set of options | |
specifying how/where to connect to a remote Samba server, | |
and a newline-delimited list of paths on standard input. | |
The paths should be relative to the local directory and | |
the remote directory. They will be downloaded from the remote | |
server into the local directory, with all components of the | |
path converted to lowercase. | |
If files are specified on stdin, each file is backed up | |
before attempting to synchronize, and if synchronization fails, | |
the original file is restored. This does NOT happen if --all is | |
specified. See the note in the option description below for more | |
information. | |
usage: smb-sync.sh | |
smb-sync.sh localdir smburl [--all [--overwrite]] [--ignore-file-case] | |
[--quiet] [--chmod localpermissions] [--chown localownership] [--verbose] | |
smburl Remote location to download from. Format: | |
smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]] | |
localpermissions Octal permissions to set downloaded files to after | |
download | |
localownership 'user', ':group', or 'user:group' to chown files to | |
--all If specified, the remote directory will be recursively downloaded into localdir. | |
NOTE: This options has the following effects: | |
- individual files are not backed up. If sync fails, restore manually | |
- --chmod and --chown options are ignored | |
--overwrite Overwrite pre-existing files. If this is not specified, such files will just be left alone. | |
--ignore-file-case Doesn't bother to convert files specified on stdin to lowercase. | |
NOTE: Running the script with no arguments prints this message. | |
" | |
# Session variables, defaults should be set here | |
script_name="$0" | |
local_dir= | |
smb_url= | |
local_perms= | |
local_ownership= | |
verbose="" | |
quiet="" | |
all_recursive="" | |
overwrite="" | |
ignore_file_case="" | |
# Options passed to smbget | |
SMBGET_OPTIONS="--nonprompt" | |
# Process-specific backup suffix | |
BACKUP_SUFFIX=".$$.presync" | |
function print_usage() | |
{ | |
echo "$HELP" | |
exit 1 | |
} | |
# Strips a trailing slash off it's first argument | |
function deslash() | |
{ | |
var="$1" | |
str="${!var}" | |
# Check for trailing slash | |
if (echo "$str" | egrep '/$' &>/dev/null); then | |
# Remove the last character | |
str=${str:0:${#str}-1} | |
fi | |
# Set the original variable back | |
eval "${var}='$str'" | |
} | |
# Cleans an input line and returns true iff the line | |
# should be processed. Returns false if line is blank. | |
function clean() | |
{ | |
var="$1" | |
str="${!var}" | |
processLine=0 | |
# Remove leading/trailing whitespace | |
str=`echo "$str" | awk '{gsub(/[[:space:]]*/,"",$0); print $0}'` | |
# Remove trailing slash | |
deslash str | |
# Check for blank/empty line | |
[ -z "$str" ] && processLine=1 | |
# Set original variable to the cleaned version | |
eval "${var}='$str'" | |
return $processLine | |
} | |
function lowercase() | |
{ | |
var="$1" | |
str=`echo ${!var} | awk '{print tolower(\$0)}'` | |
eval "${var}='$str'" | |
} | |
# Reads a list of output from smbget, detects errors due to | |
# pre-existing files, removes them, and prints the file names to | |
# stdout. | |
function removeExistingFiles() | |
{ | |
#egrep "^Can't open .\+: File exists$" 2>/dev/null | | |
while read existingFileLine; do | |
if (echo "$existingFileLine" | egrep "^Can't open .+: File exists\$" &>/dev/null); then | |
# Parse the actual file name from the error message | |
existingFile=${existingFileLine:11:${#existingFileLine}-(11+13)} | |
rm -f "$existingFile" | |
[ $verbose ] && echo "Overwriting: $existingFile" 1>&2 | |
echo "$existingFile" | |
fi | |
done | |
} | |
# If --all was specified, deals with output from smbget | |
# concerning existing files. | |
# If --overwrite was specified, overwrites them, else does nothing | |
function handleExistingFiles() | |
{ | |
if [ $overwrite ]; then | |
# If any of the files already exist, remove them and download them separately | |
removeExistingFiles | | |
"$script_name" "$local_dir" "$smb_url" --ignore-file-case --quiet | |
fi | |
} | |
# Parse arguments | |
local_dir="$1" | |
smb_url="$2" | |
shift; shift | |
# Validate mandatory arguments | |
if [ -z "$local_dir" -o -z "$smb_url" ]; then | |
print_usage | |
fi | |
if [ ! -d "$local_dir" ]; then | |
echo "Local directory does not exist: $local_dir" | |
exit 1 | |
fi | |
# Check for optional arguments | |
while [ "$1" ]; do | |
case "$1" in | |
--all) | |
all_recursive="true" | |
;; | |
--overwrite) | |
overwrite="true" | |
;; | |
--ignore-file-case) | |
ignore_file_case="true" | |
;; | |
--chmod) | |
local_perms="$2" | |
[ -z "$local_perms" ] && print_usage | |
shift | |
;; | |
--chown) | |
local_ownership="$2" | |
[ -z "$local_ownership" ] && print_usage | |
shift | |
;; | |
--verbose) | |
verbose="true" | |
;; | |
--quiet) | |
quiet="true" | |
;; | |
esac | |
shift | |
done | |
# Normalize formatting of local/remote paths | |
deslash local_dir | |
deslash smb_url | |
# Blindly download all files in remote directory | |
if [ $all_recursive ]; then | |
# Save the current directory | |
origDir="`pwd`" | |
# -o options to smbget isn't compatible with -R: i.e. all files will be | |
# downloaded into current working directory, so we have to enter localdir | |
# manually before downloading | |
cd "$local_dir" | |
# Recursively download all files in the remote dir. | |
# NOTE: smbget will attempt to change permissions of the current | |
# directory after downloading, and this will (should) fail. | |
smbget $SMBGET_OPTIONS -R "${smb_url}" 2>&1 | | |
# Determine what to do with existing files based on output of smbget | |
# and command-line arguments | |
(cd "$origDir" && handleExistingFiles) | |
# Files will be specified on stdin. | |
else | |
SMBGET_OPTIONS="$SMBGET_OPTIONS --keep-permissions --quiet" | |
# Main loop: read line, download, modify if necessary, repeat | |
while read line; do | |
success=0 | |
# Only process line if cleaning results in valid line | |
if clean line; then | |
[ $quiet ] || echo "Synchronizing: $line" | |
[ $ignore_file_case ] || lowercase line | |
local_file="${local_dir}/${line}" | |
backup_file="${local_file}${BACKUP_SUFFIX}" | |
# Backup original if it exists | |
if [ -f "$local_file" ]; then | |
mv "$local_file" "$backup_file" | |
success=$? | |
if [ $success -ne 0 -o ! -f "$backup_file" ]; then | |
echo "Couldn't create backup file, skipping" >&2 | |
success=1 | |
fi | |
fi | |
# Download the file | |
if [ $success -eq 0 ]; then | |
smbget $SMBGET_OPTIONS -o "${local_file}" "${smb_url}/${line}" | |
# smbget's return value is backwards, so we have to NOT it first | |
[ $? -eq 1 ] | |
success=$? | |
if [ ! -f "$local_file" ]; then | |
echo "Download failed." >&2 | |
success=1 | |
fi | |
fi | |
if [ $success -eq 0 -a "$local_perms" ]; then | |
chmod "$local_perms" "$local_file" | |
success=$? | |
fi | |
if [ $success -eq 0 -a "$local_ownership" ]; then | |
chown "$local_ownership" "$local_file" | |
success=$? | |
fi | |
# If any part of the process failed, remove local copy | |
if [ $success -ne 0 ]; then | |
if [ -f "$backup_file" ]; then | |
echo "Synchronization failed, restoring pre-sync backup..." >&2 | |
mv "$backup_file" "$local_file" || echo "Error restoring backup, file is: $backup_file" >&2 | |
fi | |
[ $quiet ] || echo -e "\tfailure." | |
else | |
if [ -f "$backup_file" ]; then | |
rm -f "$backup_file" | |
fi | |
[ $quiet ] || echo -e "\tsuccess." | |
fi | |
fi | |
done | |
fi | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment