Mike Slinn
Mike Slinn

Linking Directories on NTFS and Ext4 Volumes

Published 2022-02-07.
Time to read: 2 minutes.

This site is categorized under Bash, Ubuntu, WSL, WSL2.

Sometimes I need to insert some code into a program that depends on the type of format that a drive volume has. For example, today I need to either make a Windows junction to connect two directories on NTFS volumes. On the other hand, if one or both directories were on other types of volumes, I would have to connect the directories using a Linux symlink.

All of the bash scripts shown in this blog post are meant to run in a Bash shell running on WSL or WSL2.

Use Windows Junctions When Possible

When working on WSL, Windows junctions are more desirable than Linux hard links and symlinks because junctions are visible in Windows and also in WSL. Unlike Linux hard links, which only work within a single volume, Windows junctions can span two volumes. Linux symlinks are only visible from WSL; a symlinked directory only appears as a useless file when viewed from Windows.

Both directories need to be on NTFS volumes to make a Windows junction between them. Junctions are permitted within a single NTFS volume, or between two NTFS volumes. Linux symlinks can be used on all volume types, but only work properly when viewed from Linux.

Windows junctions are shown with a small arrow icon in Windows File Manager. In the image above, the curriculum directory is a junction.

Determining a Volume Type

I wrote the volumeType bash function to obtain the type of the volume that contains a file or directory. Linux ext4 volumes have partition type ext4. NTFS volumes have partition type 9p.

Shell
function volumeType {
  # Usually returns volume types ext4 or 9p (for NTFS)
  df -Th "$1" | tail -n 1 | awk '{print $2}'
}

Here are examples of using volumeType:

Shell
$ volumeType /mnt/c  # Under WSL/WSL2 this is usually NTFS
9p 

$ volumeType /       # For Ubuntu this defaults to ext4
ext4 

All of the remaining scripts on this page either return a value (indicating true), or they do not return anything (indicating false).

Two more bash functions test if a file or directory is part of an NTFS or ext4 volume:

Shell
function isNTFS {
  if [ "$( volumeType "$1" )" == 9p ]; then echo yes; fi
}

function isExt4 {
  if [ "$( volumeType "$1" )" == ext4 ]; then echo yes; fi
}

Here are examples of using isNTFS and isExt4:

Shell
$ isNTFS /mnt/c
yes 

$ isExt4 /mnt/c

$ isNTFS /

$ isExt4 /
yes 

Windows Junctions

The bothOnNTFS bash function indicates if both of the paths passed to it are on NTFS volumes.

Shell
function bothOnNTFS {
  if [ "$( isNTFS "$1" )" ] && [ "$( isNTFS "$2" )" ]; then echo yes; fi
}

Let's try out bothOnNTFS.

$ bothOnNTFS /mnt/c /mnt/f
yes 

$ bothOnNTFS /mnt/c /

bothOnNTFS lets us decide how to connect two directories. If they are both on NTFS volumes, we can connect them using a Windows junction; otherwise we'll need to symlink them.

Connecting Via a Windows Junction or Linux Symlink

We could either make a Windows junction using the mklink command, or we could make a Linux symlink using the ln -s command. Notice how the order of parameters between mklink is the reverse of the order of the Linux ln command.

Shell
if [ $( bothOnNTFS "$cadenzaCurriculum" . ) ]; then
    WINDOWS_PATH="$( wslpath -w "$cadenzaCurriculum/site_$TITLE" )"
    echo "Making Windows junction from $cadenzaCurriculum/site_$TITLE to curriculum/"
    cmd.exe /C mklink /j curriculum "$WINDOWS_PATH"
else
  echo "Symlinking $cadenzaCurriculum/site_$TITLE to curriculum/"
  ln -s "$cadenzaCurriculum/site_$TITLE" curriculum
fi
When the above code ran it produced:
Making Windows junction from /mnt/f/work/cadenzaHome/cadenzaCurriculum/site_ScalaCourses.com to curriculum/
Junction created for curriculum <<===>> F:\work\cadenzaHome\cadenzaCurriculum\site_ScalaCourses.com