Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Show something mumble mumble APFS cloned files mumble?
import Cocoa
// https://cocoa-dev.apple.narkive.com/Ciy40e20/is-cloning-the-same-as-copying-in-apfs#post8
func unclonedSize(of url: URL) throws -> off_t {
var list = attrlist(bitmapcount: UInt16(ATTR_BIT_MAP_COUNT),
reserved: 0,
commonattr: 0,
volattr: 0,
dirattr: 0,
fileattr: 0,
forkattr: attrgroup_t(ATTR_CMNEXT_PRIVATESIZE))
let bufsize = 4 + MemoryLayout<off_t>.size
let buf = UnsafeMutablePointer<UInt8>.allocate(capacity: bufsize)
defer { buf.deallocate() }
let err = url.withUnsafeFileSystemRepresentation { getattrlist($0, &list, buf, bufsize, UInt32(FSOPT_ATTR_CMN_EXTENDED)) }
if err != 0 { throw POSIXError.Code(rawValue: errno).map { POSIXError($0) } ?? CocoaError(.fileReadUnknown) }
let attrsize = buf.withMemoryRebound(to: UInt32.self, capacity: 1) { $0.pointee }
if attrsize < bufsize { throw CocoaError(.fileReadUnknown) }
var unclonedSize: off_t = 0
_ = withUnsafeMutableBytes(of: &unclonedSize) { memcpy($0.baseAddress!, buf + 4, MemoryLayout<off_t>.size) }
return unclonedSize
}
do {
let regular = URL(fileURLWithPath: "/Users/andre/borkens/regular.dmg")
let clone = URL(fileURLWithPath: "/Users/andre/borkens/clone.dmg")
let cpRegular = URL(fileURLWithPath: "/Users/andre/borkens/cp-regular.dmg")
let cloneAppended = URL(fileURLWithPath: "/Users/andre/borkens/clone-appended.dmg")
print("Uncloned size of regular.dmg : \(try unclonedSize(of: regular))")
print("Uncloned size of clone.dmg : \(try unclonedSize(of: clone))")
print("Uncloned size of cpRegular.dmg : \(try unclonedSize(of: cpRegular))")
print("Uncloned size of cloneAppended.dmg: \(try unclonedSize(of: cloneAppended))")
} catch {
print("Error occurred: \(error.localizedDescription)")
}
@dreness

This comment has been minimized.

Copy link
Owner Author

dreness commented May 1, 2019

Let's try it. In Xcode, make a new macOS playground and use the above Swift code. The test files are described as follows:

  • regular.dmg is a file of zeroes made with dd
  • cp-regular.dmg is a copy of that file made with cp, no arguments. standard copy.
  • clone.dmg was made with clonefile (cp -c).
  • clone-appended.dmg is a clone of regular.dmg, but with 10 bytes appended to it with echo and >>.
xomg% /bin/ls -le@ *.dmg
-rw-r--r--  1 andre  staff  104857610 Apr 30 21:35 clone-appended.dmg
-rw-r--r--  1 andre  staff  104857600 Apr 30 21:32 clone.dmg
-rw-r--r--  1 andre  staff  104857600 Apr 30 21:32 cp-regular.dmg
-rw-r--r--  1 andre  staff  104857600 Apr 30 21:32 regular.dmg

The playground output is:

Uncloned size of regular.dmg      : 0
Uncloned size of clone.dmg        : 0
Uncloned size of cpRegular.dmg    : 104857600
Uncloned size of cloneAppended.dmg: 14921728

Because this is a gist, conclusions are left as an exercise for the reader. I'll even tell you where the answer is: in the man page for getattrlist(2).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.