How to write zeros in one pass to free space on FAT32 drive? [duplicate]

This really sounds like an XY problem.

sfill, or shred which is more generally available (part of coreutils) overwrite the contents of existing files (if everything goes well, e.g. the file system overwrites in place, and see other gotchas mentioned in their manuals).

If you wanted this, you could do so with shred -n 1 --random-source /dev/zero; or a tiny shell script that gets the file's size and then does a dd conv=notrunc if=/dev/zero of=the_file_to_be_zeroed_out bs=... count=....

But as far as I understand, this is not what you need. (Unless can make sure that you only ever delete a file after zeroing it out, which sounds truly cumbersome and hardly feasible.) What you need is to zero the space that's currently unused by any file, so that instead of the remains of previously deleted files (which would still need to be compressed) the unused area is as compressible as possible, that is, preferably full of zeros.

You should create a new file that's as large as possible, and is full of zeros. Go with something like dd if=/dev/zero of=tmpfile bs=1M, wait until it exits with the error message "No space left on device" and then delete this file. Your image is ready to be compressed – but don't forget to umount it first!


These instructions are outdated, if you want to reliably zero out the data on your FAT32 drive, use the script. (if you can, feel free to edit and update these instructions)

  1. Always make sure you are updated, and install the secure-delete tool

     sudo apt-get update
     sudo apt-get install secure-delete
    
  2. Mount the FAT32 drive

    ###On Linux

     fdisk -l
     sudo mount -t vfat /dev/sdb1 /PATH/TO/MOUNTED/DRIVE
    

    (where sdb1 is your sdxx volume name)

    ###With WSL

     sudo mount -t drvfs F: /PATH/TO/MOUNTED/DRIVE
    

    (where F would be your drive letter)

    Also there may be a bug where the mount doesn't work if trying to mount to existing folder name in /mnt, in which case if you tried to mount, you need to unmount by sudo umount /mnt/f, restart WSL, delete the folder (sudo rmdir /mnt/f), recreate the folder (sudo mkdir /mnt/f), and finally mount again

    (where f would be your drive letter as lowercase)

  3. Create a temporary folder at the root of the drive and move into it

     mkdir /PATH/TO/MOUNTED/DRIVE/tmp
     cd /PATH/TO/MOUNTED/DRIVE/tmp
    
  4. Find free space then create dummy files

     df -h /PATH/TO/MOUNTED/DRIVE
     for i in $(seq START ( END-1 )); \
       do fallocate -l 1G emptyfile${i} && echo Created ${i} out of ( END-1 ); \
     done
    

    where START is 1 GB and END is the free space shown by df -h -> how many gigabytes to write, e.g.

     for i in $(seq 1 ( 10-1 )); do \
       fallocate -l 1G ${i} && echo Created ${i} out of ( 10-1 ); \
     done
    

    This would make nine 1 GB "emptyfile"s.

  5. Find last bit of free space to write to

     df  /PATH/TO/MOUNTED/DRIVE
     fallocate -l ( REST-1 ) emptyfileEND
    

    (where REST is the free space shown in df -hB)

  6. Go back to the root of the drive and now delete the tmp folder with srm (a secure-delete tool)

     cd /PATH/TO/MOUNTED/DRIVE
     srm -llrvz /PATH/TO/MOUNTED/DRIVE/tmp
    

I created a script, and it works without using fallocate in favor of truncate, and should now work well. Instead of allocating 1 GB, I instead made the script allocate a byte shy of 4 GiB so I'll fill up the drive better. (the last truncate will make a file less than 4 GiB)

###Bash Script (compatible with WSL) (download)