In this document, we’re going to show an example of one of the default apfsutil scenarios, explain how to work with APFS sub-volumes, describe read/write access, and define the main possible apfsutil error codes you might encounter.

Feel free to jump ahead to the section you’re most interested in:

User scenarios

The apfsutil contains some simple user scenarios by default, such as:

#ScenarioName
1Root folder enumerationenumroot
2Sub-directory enumerationenumfolder
3File readingreadfile
4List and show all file extended attributeslistea
5Show all sub-volumes from the containerlistsubvolumes

Working with sub-volumes

The apfsutil can work with all sub-volumes in an APFS container. To mount all volumes, add the option “– subvolumes” to the apfsutil arguments. Without this option, only the main (1st) volume will be mounted.

Paragon APFS SDK puts sub-volumes in the “/Ufsd_Volumes” folder. To read or enumerate files and folders on a sub-volume, its full path should be provided.

For example, let’s first acquire a list of sub-volumes using the command syntax below. Note that for this user scenario, the “– subvolumes” switch is optional. If a required sub-volume name is known, this step can be skipped.

apfsutil listsubvolumes /dev/xxx
Volumes:
Untitled Volume2 MyEncryptedVolume
APFS: listsubvolumes returns 0. finished in 4 ms

Next, enumerate the root sub-volume folder or read any file:

apfsutil enumfolder /dev/xxx/Ufsd_Volumes/Untitled
apfsutil readfile /dev/xxx/Ufsd_Volumes/Untitled/testfile.txt

How to add your case

To create your own custom case, input its name (cannot use a previously defined name) in the list, entitled “s_Cmd” (it can be found in the linutil/apfsutil.cpp). Then create a command handler (function) there. To accomplish this, implement the following: 

tatic const t_CmdHandler s_Cmd[] = {
  { "enumroot"        , OnEnumRoot         },   // readdir example
  { "enumfolder"      , OnEnumFolder       },   // enumerate folder
  { "readfile"        , OnReadFile         },   // file reading
  { "listea"          , OnListEa           },   // list all extended attributes
  { "listsubvolumes"  , OnEnumSubvolumes   },   // sub-volumes enumeration
  // handlers for RW version
  { "createfile"      , OnCreateFile       },   // create file
  { "createfolder"    , OnCreateFolder     },   // create folder
  { "queryalloc"      , OnQueryAlloc       },   // list file extents (allocations)
  { "fsinfo"          , OnFsInfo           },   // get file system information
  //
  // TODO: add your handlers here
  // ...
  { NULL      , NULL },
};

Test handler should be of type:

typedef int (*HandlerFunc)(CFileSystem*, const char*);

Inside your specified handler, all public functions from base UFSD classes CFileSystem, CFile, and CDir are available (for more details see ufs\ufsd\include\ufsd\u_fsbase.h).

After rebuilding the utility, a selected test case will be available to start:

sudo apfsutil my_new_case /dev/xxx/path/to/file/or/folder

Read-Write access

Some operations require the full Read-Write sources (The version will be available soon on site: https://www.paragon-software.com/). In the Community Edition, these cases will return a “not implemented” error.

Test NameTest Description
createfilefile creation
createfolderfolder creation
queryalloclist file extents
fsinfoinformation about the file system (all sub-volumes, even encrypted)

Fsinfo example

sudo apfsutil fsinfo /dev/sdb1
APFS Volume [0] 0F7AFC7E-BDF6-4546-8494-2A0C449E8D1F
  Name               : volume1 (Case-insensitive)
  Creator            : newfs_apfs (945.200.129)
  Used Clusters      : 1187894
  Reserved Clusters  : 0
  Files              : 63478
  Directories        : 1630
  Symlinks           : 5
  Special files      : 0
  Snapshots          : 0
  Encrypted          : Yes
 
APFS Volume [1] D45089E3-D391-4246-9490-B4EAC8D4E395
  Name               : volume2 (Case-insensitive)
  Creator            : diskmanagementd (945.200.129)
  Used Clusters      : 270
  Reserved Clusters  : 0
  Files              : 71
  Directories        : 19
  Symlinks           : 1
  Special files      : 0
  Snapshots          : 0
  Encrypted          : No
 
APFS Volume [2] 9D8EBA18-B110-4FCB-86FC-3E18B304628E
  Name               : volume3 (Case-insensitive)
  Creator            : diskmanagementd (945.200.129)
  Used Clusters      : 265
  Reserved Clusters  : 0
  Files              : 64
  Directories        : 18
  Symlinks           : 0
  Special files      : 0
  Snapshots          : 0
  Encrypted          : No

Apfsutil error codes

The utility can return following exit codes:

CodeDescription
0Everything is OK, no error
-1Invalid command line parameters
-2Invalid or empty device name
-3The device is mounted (linux only)
-4No handler specified for the selected test_name
-5Misuse of the –pass option
0xA0001001Errors from the Paragon APFS SDK
0xA0001026Console output will contain an error message

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Summary
Article Name
How APFS SDK CE Works
Description
In this document, you'll learn the main user scenarios including working with sub-volumes, how to add your custom case. We'll look through read-write access, fsinfo example and main apfsutil error codes.
Author
Publisher Name
Paragon Software Group
Publisher Logo