Last active
June 29, 2018 18:10
-
-
Save bwmorales/40defa96fdc3331c379f48e0b8acd893 to your computer and use it in GitHub Desktop.
Swap out those pesty SMB illegals with benign characters!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# USAGE: ./rmSMB_Illegals.sh path | |
# Find searches through each file on a filesystem and passes the filenames to a | |
# function that tests for the presence of illegal characters and remediates. | |
# Bad characters are either removed or replaced with a ``-''. | |
# This has been tested on APFS on macOS 10.13.5. It'd be pretty safe to run this | |
# on a mounted volume, but it'd be nicer to test on Synology Linux and have it | |
# run directly. | |
LOG_FILE="$(pwd)/$0.log" | |
REGEX='^[][a-zA-Z0-9_ .-]*$' | |
TRAILING_SPACE=' $' | |
TRAILING_PERIOD='\.$' | |
writeToLog(){ | |
local LOG_DIRNAME | |
LOG_DIRNAME=$(dirname "${LOG_FILE}") | |
if [[ ! -d "${LOG_DIRNAME}" ]]; then | |
mkdir -p "${LOG_DIRNAME}" | |
touch "${LOG_FILE}" | |
printf "%s Log and log parent directory created.\n" \ | |
"$(date "+%Y/%m/%d %H:%M:%S")" >> "${LOG_FILE}" | |
fi | |
if [[ ! -e "${LOG_FILE}" ]]; then | |
touch "$LOG_FILE" | |
printf "%s Log created.\n" "$(/bin/date "+%Y/%m/%d %H:%M:%S")" \ | |
>> "${LOG_FILE}" | |
fi | |
LOGGED_MESSAGE="$*" | |
printf "%s $LOGGED_MESSAGE\n" "$(/bin/date "+%Y/%m/%d %H:%M:%S")" \ | |
>> "$LOG_FILE" | |
} | |
testForIllegalCharacters(){ | |
STRING="$1" | |
# Check that file name string only contains white-listed characters. | |
if [[ $STRING =~ $REGEX ]]; then | |
# Check that white-listed characters are not in bad places | |
if [[ ! $STRING =~ $TRAILING_SPACE ]]; then | |
: # No trailing space... moving along | |
else | |
return 1 # Trailing space found | |
fi | |
if [[ ! $STRING =~ $TRAILING_PERIOD ]]; then | |
: # Not trailing period found... moving along | |
else | |
return 1 # Trailing period found | |
fi | |
return 0 # YAY! This file is clean! | |
else | |
return 1 # Non-whitelisted character found. We'll take some action. | |
fi | |
} | |
sanitizeFilename(){ | |
STRING="$1" | |
STRING_REPLACEMENT="$STRING" # Set variable outside of for loop | |
writeToLog "WORKING: \"$TARGET_FILE\"" | |
# Let's iterate through this string and replace anything not on the whitelist | |
for (( INDEX = 0; INDEX < ${#STRING}; INDEX++ )); do | |
CHAR=${STRING:$INDEX:1} | |
if [[ ! $CHAR =~ $REGEX ]]; then # We found one! | |
# writeToLog "\t$STRING: '$CHAR' at index $INDEX" | |
STRING_REPLACEMENT=$(printf $STRING_REPLACEMENT \ | |
| sed "s,.,-,$(expr $INDEX + 1)") | |
fi | |
done | |
if [[ $STRING_REPLACEMENT =~ $TRAILING_SPACE ]]; then # return without trailing space | |
# writeToLog "\t$STRING_REPLACEMENT: ' ' at index $(expr ${#STRING_REPLACEMENT} - 1)" | |
printf "$STRING_REPLACEMENT" | sed "s, $,," | |
return 0 | |
elif [[ $STRING_REPLACEMENT =~ $TRAILING_PERIOD ]]; then # return without trailing period | |
# writeToLog "\t$STRING_REPLACEMENT: '.' at index $(expr ${#STRING_REPLACEMENT} - 1)" | |
printf "$STRING_REPLACEMENT" | sed "s,.$,," | |
return 0 | |
else # We're good to go. | |
printf "$STRING_REPLACEMENT" | |
return 0 | |
fi | |
} | |
if [[ $EUID -ne 0 ]]; then | |
writeToLog "This must be run as root." | |
exit 1 | |
fi | |
OIFS=$IFS | |
IFS=$'\n' | |
# find will crawl the filesystem performing some tests on each filename | |
for TARGET_FILE in $(find "$1" -name "*" | grep -vE "^\.*$"); do | |
TARGET_BASE="$(basename $TARGET_FILE)" | |
if [[ $TARGET_BASE == ".DS_Store" ]]; then | |
rm "$TARGET_FILE" | |
fi | |
testForIllegalCharacters "$TARGET_BASE" # Run initial test. Clean returns 0. | |
if [[ "$?" -eq "1" ]]; then # We found a dirty filename | |
# Find a decent, sanitized name for the file. | |
SANITIZED_NAME="$(sanitizeFilename "$TARGET_BASE")" | |
# Let's make sure we don't overwrite anything. | |
if [[ -e "$(dirname $TARGET_FILE)/$SANITIZED_NAME" ]]; then | |
# The sanitized name would overwrite something, so we'll add the date | |
# to the beginning of the filename. | |
mv "$TARGET_FILE" \ | |
"$(dirname $TARGET_FILE)/$(date +%Y-%m-%d)_$SANITIZED_NAME" | |
writeToLog "\t$(dirname $TARGET_FILE)/$SANITIZED_NAME already exists!" | |
writeToLog "CHANGE: $TARGET_FILE to $(dirname $TARGET_FILE)/$(date +%Y-%m-%d)_$SANITIZED_NAME" | |
else | |
# No conflict. Going to go ahead and overwrite. | |
mv "$TARGET_FILE" "$(dirname $TARGET_FILE)/$SANITIZED_NAME" | |
writeToLog "CHANGE: $TARGET_FILE to $(dirname $TARGET_FILE)/$SANITIZED_NAME" | |
fi | |
fi | |
done | |
IFS=$OIFS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment