-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathramify.sh
More file actions
executable file
·131 lines (106 loc) · 3.32 KB
/
ramify.sh
File metadata and controls
executable file
·131 lines (106 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/bin/bash
set -x
function usage() {
echo "Usage: $0 [-s size] <target_directory>"
echo " -s size: Optional, define the RAM disk size in kilobytes."
echo " <target_directory>: The directory to be ramified."
}
# Parsing optional arguments
USER_SIZE=0
while getopts ":s:" OPTIONS; do
case $OPTIONS in
s)
echo "User size: $OPTARG"
USER_SIZE=$OPTARG
;;
*)
echo "Invalid option: -$OPTARG" >&2
usage
exit 2
;;
esac
done
# Shift the optional arguments
shift $((OPTIND - 1))
# Check if required argument is provided
if [ $# -eq 0 ]; then
echo "Error: No target directory provided." >&2
usage
exit 1
fi
# Setting variables for target and shadow paths, and owner/group
TARGET_PATH="${1}"
SHADOW_PATH=".${1}.ramify"
if [[ "$OSTYPE" == "darwin"* ]]; then
USER=$(stat -f '%Su' "${TARGET_PATH}")
GROUP=$(stat -f '%Sg' "${TARGET_PATH}")
else
USER=$(stat -c '%U' "${TARGET_PATH}")
GROUP=$(stat -c '%G' "${TARGET_PATH}")
fi
cleanup() {
echo '***CLEANUP CALLED***'
# Sync changes back to the shadow folder
rsync -av --delete --exclude .fseventsd "${TARGET_PATH}"/ "${SHADOW_PATH}"/
# Check if the directory is still mounted before attempting to unmount
if mount | grep "on ${TARGET_PATH}"; then
umount "${TARGET_PATH}"
fi
# Remove the RAM disk
if [[ "$OSTYPE" == "darwin"* ]]; then
hdiutil detach "${DEVICE}"
fi
# Move the contents of the shadow folder back to the target folder
shopt -s dotglob
mv "${SHADOW_PATH}"/* "${TARGET_PATH}/"
shopt -u dotglob
# Remove the shadow folder
rm -rf "${SHADOW_PATH}"
exit
}
# Calculate folder size and RAM disk size
SIZE=$(du -s "${TARGET_PATH}" | cut -f 1)
RAM_SIZE=$((SIZE + (SIZE / 10)))
# Use user-defined size if provided
if [ $USER_SIZE -gt 0 ]; then
RAM_SIZE=$USER_SIZE
fi
# Check for open files in the target folder
open_files=$(lsof "${TARGET_PATH}" 2>/dev/null | wc -l | tr -d ' ')
if [ $open_files -gt 0 ]; then
echo "There are $open_files open files in the target folder. Please close them before proceeding."
exit 1
fi
# Move target folder to shadow folder and set trap for cleanup
mkdir "${SHADOW_PATH}"
chown $USER:$GROUP "${SHADOW_PATH}"
shopt -s dotglob
mv "${TARGET_PATH}/"* "${SHADOW_PATH}/"
shopt -u dotglob
trap cleanup SIGHUP SIGINT SIGTERM
# Create and mount tmpfs at the target location
if [[ "$OSTYPE" == "darwin"* ]]; then
RAM_SIZE_BYTES=$((RAM_SIZE * 1024))
DEVICE=$(hdid -nomount ram://${RAM_SIZE_BYTES} | awk '{print $1}')
newfs_hfs "${DEVICE}"
mount -t hfs "${DEVICE}" "${TARGET_PATH}"
else
mount -t tmpfs -o size=${RAM_SIZE}k tmpfs "${TARGET_PATH}"
fi
chown $USER:$GROUP "${TARGET_PATH}"
# Check for mounting errors
if [ $? -ne 0 ]; then
echo "Failed to mount tmpfs on ${TARGET_PATH}"
exit 1
fi
# Rsync the contents of the shadow folder to the RAM disk
rsync -a --progress "${SHADOW_PATH}"/ "${TARGET_PATH}"/
# Sync changes between the RAM disk and the shadow folder
while true; do
if [[ "$OSTYPE" == "darwin"* ]]; then
fswatch -1 "${TARGET_PATH}"
else
inotifywait -r -e modify,attrib,close_write,move,create,delete "${TARGET_PATH}"
fi
rsync -av --delete --exclude '.fseventsd' "${TARGET_PATH}"/ "${SHADOW_PATH}"/
done