Skip to content

Commit 472ae8e

Browse files
committed
feat: add initial support for DMGs in the ipsw pkg cmd
1 parent 8a32846 commit 472ae8e

File tree

1 file changed

+55
-11
lines changed

1 file changed

+55
-11
lines changed

cmd/ipsw/cmd/pkg.go

+55-11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ THE SOFTWARE.
2222
package cmd
2323

2424
import (
25+
"bufio"
2526
"bytes"
2627
"context"
2728
"fmt"
@@ -37,6 +38,8 @@ import (
3738

3839
"github.com/alecthomas/chroma/v2/quick"
3940
"github.com/apex/log"
41+
"github.com/blacktop/go-apfs/pkg/disk/dmg"
42+
"github.com/blacktop/go-apfs/pkg/disk/hfsplus"
4043
"github.com/blacktop/go-macho/pkg/cpio"
4144
"github.com/blacktop/go-macho/pkg/xar"
4245
"github.com/blacktop/ipsw/internal/magic"
@@ -72,14 +75,12 @@ func init() {
7275
// pkgCmd represents the pkg command
7376
var pkgCmd = &cobra.Command{
7477
Use: "pkg [DMG|PKG]",
75-
Short: "List contents of a DMG/PKG file",
78+
Short: "🚧 List contents of a DMG/PKG file",
7679
Args: cobra.ExactArgs(1),
7780
SilenceUsage: true,
7881
SilenceErrors: true,
7982
RunE: func(cmd *cobra.Command, args []string) (err error) {
8083

81-
var cwd string
82-
8384
if Verbose {
8485
log.SetLevel(log.DebugLevel)
8586
}
@@ -92,6 +93,7 @@ var pkgCmd = &cobra.Command{
9293
flat := viper.GetBool("pkg.flat")
9394
output := viper.GetString("pkg.output")
9495

96+
var cwd string
9597
if len(output) == 0 {
9698
cwd, err = os.Getwd()
9799
if err != nil {
@@ -115,15 +117,57 @@ var pkgCmd = &cobra.Command{
115117
}
116118

117119
if isDMG {
118-
log.Fatal("DMG files are not supported yet")
119-
// d, err := dmg.Open(infile, nil)
120-
// if err != nil {
121-
// return err
122-
// }
123-
// defer d.Close()
124-
// if err := d.Load(); err != nil {
125-
// return err
120+
d, err := dmg.Open(infile, nil)
121+
if err != nil {
122+
return err
123+
}
124+
defer d.Close()
125+
diskImg, err := d.Partition("disk image")
126+
if err != nil {
127+
return fmt.Errorf("failed to open partition: %w", err)
128+
}
129+
o, err := os.Create(filepath.Join(output, "disk.img"))
130+
if err != nil {
131+
return err
132+
}
133+
defer o.Close()
134+
// if _, err := io.Copy(o, diskImg); err != nil {
135+
// return fmt.Errorf("failed to copy disk image: %w", err)
126136
// }
137+
138+
w := bufio.NewWriter(o)
139+
if err := diskImg.Write(w); err != nil {
140+
return fmt.Errorf("failed to write disk image: %w", err)
141+
}
142+
if err := w.Flush(); err != nil {
143+
return fmt.Errorf("failed to flush buffer: %w", err)
144+
}
145+
log.Infof("Extracted disk image to %s", strings.TrimPrefix(filepath.Join(output, "disk.img"), cwd+"/"))
146+
147+
///////////////////////////////////////
148+
149+
log.Info("Parsing disk.img as HFS+...")
150+
hfs, err := hfsplus.Open(filepath.Join(output, "disk.img"))
151+
if err != nil {
152+
return fmt.Errorf("failed to open HFS+: %w", err)
153+
}
154+
defer hfs.Close()
155+
files, err := hfs.Files()
156+
if err != nil {
157+
return fmt.Errorf("failed to get files: %w", err)
158+
}
159+
for _, hf := range files {
160+
ff, err := os.Create(filepath.Join(output, hf.Key.NodeName.String()))
161+
if err != nil {
162+
return fmt.Errorf("failed to create file: %w", err)
163+
}
164+
defer ff.Close()
165+
if _, err := io.Copy(ff, hf.Reader()); err != nil {
166+
return fmt.Errorf("failed to copy file: %w", err)
167+
}
168+
log.Infof("Extracted %s", strings.TrimPrefix(filepath.Join(output, hf.Key.NodeName.String()), cwd+"/"))
169+
log.Warnf("NOW try running `ipsw pkg %s`", strings.TrimPrefix(filepath.Join(output, hf.Key.NodeName.String()), cwd+"/"))
170+
}
127171
} else { // PKG/XAR
128172
pkg, err := xar.Open(infile)
129173
if err != nil {

0 commit comments

Comments
 (0)