add inverse recursive feature or do a mkdir -p/install -D -d ?

Infomaniak Network SA / Guy Baconniere baco at infomaniak.ch
Wed Jun 6 10:31:39 GMT 2007


Hi,

Background :
I am using rsync to push/sync FTP uploaded files from master server
to slave servers. On slaves the full directory path of each file doesn't
exist so rsync is unable to sync it and there a no options in rsync to do
something like "mkdir -p/install -D -d" on destination before sync file.

N.B. I don't want to do a full sync of the root/home directory every time
a file is uploaded somewhere in the hierarchy on the master server

Can you implement recursive make directory for the parents missing
on the destination ?

As alternative can you add an option to do a inverse recursive
syncronisation
of every parents directoy missing until full path is available on the
destination.

As workaround I have coded a little script rrsync.sh who do
an inverse recursive sync by calling rsync dry-run on every parents and
do a full rsync from the first parent available on destination.


TEST

$ mkdir -p test1/toto1/toto2/toto3/toto4
$ mkdir -p test2
$ touch test1/toto1/toto2/toto3/toto4/a

$ rsync -av test1/toto1/toto2/toto3/toto4 test2/toto1/toto2/toto3/toto4
building file list ... done
rsync: mkdir "/home/baco/test2/toto1/toto2/toto3/toto4" failed: No such
file or directory (2)
rsync error: error in file IO (code 11) at main.c(529) [receiver=2.6.9]
rsync: connection unexpectedly closed (8 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(453)
[sender=2.6.9]

$ rsync -av test1/toto1/toto2/toto3/toto4/a test2/toto1/toto2/toto3/toto4/a
building file list ... done
rsync: push_dir#3 "/home/baco/test2/toto1/toto2/toto3/toto4" failed: No
such file or directory (2)
rsync error: errors selecting input/output files, dirs (code 3) at
main.c(565) [receiver=2.6.9]
rsync: connection unexpectedly closed (8 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(453)
[sender=2.6.9]

$ ./rrsync.sh test1/toto1/toto2/toto3/toto4/a
test2/toto1/toto2/toto3/toto4/a
rsync -av test1/toto1 test2/toto1

$ ./rrsync.sh test1/toto1/toto2/toto3/toto4 test2/toto1/toto2/toto3/toto4
rsync -av test1/toto1 test2/toto1

$ rsync -av test1/toto1 test2/toto1
building file list ... done
created directory test2/toto1
toto1/
toto1/toto2/
toto1/toto2/toto3/
toto1/toto2/toto3/toto4/
toto1/toto2/toto3/toto4/a

sent 196 bytes  received 66 bytes  524.00 bytes/sec
total size is 0  speedup is 0.00

$ ./rrsync.sh test1/toto1/toto2/toto3/toto4 test2/toto1/toto2/toto3/toto4
rsync -av test1/toto1/toto2 test2/toto1/toto2

$ ./rrsync.sh test1/toto1/toto2/toto3/toto4/a
test2/toto1/toto2/toto3/toto4/a
rsync -av test1/toto1/toto2 test2/toto1/toto2


CODE

#!/bin/bash
# rrsync.sh by Guy Baconniere

usage="$0 <src> <dst>"
src=${1:?$usage}
dst=${2:?$usage}

function crushedpath() {
        path="${1:?give a path please}"
        path=$(echo -n "${path}" | sed -e 's,/$,,')
        pathdepth=$(echo -n "${path}" | sed -e 's,[^/],,g' | wc -c)
        echo "${path}"
        for (( i=1; ${i} < ${pathdepth}; i=$(( ${i}+1 )) )); do
                fpath=$(( ${pathdepth} - ${i} ))
                subpath=$(echo -n "${path}" | cut -d "/" -f1-${fpath})
                if [ ! -z "${subpath}" ]; then
                        echo "${subpath}"
                fi
        done
}

function doublecrushedpath() {
        src="${1:?give a src path please}"
        dst="${2:?give a dst path please}"
        src=$(echo -n "${src}" | sed -e 's,/$,,')
        dst=$(echo -n "${dst}" | sed -e 's,/$,,')
        srcdepth=$(echo -n "${src}" | sed -e 's,[^/],,g' | wc -c)
        dstdepth=$(echo -n "${dst}" | sed -e 's,[^/],,g' | wc -c)
        if [ $srcdepth -lt $dstdepth ]; then
                maxdepth=$srcdepth;
        else
                maxdepth=$dstdepth;
        fi
        echo "${src} ${dst}"
        for (( i=1; ${i} < ${maxdepth}; i=$(( ${i}+1 )) )); do
                fsrc=$(( ${srcdepth} - ${i} ))
                fdst=$(( ${dstdepth} - ${i} ))
                subsrc=$(echo -n "${src}" | cut -d "/" -f1-${fsrc})
                subdst=$(echo -n "${dst}" | cut -d "/" -f1-${fdst})
                if [ ! -z "${subsrc}" ] || [ ! -z "${subdst}" ]; then
                        echo "${subsrc} ${subdst}"
                fi
        done
}

function rrsync() {
        src=${1:?src please}
        dst=${2:?dst please}
        doublecrushedpath "${src}" "${dst}" | while read t_src t_dst; do
                if ! rsync -nlD -- "${t_src}" "${t_dst}" 2>&1 \
                | grep -q -E 'rsync: push_dir#3 "[^"]*" failed: No such
file or directory'; then
                        echo rsync -av "${t_src}" "${t_dst}" || true
                        break
                fi
        done

}

#crushedpath "${dst}"
#doublecrushedpath "${src}" "${dst}"

rrsync "${src}" "${dst}"



--

Infomaniak Network SA
Guy Baconniere <baco at infomaniak.ch>
Unix System Administrator
Certified Linux Engineer (RHCE, LPIC-2)
Avenue de la Praille 26
1227 Carouge (Geneva)
Switzerland (CH)
Phone +41 (0)22 820 3541
Fax +41 (0)22 820 3546
AS29222 / BACO-RIPE



More information about the rsync mailing list