Automatically delete empty QubesIncoming subdirectories

Yes, that manpage is wrong (in a characteristically GNU way)

alt.:

find "${path}" -depth -type d -empty -delete
2 Likes

Super elegant! :+1:

I picked your command line for the first post because it’s just better in all ways :slight_smile:

1 Like

You need to keep -mindepth 1 to not remove /home/user/QubesIncoming and you either need to specify $path variable or specify path to directory:

test ! -d /home/user/QubesIncoming || find /home/user/QubesIncoming -mindepth 1 -type d -empty -delete

or

qubes_incoming_path='/home/user/QubesIncoming' && test ! -d "$qubes_incoming_path" || find "$qubes_incoming_path" -mindepth 1 -type d -empty -delete

The command above does not delete QubesIncoming even if it’s empty

It does for me:

user@testqube:~$ mkdir /home/user/QubesIncoming
user@testqube:~$ find /home/user/QubesIncoming -depth -type d -empty -delete
user@testqube:~$ ls -la /home/user/QubesIncoming
ls: cannot access '/home/user/QubesIncoming': No such file or directory

What’s the need to keep ~/QubesIncoming? (As far as I can tell, it gets created if needed whenever you copy files to a qube.)

2 Likes

my bad, I have an hidden file to prevent this directory to be backuped! This prevented deletion.

I have this directory in Nautilus as a bookmark, Nautilus isn’t happy when the directory disappear

1 Like

In those few cases where this is an issue (most of my VMs are disposables), I just go into QubesIncoming and issue rmdir *, ignoring the “not empty” error messages. I could certainly automate this in .bashrc.

If I wanted to delete QubesIncoming itself (provided it’s empty) of course I could add a line to do that as well.

Solene of course could skip that last step.

For DRY, re-use the last argument to the previous command.
For not removing the folder itself, it seems that subfolders can be used as targets for find .

test ! -d /home/user/QubesIncoming ||
    find "${_}/"* -depth -type d -empty -delete

Of course, many options.

I don’t know why, but i typed this now, from my mobile :crazy_face: … so untested (and perhaps mistyping), should be compatible with quite a few shells that have: test, printf, find, read.

#!/usr/bin/env sh

{
    usage() {
        >&2 printf 'usage:\npath=~/QubesIncoming/ %s' "$0"
    }

# ask input if unset & stdin (0) is connected to a terminal
    test -t 0 &&
        path="${path:-$(
            >&2 printf 'What path? '
            read p
            printf '%s' "$p"
        )}"

# exit script if $path is unset,
# unless there is a $default_path to set it to
    : path="${path:-${default_path?-no $path and no $default_path to set $path to}}"

    test -d "${path?}" &&
        {
            findArgs='-type d -empty'
            test ! -t 0 ||
                {
# stdin tty-connected, ask confirmation
                    >&2 {
                         printf 'To be deleted:\n'
                         printf '%s' $(
                             find "${path?}/"* $findArgs -depth -print
                         )
                         printf 'Delete paths? [y/N] '
                    }
                    read confirmed
                    test -z "${confirmed%y}" -o -z "${confirmed%Y}"
            }
# $? is 0 when stdin is not a tty
# or, when $confirmed is y or Y
        test $? -eq 0 &&
            find "${path?}/"* $findArgs -delete
    }
}
$ test ! -d /home/user/QubesIncoming ||
    find "${_}/*" -type d -empty -delete
find: ‘/home/user/QubesIncoming/*’: No such file or directory

You can also remove -depth option sine according to the man it’s automatically turns on by -delete option:

The use of the -delete action on the command line automatically turns on the -depth option.

ah, yes, that’s right.

the asterisk needs to move outside.

Also, assuming there are no spaces in ~ , the quotes can be removed.

To delete the existing QubesIncoming as well:

test ! -e ~/QubesIncoming ||
    find $_ -type d -empty -delete

To keep/guarantee QubesIncoming is there, without empty subdirectories:

mkdir -p ~/QubesIncoming &&
    find ${_}/* -type d -empty -delete
2 Likes

I use a simpler approach.
My ~/QubesIncoming is on a RAM drive. In /rw/config/rc.local I have:

mount -o remount,size=2G /tmp
mkdir -p /tmp/download -m 700
chown -R user:user /tmp/download
ln -sfT /tmp/download /home/user/QubesIncoming

So, everything deletes itself automatically on qube shutdown + I also have a convenient directory for storing other volatile stuff.

1 Like

Mounting “something else” to ~/QubesIncoming can help out with other situations too.

If I want to move a big file to my NAS (mounted on nas-qube) from some other-qube that cannot access the NAS, normally one would do a qvm-copy to nas-qube, and then copy from nas-qube:~/QubesIncoming/other-qube onto the NAS.

That involves writing redundantly to the SSD that Qubes is installed on; if you’re worried about wearing out your SSD, this could be a consideration.

However if you mount the NAS storage to QubesIncoming, then the copy goes directly to the NAS. (I was originally going to mount a ramdisk as you did, but then realized for what I was trying to do, this is simpler. Besides there might not be enough RAM for it to work for large files.)

This, by the way also applies to other kinds of storage (CD/DVD/Bluray burner, a thumb drive) if you want to have a qube dedicated to mounting that storage.

That involves writing redundantly to the SSD that Qubes is installed on; if you’re worried about wearing out your SSD, this could be a consideration.

This is a real concern. Unfortunately, due to the way Qubes OS works, moving a file from qube-A to qube-B (with persistence) also means copying, then deleting of the original (which is not true deletion on SSD technology). On a local file system, that would not result in SSD wear but cross-qube… I wonder if there is a solution to this technical inefficiency as it results in actual hardware amortization (+ overhead, as IIUC, qube-A and qube-B use separate encryption keys). Do you know anything about it? Any existing issues/discussions?

As far as I know mounting something else (ramdisk, like you mentioned in connection with deleting the directories, or some other storage) to QubesIncoming (or QubesIncoming/source-qube-name solves the problem…the copy then is directly TO that device rather than to storage in the destination qube which is really on the host SSD.

Returning to the topic of deleting empty QubesIncoming/* directories, one option is to use disposables (either named ones, which most of mine are, or disp1234); of course the directories go away when the qube shuts down. Most of my qubes are disposables, though QubesIncoming/* directories do accumulate on the rest.

Hi, I love it! Is there a way to apply it to all the qubes via dom0 command?

You can write a custom salt state that will apply to all qubes, then run salt on all qubes.

If you do not have many templates, a slightly cleaner solution would be to implement this cleanup as a systemd service and enable it at boot in the template, all qubes based on this template will run the cleanup. (this could also be automated through salt).

I never played around with salt so far - I guess I will have to add one by one…