Created
March 15, 2019 12:47
-
-
Save cirocosta/1a3e69e78dd6927a7161d9a54f6f899b to your computer and use it in GitHub Desktop.
a "baggageclaim-driver"-a-like script leveraging `hdiutil` and `clonefile(2)`
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 | |
# apfs - a "baggageclaim-driver"-a-like script leveraging `hdiutil` and | |
# `clonefile(2)`. | |
# | |
# Usage: apfs.sh (create|cow|destroy) | |
# | |
# Commands: | |
# create vol-id desc: creates a volume | |
# cow vol-id parent-vol-id desc: creates a cow layer based on `parent-vol-id` | |
# destroy vol-id desc: destroys a volume | |
# | |
set -e -x | |
readonly IMAGES_PATH="/tmp/images" | |
readonly VOLUMES_PATH="/tmp/volumes" | |
main() { | |
case $1 in | |
create) | |
create_volume $2 | |
;; | |
destroy) | |
destroy_volume $2 | |
;; | |
cow) | |
create_cow $2 $3 | |
;; | |
*) | |
echo "Error: Unknown argument '$1'." | |
echo "Usage: $0 (create|cow|destroy)" | |
exit 1 | |
;; | |
esac | |
} | |
# creates an underlying image (sparse file) to back the volume, then attaches | |
# such image to a `/dev` device which gets mounted to a mountpoint. | |
# | |
# /images/uuid1.sparseimage (1G sparse file) | |
# | | |
# *--> /dev/disk27s1 (block device) | |
# | | |
# *--> /volumes/uuid1 (mountpoint) | |
# | |
create_volume() { | |
local handle=$1 | |
local volume_path disk_image | |
if [[ -z $1 ]]; then | |
echo "create_volume(handle): arg must not be empty" | |
return 1 | |
fi | |
disk_image="$IMAGES_PATH/${handle}.sparseimage" | |
volume_path="$VOLUMES_PATH/${handle}" | |
hdiutil create \ | |
-size 1g \ | |
-type SPARSE \ | |
-fs APFS \ | |
-volname $handle \ | |
$disk_image | |
hdiutil attach \ | |
-mountpoint $volume_path \ | |
$disk_image | |
} | |
# clones the backing image of the parent volume and then mounts that | |
# to a different location, allowing us to modify the contents of the | |
# parent volume without interfering with the contents of the first | |
# (multi-file cow semantics!) | |
# | |
# | |
# /images/uuid1.sparseimage (parent's 1G sparse file) | |
# | | |
# | | |
# *-> clone this thing: clonefile(src,dst, flags) | |
# | | |
# *-> produces /volume/uuid12.sparseimage | |
# | | |
# *-> create disk & attach to it | |
# | | |
# mount to a volume location <-* | |
# | |
# | |
create_cow() { | |
local handle=$1 | |
local handle_parent=$2 | |
local volume_path disk_image disk_image_parent | |
if [[ -z $handle || -z $handle_parent ]]; then | |
echo "create_cow(handle, handle_parent): both args must not be empty" | |
return 1 | |
fi | |
disk_image="$IMAGES_PATH/${handle}.sparseimage" | |
disk_image_parent="$IMAGES_PATH/${handle_parent}.sparseimage" | |
volume_path="$VOLUMES_PATH/${handle}" | |
cp -c $disk_image_parent $disk_image | |
hdiutil attach \ | |
-mountpoint $volume_path \ | |
$disk_image | |
} | |
# destroys a volume by detaching it an removing the underlying disk image. | |
destroy_volume() { | |
local handle=$1 | |
local volume_path disk_image | |
if [[ -z $handle ]]; then | |
echo "destroy_volume(handle): arg must not be empty" | |
return 1 | |
fi | |
disk_image="$IMAGES_PATH/${handle}.sparseimage" | |
volume_path="$VOLUMES_PATH/${handle}" | |
hdiutil detach $volume_path | |
rm -f $disk_image | |
} | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment