Sunday, January 18, 2015

rooting - How can I make a symlink (or equivalent) inside /storage/emulated/0?


So, I have rooted my phone (GT-i9505 with android 5.0.1) and I would like to move my WhatsApp folder to my external SD card to save 3GB on internal storage. This is what I tried so far.


EDIT: solution found


So, after all the option #2 seemed to be the right one, but it needed some tweaks to make it work. As suggested by Irfan Latif , the problem was that the mount point has to be created in a global mount namespace, otherwise other apps will not see it, so the commands to use are:


su -mm
mount -o bind /data/sdext2/AppData/WhatsAppMedia /sdcard/WhatsApp/Media

But that may not be enough! It still didn't work until I made sure that the namespace of root was global. To do that I don't know any universal way, but what worked for me was going in the SuperSU app settings and uncheck the option mount namespace separation.



That really depends on the SU app that you have installed.


Option 1: symlink


The first thing that I thought was to make a symlink, so that was the command that I used:


ln -s "/data/sdext2/AppData/WhatsAppMedia" "/sdcard/WhatsApp/Media"

I had already created a second partition on my external SD card (ext4) that is mounted in /data/sdext2


However that returns operation not permitted when using the terminal emulator (yes I did su) and an error with any root file manager app that I tried.


After some research I figured out that for some reason, although /storage/emulator/0 is in an ext partition, it is treated in a differente way so that it doesn't support symlink inside (correct me if I'm wrong).


So, onto the next thing


Option 2: mount



According to this question, the following command should mount the folder on external SD card in another folder in the internal SD card, without the need for a symlink


mount -o bind "/data/sdext2/AppData/WhatsAppMedia" "/sdcard/WhatsApp/Media"

However, while running the command doesn't return any error the folder in /sdcard/WhatsApp/Media is still empty, so I don't really know how to handle this.


Option 3: symlink in /data/media/


I followed the instructions on this post and made the symlink in /data/media/0 instead of storage, so using this command:


ln -s "/data/sdext2/AppData/WhatsAppMedia" "/data/media/0/WhatsApp/Media"

This time the link is created! However ...


Although an ls in /data/media/0/WhatsApp/Media revealed that the link was successful, cd /sdcard/WhatsApp/Media returns a very irritating no such file or directory and that is confirmed by the file explorer that shows an empty folder with a blank file icon.



My thoughts


First of all, I now discovered that I really hate android. Now, stated this, here's what I think might help doing:



  • moving my sdcard files somewhere else: if the rest of the root filesystem supports symlink (which it seems like it does), I might even move the folder /storage/emulated/0 somewhere else and make a new link to it, but I don't know if that would solve the problem


That's it for now, I will update with more options when I think about them...



Answer



ANDROID STORAGE:


On Android 5:


/sdcard >S> /storage/emulated/legacy >S> /mnt/shell/emulated/0

/mnt/shell/emulated >E> /data/media

On Android 6+:


# USER-ID of current user in case of multiple users, normally "0"

# for apps
# VIEW is one of "read" or "write" and /storage to VIEW bind mount is inside a separate mount namespace for every app
/sdcard >S> /storage/self/primary
/storage/self >B> /mnt/user/USER-ID
/mnt/user/USER-ID/primary >S> /storage/emulated/USER-ID

/storage/emulated >B> /mnt/runtime/VIEW/emulated
/mnt/runtime/VIEW/emulated >E> /data/media

# for services/daemons/processes in root namespace
/sdcard >S> /storage/self/primary
/storage >B> /mnt/runtime/default
/mnt/runtime/default/self/primary >S> mnt/user/0/primary
/mnt/user/0/primary >S> /storage/emulated/0
/storage/emulated >B> /mnt/runtime/default/emulated
/mnt/runtime/default/emulated >E> /data/media


>S> for symlink, >E> for emulated and >B> for bind mount


In short, /sdcard points to /data/media/0 through FUSE or sdcardfs emulation. This is to restrict unauthorized access of apps/processes to private media on SD card. Read Android's Storage Journey.


SYMLINKS:


Now /sdcard is not a real but emulated storage which represents a FAT/vFAT/FAT32 filesystem (for backward compatibility and permission management) which doesn't support symlinks (and other things including *NIX permissions and ioctls like FS_IOC_FIEMAP). So the Option 1 and 3 of yours won't work whether you create symlink directly on emulated storage or try to emulate the symlink already created on ext4.


BIND MOUNT:


This is the commonly used alternate of symlink for FAT family of filesystems. What you have tried in Option 2 should work. This is what apps like Apps2SD do. But there is again a constraint: mount namespace. You need to bind mount in global/root mount namespace so that the mount is visible to all apps:


su -mm -c 'mount -o bind "/data/sdext2/AppData/WhatsApp Media" "/sdcard/WhatsApp/Media"'

On Android 6+ this needs to be bind mounted on each VIEW (default, read, write) separately for all apps to work.



You can make it permanent by setting Mount Namespace Mode to Global in Magisk or by disabling Mount Namespace Separation in SuperSU. For details see this answer.




RELATED:



No comments:

Post a Comment

samsung galaxy s 2 - Cannot restore Kies backup after firmware upgrade

I backed up my Samsung Galaxy S2 on Kies before updating to Ice Cream Sandwich. After the upgrade I tried to restore, but the restore fails ...