[Script] Fix permissions when copying from a non Linux filesystem

It is not uncommon that one copies files from a non-Linux filesystem to one’s Linux computer. For example, many digital cameras use FAT or NTFS, and it makes sense to format a USB thumb drive as FAT, so it can be read by various other devices (like game consoles, cameras, etc…).

The issue with copying files from a non-Linux filesystem is that permissions will typically be 777 on both files and directories, and this is certainly not what a Linux user wants. Typically, a Linux user will want (non-executable) files to have permissions set to 644 (-rw-r--r--) and directories to 755 (drwxr-xr-x).

It gets tedious to reset permissions manually when copying a bunch of files (e.g. a few hundred images from a digital camera) using

chmod 644 file

especially if the files are in multiple directories. The two proper commands that reset permissions of all files and directories in a given directory are:

find directory -type f -exec chmod 644 {} \;
find directory -type d -exec chmod 755 {} \;

The problem with them is obvious: they are very verbose, which makes them difficult to remember, annoying to type, and prone to making an error (which could be disastrous).

My solution is this simple utility script, which I call reset-permissions:

#!/bin/bash
# A simple bash script that sets permissions of directories to 755
# and files to 644.
# Version 1.1
# by Krešimir, 2020
###############################################################################

# Detect witdth of the terminal, so that folding works nicely
if ! tcols=$(tput cols 2> /dev/null); then 
  tcols=60 # assume width is 60 if tput does not work
fi

print_help() {
  fold -sw $tcols << EOF
A simple bash script that sets permissions of directories to 755 and files to 644.

If used improperly, this script can break stuff. There is no warranty.

Usage:

  reset-permissions file
      Sets permissions of the file to 644.
  
  reset-permissions directory
      Sets permissions of the directory to 755
      without touching its contents.

  reset-permissions -R directory
      Recursively descend into directory setting
      permissions of all files within to 644
      and all directories to 755.

Running as root is disabled by default. Use 'chmod' instead, or modify the script file.
EOF
}

# Check if run as root. Comment out at your own risk. 
if [ "$EUID" -eq 0 ]; then
    >&2 fold -sw $tcols <<< "Error: It is dangerous to run this script as root. Use 'chmod'\
 instead, or edit the script file to remove this check."
    exit 9
fi
# End of check. 

# Recursive mode
if [ "$1" = "-R" ]; then
    if [ "$2" != "" ]; then
        if [ -d "$2" ]; then
            DIRECTORY=$(readlink -f -n "$2")
            echo "Permissions will be set to 755 for"
            echo -e "\033[1m$DIRECTORY\033[0m"
            echo "and for all of its subdirectories, recursively."
            fold -sw $tcols <<< "Persmissions will be set to 644 for all files contained in\
 it and in its subdirectories, recursively."
            read -p "Are you sure [y/N]? " response
            if [[ $response =~ ^(yes|y|Y|Yes)$ ]]; then
                
                find "$DIRECTORY" -type f -exec chmod 644 {} \;
                find "$DIRECTORY" -type d -exec chmod 755 {} \;
                
                exit 0
            fi            
            echo "Cancelled."
            exit 0
        fi 
        >&2 fold -sw $tcols <<< "Error: $2 is not a directory."
        exit 1
    fi
    >&2 echo "Error: Missing path to directory after -R."
    exit 2
fi

# Unknown flag, print help
if [[ $# -eq 0 || "$1" =~ ^- ]]; then 
    print_help;
    exit 0
fi

# Single file or directory mode
for FILE in "$@"; do
    if [ -f "$FILE" ]; then
        chmod 644 "$FILE"
    elif [ -d "$FILE" ]; then
        chmod 755 "$FILE"
    else
        >&2 fold -sw $tcols <<< "Error: $FILE is neither a file nor a directory."
        exit 3
    fi
done

Installation: just copy and paste the code into a file named reset-permissions, save it in a directory listed in your PATH variable, and make it executable with: chmod u+x reset-permissions.

Features:

  • does what it is supposed to do: it sets permissions of files to 644 and directories to 755
  • it can operate on a single file/directory or descend into a directory recursively
  • it has a built-in help (just run the script without an argument)
  • it has a protection against being used as root, because, in normal, everyday usage, massively changing permissions as root is just asking for trouble

I hope at least someone finds it useful. :slight_smile:

6 Likes

I myself run those all the time to fix those little critters :slight_smile:

1 Like

Yeah, that’s what I did until I got fed up with typing that. :smiley:

2 Likes

What do you think of:

chmod -R a-x,a=rX,u+w $DIR

?

(no executable, all read-traverse and user write for all files and directories)

btw, i have never find myself in situation of using them non-recursive… :thinking:

It’s a good command, but it does not do the job. It still keeps all files as executable (it sets everything to 755). When I copy a bunch of images from my camera, they are all 777, both files and directories that contain those files. I don’t want files to be executable, but the directories in which they are have to be.

The issue is that all directories have to be 755 and all files have to be 644. As far as I can tell (and my knowledge is very limited, so I could be wrong), chmod does not discriminate between files and directories.

For example...
~/test🐸 ll
total 20K
drwxrwxrwx  5 kresimir 4.0K Aug 21 16:10 ./
drwx------ 28 kresimir 4.0K Aug 21 16:10 ../
drwxrwxrwx  2 kresimir 4.0K Aug 21 16:10 dir1/
drwxrwxrwx  2 kresimir 4.0K Aug 21 16:10 dir2/
drwxrwxrwx  2 kresimir 4.0K Aug 21 16:10 dir3/
-rwxrwxrwx  1 kresimir    0 Aug 21 16:10 file1*
-rwxrwxrwx  1 kresimir    0 Aug 21 16:10 file2*
-rwxrwxrwx  1 kresimir    0 Aug 21 16:10 file3*
~/test🐸  chmod -R a=rX,u+w .
~/test🐸 ll
total 20K
drwxr-xr-x  5 kresimir 4.0K Aug 21 16:10 ./
drwx------ 28 kresimir 4.0K Aug 21 16:10 ../
drwxr-xr-x  2 kresimir 4.0K Aug 21 16:10 dir1/
drwxr-xr-x  2 kresimir 4.0K Aug 21 16:10 dir2/
drwxr-xr-x  2 kresimir 4.0K Aug 21 16:10 dir3/
-rwxr-xr-x  1 kresimir    0 Aug 21 16:10 file1*
-rwxr-xr-x  1 kresimir    0 Aug 21 16:10 file2*
-rwxr-xr-x  1 kresimir    0 Aug 21 16:10 file3*
~/test🐸  reset-permissions -R .
Permissions will be set to 755 for
/home/kresimir/test
and for all of its subdirectories, recursively.
Persmissions will be set to 644 for all files contained in it and in its subdirectories, recursively.
Are you sure [y/N]? y
~/test🐸 ll
total 20K
drwxr-xr-x  5 kresimir 4.0K Aug 21 16:10 ./
drwx------ 28 kresimir 4.0K Aug 21 16:10 ../
drwxr-xr-x  2 kresimir 4.0K Aug 21 16:10 dir1/
drwxr-xr-x  2 kresimir 4.0K Aug 21 16:10 dir2/
drwxr-xr-x  2 kresimir 4.0K Aug 21 16:10 dir3/
-rw-r--r--  1 kresimir    0 Aug 21 16:10 file1
-rw-r--r--  1 kresimir    0 Aug 21 16:10 file2
-rw-r--r--  1 kresimir    0 Aug 21 16:10 file3
2 Likes

How dare you!? :scream:
It’s so rude to chinese camera manufacturers… :roll_eyes:

Now they won’t see your :frog: pictures…

:blush:

2 Likes

Although I don’t have any need for that, this is really good stuff :slight_smile:

3 Likes