• VMware

    Learn about VMware virtualization for its products like vsphere ESX and ESXi, vCenter Server, VMware View, VMware P2V and many more

  • Linux

    Step by step configuration tutorials for many of the Linux services like DNS, DHCP, FTP, Samba4 etc including many tips and tricks in Red Hat Linux.

  • Database

    Learn installation and configuration of databases like Oracle, My SQL, Postgresql, etc including many other related tutorials in Linux.

  • Life always offers you a second chance ... Its called tomorrow !!!

    Sunday, September 11, 2016

    How to preserve symbolic link while copying a file in Linux

    Below set of commands are executed on Suse Linux Enterprise Server 11 SP 3 operating system,

    There can be many scenarios of copying symbolic links between different directories, let me try to explain some of the cases with examples to help you understand

    I have created few sample files and symbolic links to demonstrate this example
    # mkdir /tmp/src_file
    # cd /tmp/src_files

    # ll
    total 0
    -rw-r--r-- 1 root root  0 Sep 11 17:53 a
    -rw-r--r-- 1 root root  0 Sep 11 17:53 b
    -rw-r--r-- 1 root root  0 Sep 11 17:53 c
    lrwxrwxrwx 1 root root 13 Sep 11 17:53
    cron_allow -> ../cron.allow
    lrwxrwxrwx 1 root root 12 Sep 11 17:53 cron_deny -> ../cron.deny

    Copy symbolic links as files

    Above I have two smylinks cron_allow and cron_deny, Let us copy them to /tmp/dst_files as normal files instead of symlinks

    # cp -LRv /tmp/src_files/* /tmp/dst_files/
    `/tmp/src_files/a' -> `/tmp/dst_files/a'
    `/tmp/src_files/b' -> `/tmp/dst_files/b'
    `/tmp/src_files/c' -> `/tmp/dst_files/c'
    `/tmp/src_files/cron_allow' -> `/tmp/dst_files/cron_allow'
    `/tmp/src_files/cron_deny' -> `/tmp/dst_files/cron_deny'

    # ll /tmp/dst_files/
    total 8
    -rw-r--r-- 1 root root  0 Sep 11 18:03 a
    -rw-r--r-- 1 root root  0 Sep 11 18:03 b
    -rw-r--r-- 1 root root  0 Sep 11 18:03 c
    -rw-r--r-- 1 root root 28 Sep 11 18:03 cron_allow
    -rw-r--r-- 1 root root 15 Sep 11 18:03 cron_deny

    As you see both symlinks are converted into normal file. Let us match the content of these with the original file
    # sdiff cron_allow /tmp/cron.allow
    root                                                         root
    deepak                                                       deepak
    amit                                                         amit
    rahul                                                        rahul

    From the 'man' page
    ‘-L’ ,‘--dereference’ - Follow symbolic links when copying from them. With this option, cp cannot create a symbolic link. For example, a symlink (to regular file) in the source tree will be copied to a regular file in the destination tree.


    Copy symlinks as symlinks (not a file)

    # cp -Prv /tmp/src_files/* /tmp/dst_files/
    `/tmp/src_files/a' -> `/tmp/dst_files/a'
    `/tmp/src_files/b' -> `/tmp/dst_files/b'
    `/tmp/src_files/c' -> `/tmp/dst_files/c'
    `/tmp/src_files/cron_allow' -> `/tmp/dst_files/cron_allow'
    `/tmp/src_files/cron_deny' -> `/tmp/dst_files/cron_deny'

    # ll /tmp/dst_files/
    total 0
    -rw-r--r-- 1 root root  0 Sep 11 18:06 a
    -rw-r--r-- 1 root root  0 Sep 11 18:06 b
    -rw-r--r-- 1 root root  0 Sep 11 18:06 c
    lrwxrwxrwx 1 root root 13 Sep 11 18:06
    cron_allow -> ../cron.allow
    lrwxrwxrwx 1 root root 12 Sep 11 18:06 cron_deny -> ../cron.deny

    This can also be achieved with some more arguments like below
    # cp -dv /tmp/src_files/* /tmp/dst_files/
    `/tmp/src_files/a' -> `/tmp/dst_files/a'
    `/tmp/src_files/b' -> `/tmp/dst_files/b'
    `/tmp/src_files/c' -> `/tmp/dst_files/c'
    `/tmp/src_files/cron_allow' -> `/tmp/dst_files/cron_allow'
    `/tmp/src_files/cron_deny' -> `/tmp/dst_files/cron_deny'

    Copy symlinks with same permissions and ownership as from source directory

    Normally if you copy a file the permission of the target location is changed to the user which was used to copy the file (considering that user as the new owner of the target location)

    Let us change the permission and owner of one of the file from our source directory
    # ll
    total 0
    -rwxrwxrwx 1 oamsys root  0 Sep 11 17:53 a
    -rwxrwxrwx 1 oamsys root  0 Sep 11 17:53 b
    -rw-r--r-- 1 root   root  0 Sep 11 17:53 c
    lrwxrwxrwx 1 root   root 13 Sep 11 17:53
    cron_allow -> ../cron.allow
    lrwxrwxrwx 1 root   root 12 Sep 11 17:53 cron_deny -> ../cron.deny

    After copying
    # cp -dv /tmp/src_files/* /tmp/dst_files/
    `/tmp/src_files/a' -> `/tmp/dst_files/a'
    `/tmp/src_files/b' -> `/tmp/dst_files/b'
    `/tmp/src_files/c' -> `/tmp/dst_files/c'
    `/tmp/src_files/cron_allow' -> `/tmp/dst_files/cron_allow'
    `/tmp/src_files/cron_deny' -> `/tmp/dst_files/cron_deny'

    # ll /tmp/dst_files/
    total 0
    -rwxr-xr-x 1 root root  0 Sep 11 18:12 a
    -rwxr-xr-x 1 root root  0 Sep 11 18:12 b
    -rw-r--r-- 1 root root  0 Sep 11 18:12 c
    lrwxrwxrwx 1 root root 13 Sep 11 18:12 cron_allow -> ../cron.allow
    lrwxrwxrwx 1 root root 12 Sep 11 18:12 cron_deny -> ../cron.deny

    So considering my umask value i.e. 0022 the file permission were updated to 755 and ownership has been changed to 'root'' as the files were copied using 'root' user.

    So how do I preserve these permissions along with symlinks
    # cp -dav /tmp/src_files/* /tmp/dst_files/
    `/tmp/src_files/a' -> `/tmp/dst_files/a'
    `/tmp/src_files/b' -> `/tmp/dst_files/b'
    `/tmp/src_files/c' -> `/tmp/dst_files/c'
    `/tmp/src_files/cron_allow' -> `/tmp/dst_files/cron_allow'
    `/tmp/src_files/cron_deny' -> `/tmp/dst_files/cron_deny'

    # ll /tmp/dst_files/
    total 0
    -
    rwxrwxrwx 1 oamsys root  0 Sep 11 17:53 a
    -rwxrwxrwx 1 oamsys root  0 Sep 11 17:53 b
    -rw-r--r-- 1 root   root  0 Sep 11 17:53 c
    lrwxrwxrwx 1 root   root 13 Sep 11 17:53 cron_allow -> ../cron.allow
    lrwxrwxrwx 1 root   root 12 Sep 11 17:53 cron_deny -> ../cron.deny

    So everything looks on track now.

    From 'man' page
           -a, --archive
                  same as -dR --preserve=all

    Copy symlinks with relative path

    One big question here, for me the copying of symbolic link is working fine because we are copying the symlink in the same parent directory and the target file is always accessible by the symlink.

    Let me show you some more examples
    # ll
    total 0
    -rwxrwxrwx 1 oamsys root  0 Sep 11 17:53 a
    -rwxrwxrwx 1 oamsys root  0 Sep 11 17:53 b
    -rw-r--r-- 1 root   root  0 Sep 11 17:53 c
    lrwxrwxrwx 1 root   root 13 Sep 11 17:53
    cron_allow -> ../cron.allow
    lrwxrwxrwx 1 root   root 12 Sep 11 17:53 cron_deny -> ../cron.deny

    Here above the symlink cron_allow is pointing to /tmp/cron.allow, but what I copy these files to a completely different location where relative path"../cron.allow" is inaccessible

    # cp -Prv /tmp/src_files/* /tmp/test/new_dst/
    `/tmp/src_files/a' -> `/tmp/test/new_dst/a'
    `/tmp/src_files/b' -> `/tmp/test/new_dst/b'
    `/tmp/src_files/c' -> `/tmp/test/new_dst/c'
    `/tmp/src_files/cron_allow' -> `/tmp/test/new_dst/cron_allow'
    `/tmp/src_files/cron_deny' -> `/tmp/test/new_dst/cron_deny'

    # ll /tmp/test/new_dst/
    total 0
    -rwxr-xr-x 1 root root  0 Sep 11 18:19 a
    -rwxr-xr-x 1 root root  0 Sep 11 18:19 b
    -rw-r--r-- 1 root root  0 Sep 11 18:19 c
    lrwxrwxrwx 1 root root 13 Sep 11 18:19
    cron_allow -> ../cron.allow
    lrwxrwxrwx 1 root root 12 Sep 11 18:19 cron_deny -> ../cron.deny

    # cd /tmp/test/new_dst/
    # less cron_allow
    cron_allow: No such file or directory

    So ../cron.allow is not accessible. To avoid such scenarios it is always  recommended to use full path of the target file for a symlink.

    Currently I am now aware of a single command which can fix this, if someone knows than please put in your comment which can be used to overcome such scenarios

    As of now I use scripting to fix these issues (a small sample script)
    #!/bin/sh

    src="/tmp/src_files"
    dst="/tmp/test/new_dst"

    #clean destination
    if [ -d $dst ]; then
       echo "Cleaning target directory $dst"
       rm -f $dst/*
    fi

    #copy files
    for i in `ls $src`; do
       path=""
       if [  -L $i ]; then
          path=`readlink -f $i`
          ln -s $path $dst/$i
       else
          cp -vP $i $dst
       fi
    done

    # Listing target directiry files
    ls -al $dst


    Follow the below links for more tutorials

    How to find the path of any command in Linux
    How to configure a Clustered Samba share using ctdb in Red Hat Cluster
    How to delete an iscsi-target from openfiler and Linux
    How to perform a local ssh port forwarding in Linux
    How to use yum locally without internet connection using cache?
    What is umask and how to change the default value permanently?
    Understanding Partition Scheme MBR vs GPT
    How does a successful or failed login process works in Linux
    How to find all the process accessing a file in Linux
    How to exclude multiple directories from du command in Linux
    How to configure autofs in Linux and what are its advantages?
    How to resize software raid partition in Linux
    How to configure Software RAID 1 mirroring in Linux
    How to prevent a command from getting stored in history in Linux

    0 comments:

    Post a Comment