3

I have 2 existing files : abcd and xyz.

$ cat abcd
abcd 
$ cat xyz
xyz

Now, when I try to softlink these files, I get this message :

ln: cannot create xyz: File exists

I do not want to use

ln -sf abcd xyz

command as it will overwrite the content of xyz with that of abcd.

What I want is: both abcd and xyz should display their original content once they are unlinked.

Or in other words, I just want to temporarily link both of these files.

Please suggest if there is any other solution to this other than soft/hard link like using mount, etc.

Edit : I am using Solaris OS which has no manual entry for commands like mount --bind,mount -B, bindfs, fusermount,etc

Also, I tried to use : mount -o bind abcd xyz and it gave following msg : cannot open /etc/vfstab. I checked and found out that /etc/vfstab was having only Root access.

5 Answers5

17

This is not what ln is meant to do. ln creates a hardlink of an existing file, i.e., two (or more) directory entries that point to the same file in the disk. Linked files work in a way that editing one will affect all.

The functionality you want is not something native to Unix (link files so that they appear as one and so that they can be unlinked later). Linux, though, has (some years ago) implemented something called bind mounting, allowing a file or a directory to be mounted on top of another (files on top of files and directories on top of directories).

Proposed solution: If you want a file to appear "to be" another temporarily, then use bind mount (mount -B file1 file2). This will mount file1 on top of file2. After unmounting this later, both files will show again as they originally exist.

# echo A >A

# echo B >B

# mount -B A B

# cat A
A

# cat B
A

# umount B

# cat A
A

# cat B
B

If you expected that the "linked" files show as a concatenation of both, you will have to create a third file and remove it later.

Marcelo
  • 3,561
  • I didn't know this one. Why does it demand sudo priviliges? –  Jun 10 '17 at 15:53
  • 3
    If this allowed regular users to "fake" other users files contents this could create major security issues. (I'm inclined to agree that if the user owns all involved files and directories this should be allowed. Unfortunately it isn't). – Marcelo Jun 10 '17 at 16:01
  • 3
    Allowing regular users to do this could create a denial-of-service vulnerability through a flood of bind mounts. I don't know how well a typical Linux kernel handles millions of mount points. If somebody has a VM snapshot handy I'd be curious to find out. :-) – David Foerster Jun 10 '17 at 17:00
  • @DavidFoster - Yes, this makes sense. Thank you for the input. Anyway, the feature worth it, so there could be a limit/mount-quota/something-similar. (a little off-topic just wondering philosophically...) – Marcelo Jun 10 '17 at 17:02
  • Bind mounting with mount --bind has existed in Linux for over a decade. This probably won't help the asker since the question was tagged Solaris. Also, it requires root. A similar solution is to use bindfs, which works on most unices and doesn't require root (provided that FUSE is allowed). – Gilles 'SO- stop being evil' Jun 10 '17 at 23:30
6

This command:

ln -sf abcd xyz

does not overwrite the content of xyz with that of abcd, as you think. A symbolic link is not a file, so it doesn't contain any content.

If you want to temporarily link xyz to abcd while not loosing it's content, you need to store the content somehow.

  • You can copy the contents to a temporary file. I guess no illustration for this is needed.
  • You can also use the memory, that is store the contents in a variable.
  • You can use a hard link.

Now I'll demonstrate the last one. You have abcd and xyz, as explained in your question.

  1. Hard-link xyz with zyx, so that the contents is kept in zyx letting you manipulate xyz.

    $ ln xyz zyx
    

    At this point xyz and zyx are two hard links of the inode containing the data xyz, as described in your question. You can check this with:

    $ cat zyx
    xyz
    
  2. Now that zyx is in place, you can force the relinking of xyz to abcd.

    $ ln -sf abcd xyz
    

    zyx still keeps the characters xyz. You can check this with:

    $ cat zyx
    xyz
    

    While xyz is now soft-linked to abcd. To check run this:

    $ cat xyz
    abcd
    
  3. Once you want to restore the starting state, relink xyz to the original contents. That is, relink it to the original inode.

    $ ln -f zyx xyz
    

    To check if it works:

    $ cat xyz
    xyz
    

    And now you can unlink the additional hard-link zyx with:

    $ rm zyx
    

    Or keep it for future operations. Either way xyz still contains what it did at the beginning.

    $ rm zyx
    $ cat xyz
    xyz
    
  • @VivekSingh Good. Accept the answer if it's satisfactory. And upvote it if you like me. –  Jun 10 '17 at 15:42
  • @VivekSingh - this is not necessary to store the contents temporarily as proposed above. The expected behavior can be obtained using bind mount (if you are using Linux). Please check my answer. – Marcelo Jun 10 '17 at 15:44
  • @Marcelo, I am using Putty console in a Windows 7 configuration system. Unfortunately, I am getting this error, when I am using "mount --bind abcd xyz" or "mount -B abcd xyz" : mount -B abcd xyz mount: illegal option -- B. Can you please elaborate or provide exact command for the same. – Raid_Master Jun 10 '17 at 16:03
  • @VivekSingh - Some questions: Is the target system a Linux? ; Are you entering the command as root? (please post the output of uname -a and whoami) – Marcelo Jun 10 '17 at 16:08
  • @Marcelo Yes, I am using a Windows machine to access Solaris OS(target system) using Putty console. I guess that answers your question. Also, I am not the root user. – Raid_Master Jun 10 '17 at 16:09
  • Ok, so this is what it seems to be the issue. I'm not sure Solaris supports bind mounting. AFAIK, this is a Linux feature. – Marcelo Jun 10 '17 at 16:11
  • @VivekSingh You may need to use the long option name, ie --bind. See man mount on the OS you work on, ie on Solaris. –  Jun 10 '17 at 16:13
  • @Marcelo ,Yes, I had gone through manual page of mount, but it was not having any option of "bind". Please let me know if there is any other way except using softlink. – Raid_Master Jun 10 '17 at 16:16
  • @VivekSingh - In case Solaris doesn't support bind mounting nativelly, please research about bindfs (part of FUSE, which I'm almost sure Solaris does support). – Marcelo Jun 10 '17 at 16:16
  • @VivekSingh See this for more details about bind mounting: https://unix.stackexchange.com/questions/198590/what-is-a-bind-mount –  Jun 10 '17 at 16:17
  • @tomas Thanks but I guess none of these options, mount --bind, bindfs,mount_nullfs are working on my OS. I got this o/p on running following command : $ mount -o bind abcd xyz mount: Cannot open /etc/vfstab – Raid_Master Jun 10 '17 at 16:30
  • @VivekSingh So it may be the lack of priviliges, right? –  Jun 10 '17 at 16:33
  • @tomas, Yes /etc/vfstab has root access only. – Raid_Master Jun 10 '17 at 16:35
  • 1
    @VivekSingh - I guess that since you don't own root privileges you'll have to work with scripts using cp, ln, etc, to backup the original contents, linking the files and then restoring them back. mount is a command supposed to be run as root. You could talk to your system administrator so that he could allow you to use a very specific mount line and parameters with sudo, but I guess this may be more difficult to convince than practical (Still, I'm not even sure Solaris supports bind mounting, so it may worth nothing in the end). – Marcelo Jun 10 '17 at 16:36
  • @Marcelo, Yes, that's the problem but anyways thanks a lot to both of you guys, cleared many of my doubts!!! – Raid_Master Jun 10 '17 at 16:41
  • Rather than writing up scripts to do this manually, if the files and directory aren't too big, you might be able to create agit folder. Create a branch, make the changes, commit. When you're done, just switch to the previous branch. You can switch back and forth between branches to switch between the two setups. – Lie Ryan Jun 11 '17 at 02:30
  • @tomas Could you please help me with another question of mine : https://unix.stackexchange.com/questions/372009/mailx-replace-from-address-with-name?noredirect=1#comment662356_372009 – Raid_Master Jun 25 '17 at 10:49
  • @Raid_Master I don't know mailx, sorry. –  Jun 25 '17 at 15:15
2

On Linux, as an alternative to bind mount, you can also use overlay mount to link one file with another temporarily. The advantage of an overlay is that you can change overlay without needing root privilege, unlike bind mount which will require root privilege to shadow and unshadow files.

Demonstration:

Create a test partition with some test files (note that you need root to create a mountpoint that isn't listed in /etc/fstab, but you won't need root for any of the other steps):

$ mkdir one two work mpnt
$ sudo mount -t overlay none -olowerdir=one,upperdir=two,workdir=work mpnt
$ echo "hello world" > one/abcd
$ echo "another" > one/xyz

We created the test files in folder one above, these files are also visible in the mount point mpnt.

$ ls -lh mpnt
total 8.0K
-rw-r--r-- 1 lieryan lieryan 12 Jun 11 03:33 abcd
-rw-r--r-- 1 lieryan lieryan  8 Jun 11 03:33 xyz

Let's modify the files in mpnt:

$ ln -sf abcd mpnt/xyz 

We modified mpnt/xyz above to be a symlink, but overlayfs redirects all writes to mpnt to the upperdir, so the symlink we created are actually written to two, we can see the symlink in folder two as well as mpnt:

$ ls -lh two
total 0
lrwxrwxrwx 1 lieryan lieryan 4 Jun 11 03:34 xyz -> abcd
$ ls -lh mpnt
total 4.0K
-rw-r--r-- 1 lieryan lieryan 12 Jun 11 03:33 abcd
lrwxrwxrwx 1 lieryan lieryan  4 Jun 11 03:34 xyz -> abcd

The symlink works as expected when used from mpnt:

$ cat mpnt/xyz
hello world

If we delete something from mpnt, overlayfs will also redirect the write to upperdir:

$ rm mpnt/xyz

In this case though, overlayfs actually creates a special character device file (notice the c attribute), called a whiteout file. When overlayfs sees this type of file in the upperdir, overlayfs pretends that the file don't exist in mpnt:

$ ls -lh mpnt 
total 4.0K
-rw-r--r-- 1 lieryan lieryan 12 Jun 11 03:33 abcd
$ ls -lh two
total 4.0K
c--------- 1 lieryan lieryan 12 Jun 11 03:33 xyz

We can remove the special character file from the upperdir to restore xyz from lowerdir:

$ rm two/xyz  # delete the "whiteout" file
rm: remove write-protected character special file 'two/xyz'? y

Now xyz is visible again in mpnt, and has the same file content as one/xyz.

$ ls -lh mpnt 
total 8.0K
-rw-r--r-- 1 lieryan lieryan 12 Jun 11 03:33 abcd
-rw-r--r-- 1 lieryan lieryan  8 Jun 11 03:33 xyz
$ cat mpnt/xyz
another
Lie Ryan
  • 1,228
  • Why am I getting this: overlayfs: filesystem on 'two' not supported as upperdir? –  Jun 10 '17 at 18:23
  • @tomas: From man mount: The upper filesystem will normally be writable and if it is it must support the creation of trusted.* extended attributes, and must provide a valid d_type in readdir responses, so NFS is not suitable. What filesystem are you using as the upperdir? – Lie Ryan Jun 10 '17 at 18:38
  • This is new to me. My only disk is all ext4. If this is a good answer... –  Jun 10 '17 at 18:44
  • @tomas: what directory are you using for your test? If you are doing it on /tmp, that is mounted as tmpfs on some systems. tmpfs doesn't support extended attributes either, so it can't be used as upperdir. Check your mount table by running mount command. – Lie Ryan Jun 10 '17 at 18:52
  • type ecryptfs (rw,nosuid,nodev,relatime,ecryptfs_fnek_sig=1c2cadf7870dc437,ecryptfs_sig=89832faac44a6443,ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_unlink_sigs) –  Jun 10 '17 at 19:14
  • @tomas: you might want to try creating the upper directories outside of ecryptfs. I think currently ecryptfs can't be used for overlayfs' upper directory for some reason. – Lie Ryan Jun 10 '17 at 19:38
  • On the unencrypted it's ok. But I don't know what's going on in your command. Could you comment them, please? –  Jun 10 '17 at 19:51
  • @tomas: I've added some comments to the demonstration. HTH. – Lie Ryan Jun 11 '17 at 02:18
  • If this doesn't require root privileges as stated, why do you use sudo in the mount command in your answer? sudo mount -t overlay ... – Marcelo Jun 12 '17 at 02:41
  • @Marcelo: as I've stated above, this does not require root privilege to change the overlay files, the initial setup (i.e. setting up the mount in fstab), does still require root. Once you've got the mount setup in fstab, set up as user-mount, regular user can mount/unmount the overlay without requiring root. – Lie Ryan Jun 12 '17 at 03:16
  • Thanks. What is the mysterious work directory for? –  Jun 14 '17 at 16:11
2

both abcd and xyz should display their original content once they are unlinked

Then what you want is not a link. If two files are linked, then they have the same content. More precisely, two directory entries are linked if they point to the same file. Unlinking a file doesn't leave two files: unlinking a directory entry means removing this directory entry (the system call to remove a file is even called unlink).

There's no general feature to shadow a file with another file. You can use the bindfs filesystem to shadow a directory with another directory. To shadow the directory xyz with the directory abcd, run

bindfs -n -o nonempty xyz abcd

After this, the former contents of abcd are hidden, and accessing abcd in any way accesses xyz. Bindfs is a FUSE filesystem that creates a bind mount. To undo the shadowing and see the original content of abcd, unmount the filesystem:

fusermount -u abcd

Note that mounting a filesystem doesn't change what's stored on the disk. The shadowing is limited to your machine, and only lasts at most until the next reboot. If you want the shadowing to last, you need to add this mounting to the list of things to mount at boot time (/etc/fstab). But if you want the shadowing to last, then mounting is probably not the right approach: instead just move the file and create a symbolic link

mv abcd abcd.orig
ln -s xyz abcd

and to go back, remove the symlink and move back the original file

rm abcd
mv abcd.orig abcd
1

As far as i understand you, you want to link two files but you don't want to loose the data in both files. You tagged your post with Solaris so i assume you use this operating system. So refering to functionalities of other operating systems doesn't seem to be useful. This answer assumes that you are using one or more zfs datasets for the data.

You could simply make a zfs snapshot of your filesystem where you want to place the link instead of the file, make the ln -sf abcd xyz, do whatever you want with it and then roll back

root@solaris:/rpool# zfs create rpool/filesystem1
root@solaris:/rpool# mkfile 1k /rpool/filesystem1/file1
root@solaris:/rpool# mkfile 1k /rpool/filesystem1/file2
root@solaris:/rpool# ls -l /rpool/filesystem1
total 2
-rw-------   1 root     root        1024 Jun  8 20:33 file1 .  
-rw-------   1 root     root        1024 Jun  8 20:33 file2
root@solaris:/rpool# zfs snapshot rpool/filesystem1@withtwofiles
root@solaris:/rpool# rm /rpool/filesystem1/file2
root@solaris:/rpool# ln -s /rpool/filesystem1/file1 /rpool/filesystem1/file1
root@solaris:/rpool# ls -l /rpool/filesystem1
total 4
-rw-------   1 root     root        1024 Jun  8 20:33 file1
lrwxrwxrwx   1 root     root          24 Jun  8 20:33 file2 -> /rpool/filesystem1/file1
root@solaris:/rpool# zfs rollback rpool/filesystem1@withtwofiles
root@solaris:/rpool# ls -l /rpool/filesystem1
total 6
-rw-------   1 root     root        1024 Jun  8 20:33 file1
-rw-------   1 root     root        1024 Jun  8 20:33 file2
root@solaris:/rpool# 

Instead of unlinking you just rollback the filesystem with the link

c0t0d0s0
  • 156