idevice 1.1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/NOTICE +202 -0
- data/README.md +74 -0
- data/Rakefile +37 -0
- data/examples/idevimgmount +58 -0
- data/examples/idumplockdownvalues +64 -0
- data/examples/ifetchcrashreports +54 -0
- data/examples/ilistapps +38 -0
- data/examples/ilistudids +26 -0
- data/examples/ilog +35 -0
- data/examples/installipa +51 -0
- data/examples/iremoveapp +42 -0
- data/examples/irestart +26 -0
- data/examples/iscreenshotr +39 -0
- data/idevice.gemspec +33 -0
- data/lib/idevice.rb +69 -0
- data/lib/idevice/afc.rb +518 -0
- data/lib/idevice/c.rb +129 -0
- data/lib/idevice/diagnostics_relay.rb +185 -0
- data/lib/idevice/file_relay.rb +83 -0
- data/lib/idevice/heartbeat.rb +99 -0
- data/lib/idevice/house_arrest.rb +138 -0
- data/lib/idevice/idevice.rb +208 -0
- data/lib/idevice/image_mounter.rb +117 -0
- data/lib/idevice/installation_proxy.rb +193 -0
- data/lib/idevice/lockdown.rb +350 -0
- data/lib/idevice/misagent.rb +112 -0
- data/lib/idevice/mobilebackup.rb +183 -0
- data/lib/idevice/mobilebackup2.rb +174 -0
- data/lib/idevice/mobilesync.rb +306 -0
- data/lib/idevice/notification_proxy.rb +168 -0
- data/lib/idevice/plist.rb +366 -0
- data/lib/idevice/restore.rb +176 -0
- data/lib/idevice/sbservices.rb +152 -0
- data/lib/idevice/screenshotr.rb +88 -0
- data/lib/idevice/version.rb +3 -0
- data/lib/idevice/webinspector.rb +96 -0
- data/spec/afc_devicespec.rb +409 -0
- data/spec/diagnostics_relay_devicespec.rb +125 -0
- data/spec/file_relay_devicespec.rb +45 -0
- data/spec/heartbeat_devicespec.rb +39 -0
- data/spec/idevice_devicespec.rb +93 -0
- data/spec/idevice_spec.rb +29 -0
- data/spec/image_mounter_devicespec.rb +65 -0
- data/spec/installation_proxy_devicespec.rb +54 -0
- data/spec/lockdown_devicespec.rb +106 -0
- data/spec/misagent_devicespec.rb +43 -0
- data/spec/mobilebackup2_devicespec.rb +58 -0
- data/spec/mobilebackup_devicespec.rb +41 -0
- data/spec/mobilesync_devicespec.rb +62 -0
- data/spec/notification_proxy_devicespec.rb +45 -0
- data/spec/plist_spec.rb +176 -0
- data/spec/restore_devicespec.rb +72 -0
- data/spec/samples/plist.bin +0 -0
- data/spec/samples/plist.xml +10 -0
- data/spec/sbservices_devicespec.rb +64 -0
- data/spec/screenshotr_devicespec.rb +39 -0
- data/spec/spec_helper.rb +73 -0
- data/spec/webinspector_devicespec.rb +36 -0
- metadata +233 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
4
|
+
#
|
5
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
6
|
+
# or more contributor license agreements. See the NOTICE file
|
7
|
+
# distributed with this work for additional information
|
8
|
+
# regarding copyright ownership. The ASF licenses this file
|
9
|
+
# to you under the Apache License, Version 2.0 (the
|
10
|
+
# "License"); you may not use this file except in compliance
|
11
|
+
# with the License. You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing,
|
16
|
+
# software distributed under the License is distributed on an
|
17
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
18
|
+
# KIND, either express or implied. See the License for the
|
19
|
+
# specific language governing permissions and limitations
|
20
|
+
# under the License.
|
21
|
+
|
22
|
+
|
23
|
+
require 'open3'
|
24
|
+
require 'bundler/setup'
|
25
|
+
require 'idevice'
|
26
|
+
|
27
|
+
outfile = ARGV.shift
|
28
|
+
if outfile.nil? or ARGV.shift
|
29
|
+
$stderr.puts "Usage: #{File.basename $0} path/to/output.cpio"
|
30
|
+
exit(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
frc = Idevice::FileRelayClient.attach
|
34
|
+
$stderr.puts "[.] Requesting crash reports"
|
35
|
+
len = 0
|
36
|
+
File.open(outfile, 'w') do |outf|
|
37
|
+
Open3.popen3("cpio -t") do |w,r,e|
|
38
|
+
begin
|
39
|
+
frc.request_sources("CrashReporter") do |chunk|
|
40
|
+
w.write(chunk)
|
41
|
+
outf.write(chunk)
|
42
|
+
len += chunk.size
|
43
|
+
end
|
44
|
+
ensure
|
45
|
+
w.close
|
46
|
+
puts "[+] Wrote #{len} bytes to #{outfile}",
|
47
|
+
"Contents:",
|
48
|
+
r.read
|
49
|
+
|
50
|
+
r.close
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
data/examples/ilistapps
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
4
|
+
#
|
5
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
6
|
+
# or more contributor license agreements. See the NOTICE file
|
7
|
+
# distributed with this work for additional information
|
8
|
+
# regarding copyright ownership. The ASF licenses this file
|
9
|
+
# to you under the Apache License, Version 2.0 (the
|
10
|
+
# "License"); you may not use this file except in compliance
|
11
|
+
# with the License. You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing,
|
16
|
+
# software distributed under the License is distributed on an
|
17
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
18
|
+
# KIND, either express or implied. See the License for the
|
19
|
+
# specific language governing permissions and limitations
|
20
|
+
# under the License.
|
21
|
+
|
22
|
+
|
23
|
+
require 'bundler/setup'
|
24
|
+
require 'idevice'
|
25
|
+
|
26
|
+
instpxy = Idevice::InstProxyClient.attach
|
27
|
+
|
28
|
+
lst = instpxy.browse.sort{|a,b| a["Path"] <=> b["Path"] }.map do |app|
|
29
|
+
puts "%s App: %s (%s - %s)\n exe: %s/%s\n\n" % app.values_at(
|
30
|
+
"ApplicationType",
|
31
|
+
"CFBundleDisplayName",
|
32
|
+
"CFBundleIdentifier",
|
33
|
+
"CFBundleVersion",
|
34
|
+
"Path",
|
35
|
+
"CFBundleExecutable",
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
data/examples/ilistudids
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
4
|
+
#
|
5
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
6
|
+
# or more contributor license agreements. See the NOTICE file
|
7
|
+
# distributed with this work for additional information
|
8
|
+
# regarding copyright ownership. The ASF licenses this file
|
9
|
+
# to you under the Apache License, Version 2.0 (the
|
10
|
+
# "License"); you may not use this file except in compliance
|
11
|
+
# with the License. You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing,
|
16
|
+
# software distributed under the License is distributed on an
|
17
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
18
|
+
# KIND, either express or implied. See the License for the
|
19
|
+
# specific language governing permissions and limitations
|
20
|
+
# under the License.
|
21
|
+
|
22
|
+
|
23
|
+
require 'bundler/setup'
|
24
|
+
require 'idevice'
|
25
|
+
|
26
|
+
puts Idevice.device_list
|
data/examples/ilog
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
4
|
+
#
|
5
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
6
|
+
# or more contributor license agreements. See the NOTICE file
|
7
|
+
# distributed with this work for additional information
|
8
|
+
# regarding copyright ownership. The ASF licenses this file
|
9
|
+
# to you under the Apache License, Version 2.0 (the
|
10
|
+
# "License"); you may not use this file except in compliance
|
11
|
+
# with the License. You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing,
|
16
|
+
# software distributed under the License is distributed on an
|
17
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
18
|
+
# KIND, either express or implied. See the License for the
|
19
|
+
# specific language governing permissions and limitations
|
20
|
+
# under the License.
|
21
|
+
|
22
|
+
|
23
|
+
require 'bundler/setup'
|
24
|
+
require 'idevice'
|
25
|
+
|
26
|
+
idev = Idevice::Idevice.attach
|
27
|
+
ldcli = Idevice::LockdownClient.attach(idevice:idev)
|
28
|
+
syslog_ldsvc = ldcli.start_service("com.apple.syslog_relay")
|
29
|
+
syslog_relay = idev.connect(syslog_ldsvc[:port])
|
30
|
+
begin
|
31
|
+
syslog_relay.receive_all(1) {|chunk| $stdout.write chunk } while true
|
32
|
+
rescue Interrupt
|
33
|
+
exit 0
|
34
|
+
end
|
35
|
+
|
data/examples/installipa
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
4
|
+
#
|
5
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
6
|
+
# or more contributor license agreements. See the NOTICE file
|
7
|
+
# distributed with this work for additional information
|
8
|
+
# regarding copyright ownership. The ASF licenses this file
|
9
|
+
# to you under the Apache License, Version 2.0 (the
|
10
|
+
# "License"); you may not use this file except in compliance
|
11
|
+
# with the License. You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing,
|
16
|
+
# software distributed under the License is distributed on an
|
17
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
18
|
+
# KIND, either express or implied. See the License for the
|
19
|
+
# specific language governing permissions and limitations
|
20
|
+
# under the License.
|
21
|
+
|
22
|
+
require 'bundler/setup'
|
23
|
+
require 'idevice'
|
24
|
+
|
25
|
+
ipa_path = ARGV.shift
|
26
|
+
if ipa_path.nil? or ARGV.shift
|
27
|
+
$stderr.puts "Usage: #{File.basename} /path/to/an.ipa"
|
28
|
+
exit(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
ipa = Pathname(ipa_path)
|
32
|
+
|
33
|
+
idev = Idevice::Idevice.attach
|
34
|
+
|
35
|
+
remote_path = Pathname("PublicStaging").join(ipa.basename)
|
36
|
+
|
37
|
+
afc = Idevice::AFCClient.attach(idevice:idev)
|
38
|
+
$stderr.puts "[.] Uploading #{ipa} to #{remote_path}"
|
39
|
+
afc.put_path(ipa.to_s, remote_path.to_s)
|
40
|
+
|
41
|
+
instpxy = Idevice::InstProxyClient.attach(idevice:idev)
|
42
|
+
$stderr.puts "[.] Requesting installation of #{remote_path}"
|
43
|
+
finished = false
|
44
|
+
instpxy.install(remote_path.to_s) do |name, status|
|
45
|
+
p [name, status]
|
46
|
+
finished = (status["Error"] or status["Status"] == "Complete")
|
47
|
+
end
|
48
|
+
|
49
|
+
while not finished
|
50
|
+
#nop
|
51
|
+
end
|
data/examples/iremoveapp
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
4
|
+
#
|
5
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
6
|
+
# or more contributor license agreements. See the NOTICE file
|
7
|
+
# distributed with this work for additional information
|
8
|
+
# regarding copyright ownership. The ASF licenses this file
|
9
|
+
# to you under the Apache License, Version 2.0 (the
|
10
|
+
# "License"); you may not use this file except in compliance
|
11
|
+
# with the License. You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing,
|
16
|
+
# software distributed under the License is distributed on an
|
17
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
18
|
+
# KIND, either express or implied. See the License for the
|
19
|
+
# specific language governing permissions and limitations
|
20
|
+
# under the License.
|
21
|
+
|
22
|
+
|
23
|
+
require 'bundler/setup'
|
24
|
+
require 'idevice'
|
25
|
+
|
26
|
+
appid = ARGV.shift
|
27
|
+
if appid.nil? or ARGV.shift
|
28
|
+
$stderr.puts "Usage: #{File.basename} appid"
|
29
|
+
exit(1)
|
30
|
+
end
|
31
|
+
|
32
|
+
instpxy = Idevice::InstProxyClient.attach
|
33
|
+
$stderr.puts "[.] Requesting uninstallation of #{appid}"
|
34
|
+
finished = false
|
35
|
+
instpxy.uninstall(appid) do |name, status|
|
36
|
+
p [name, status]
|
37
|
+
finished = (status["Error"] or status["Status"] == "Complete")
|
38
|
+
end
|
39
|
+
|
40
|
+
until finished
|
41
|
+
#nop
|
42
|
+
end
|
data/examples/irestart
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
4
|
+
#
|
5
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
6
|
+
# or more contributor license agreements. See the NOTICE file
|
7
|
+
# distributed with this work for additional information
|
8
|
+
# regarding copyright ownership. The ASF licenses this file
|
9
|
+
# to you under the Apache License, Version 2.0 (the
|
10
|
+
# "License"); you may not use this file except in compliance
|
11
|
+
# with the License. You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing,
|
16
|
+
# software distributed under the License is distributed on an
|
17
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
18
|
+
# KIND, either express or implied. See the License for the
|
19
|
+
# specific language governing permissions and limitations
|
20
|
+
# under the License.
|
21
|
+
|
22
|
+
|
23
|
+
require 'bundler/setup'
|
24
|
+
require 'idevice'
|
25
|
+
|
26
|
+
Idevice::DiagnosticsRelayClient.attach.restart(Idevice::DiagnosticsRelayClient::FLAG_WAIT_FOR_DISCONNECT)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
4
|
+
#
|
5
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
6
|
+
# or more contributor license agreements. See the NOTICE file
|
7
|
+
# distributed with this work for additional information
|
8
|
+
# regarding copyright ownership. The ASF licenses this file
|
9
|
+
# to you under the Apache License, Version 2.0 (the
|
10
|
+
# "License"); you may not use this file except in compliance
|
11
|
+
# with the License. You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing,
|
16
|
+
# software distributed under the License is distributed on an
|
17
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
18
|
+
# KIND, either express or implied. See the License for the
|
19
|
+
# specific language governing permissions and limitations
|
20
|
+
# under the License.
|
21
|
+
|
22
|
+
|
23
|
+
require 'bundler/setup'
|
24
|
+
require 'idevice'
|
25
|
+
|
26
|
+
outname = ARGV.shift || "iscreenshot.tiff"
|
27
|
+
|
28
|
+
begin
|
29
|
+
sshotr = Idevice::ScreenShotrClient.attach()
|
30
|
+
rescue Idevice::LockdownError
|
31
|
+
$stderr.puts "[-] Error: unable to connect to screenshotr",
|
32
|
+
" Hint: the DeveloperTools dmg must be mounted on device"
|
33
|
+
exit(1)
|
34
|
+
end
|
35
|
+
|
36
|
+
image = sshotr.take_screenshot
|
37
|
+
ret = File.open(outname, "w") {|f| f.write image }
|
38
|
+
puts "[+] wrote #{ret} bytes to #{outname}"
|
39
|
+
exit(0)
|
data/idevice.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'idevice/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "idevice"
|
8
|
+
spec.version = Idevice::VERSION
|
9
|
+
spec.authors = ["Eric Monti"]
|
10
|
+
spec.email = ["monti@bluebox.com"]
|
11
|
+
spec.description = %q{Ruby FFI bindings for libimobiledevice}
|
12
|
+
spec.summary = %q{Ruby FFI bindings for libimobiledevice.
|
13
|
+
|
14
|
+
The ruby Idevice library was written primarily as a research tool for
|
15
|
+
prototyping iOS tools that use USB as well as a tool to aid in
|
16
|
+
reverse-engineering new areas of the iOS USB protocols.
|
17
|
+
}
|
18
|
+
spec.homepage = "https://github.com/blueboxsecurity/idevice"
|
19
|
+
spec.license = "Apache License, Version 2.0"
|
20
|
+
|
21
|
+
spec.files = `git ls-files`.split($/)
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_dependency "ffi"
|
27
|
+
spec.add_dependency "plist"
|
28
|
+
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
30
|
+
spec.add_development_dependency "rake"
|
31
|
+
spec.add_development_dependency "rspec"
|
32
|
+
spec.add_development_dependency "pry"
|
33
|
+
end
|
data/lib/idevice.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
5
|
+
# or more contributor license agreements. See the NOTICE file
|
6
|
+
# distributed with this work for additional information
|
7
|
+
# regarding copyright ownership. The ASF licenses this file
|
8
|
+
# to you under the Apache License, Version 2.0 (the
|
9
|
+
# "License"); you may not use this file except in compliance
|
10
|
+
# with the License. You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing,
|
15
|
+
# software distributed under the License is distributed on an
|
16
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
17
|
+
# KIND, either express or implied. See the License for the
|
18
|
+
# specific language governing permissions and limitations
|
19
|
+
# under the License.
|
20
|
+
|
21
|
+
require 'rubygems'
|
22
|
+
|
23
|
+
require 'idevice/version'
|
24
|
+
require 'idevice/c'
|
25
|
+
require 'idevice/plist'
|
26
|
+
require 'idevice/idevice'
|
27
|
+
require 'idevice/lockdown'
|
28
|
+
require 'idevice/house_arrest'
|
29
|
+
require 'idevice/afc'
|
30
|
+
require 'idevice/installation_proxy'
|
31
|
+
require 'idevice/misagent'
|
32
|
+
require 'idevice/diagnostics_relay'
|
33
|
+
require 'idevice/file_relay'
|
34
|
+
require 'idevice/heartbeat'
|
35
|
+
require 'idevice/image_mounter'
|
36
|
+
require 'idevice/mobilebackup'
|
37
|
+
require 'idevice/mobilebackup2'
|
38
|
+
require 'idevice/mobilesync'
|
39
|
+
require 'idevice/notification_proxy'
|
40
|
+
require 'idevice/restore'
|
41
|
+
require 'idevice/sbservices'
|
42
|
+
require 'idevice/screenshotr'
|
43
|
+
require 'idevice/webinspector'
|
44
|
+
|
45
|
+
module Idevice
|
46
|
+
def self.debug_level= num
|
47
|
+
C.idevice_set_debug_level(num)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.device_list
|
51
|
+
FFI::MemoryPointer.new(:int) do |countp|
|
52
|
+
FFI::MemoryPointer.new(:pointer) do |devices|
|
53
|
+
ierr = C.idevice_get_device_list(devices, countp)
|
54
|
+
if ierr == :SUCCESS
|
55
|
+
ret = []
|
56
|
+
count = countp.read_int
|
57
|
+
if count > 0
|
58
|
+
devices.read_pointer.read_array_of_pointer(count).map { |sp| ret << sp.read_string }
|
59
|
+
end
|
60
|
+
C.idevice_device_list_free(devices.read_pointer)
|
61
|
+
return ret
|
62
|
+
else
|
63
|
+
raise Idevice::IdeviceError, "Library error: #{ierr}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
data/lib/idevice/afc.rb
ADDED
@@ -0,0 +1,518 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
5
|
+
# or more contributor license agreements. See the NOTICE file
|
6
|
+
# distributed with this work for additional information
|
7
|
+
# regarding copyright ownership. The ASF licenses this file
|
8
|
+
# to you under the Apache License, Version 2.0 (the
|
9
|
+
# "License"); you may not use this file except in compliance
|
10
|
+
# with the License. You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing,
|
15
|
+
# software distributed under the License is distributed on an
|
16
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
17
|
+
# KIND, either express or implied. See the License for the
|
18
|
+
# specific language governing permissions and limitations
|
19
|
+
# under the License.
|
20
|
+
|
21
|
+
require 'idevice/c'
|
22
|
+
require 'idevice/idevice'
|
23
|
+
require 'idevice/lockdown'
|
24
|
+
require 'idevice/house_arrest'
|
25
|
+
|
26
|
+
module Idevice
|
27
|
+
class AFCError < IdeviceLibError
|
28
|
+
end
|
29
|
+
|
30
|
+
AFC_DEFAULT_CHUNKSIZE = 8192
|
31
|
+
|
32
|
+
class AFCClient < C::ManagedOpaquePointer
|
33
|
+
include LibHelpers
|
34
|
+
|
35
|
+
def self.release(ptr)
|
36
|
+
C.afc_client_free(ptr) unless ptr.null?
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.attach(opts={})
|
40
|
+
if opts[:appid]
|
41
|
+
return HouseArrestClient.attach(opts).afc_client_for_container(opts[:appid])
|
42
|
+
|
43
|
+
else
|
44
|
+
identifier =
|
45
|
+
if opts[:root]
|
46
|
+
"com.apple.afc2"
|
47
|
+
elsif opts[:afc_identifier]
|
48
|
+
opts[:afc_identifier]
|
49
|
+
else
|
50
|
+
"com.apple.afc"
|
51
|
+
end
|
52
|
+
|
53
|
+
_attach_helper(identifier, opts) do |idevice, ldsvc, p_afc|
|
54
|
+
err = C.afc_client_new(idevice, ldsvc, p_afc)
|
55
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
56
|
+
|
57
|
+
afc = p_afc.read_pointer
|
58
|
+
raise AFCError, "afc_client_new returned a NULL afc_client_t pointer" if afc.null?
|
59
|
+
return new(afc)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def device_info(key=nil)
|
65
|
+
ret = nil
|
66
|
+
if key
|
67
|
+
FFI::MemoryPointer.new(:pointer) do |p_value|
|
68
|
+
err = C.afc_get_device_info_key(self, key, p_value)
|
69
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
70
|
+
|
71
|
+
value = p_value.read_pointer
|
72
|
+
unless value.null?
|
73
|
+
ret = value.read_string
|
74
|
+
C.free(value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
else
|
78
|
+
FFI::MemoryPointer.new(:pointer) do |p_infos|
|
79
|
+
err = C.afc_get_device_info(self, p_infos)
|
80
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
81
|
+
ret = _infolist_to_hash(p_infos)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
return ret
|
85
|
+
end
|
86
|
+
|
87
|
+
def read_directory(path='.')
|
88
|
+
ret = nil
|
89
|
+
FFI::MemoryPointer.new(:pointer) do |p_dirlist|
|
90
|
+
err = C.afc_read_directory(self, path, p_dirlist)
|
91
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
92
|
+
ret = _unbound_list_to_array(p_dirlist)
|
93
|
+
end
|
94
|
+
|
95
|
+
raise AFCError, "afc_read_directory returned a null directory list for path: #{path}" if ret.nil?
|
96
|
+
return ret
|
97
|
+
end
|
98
|
+
alias :ls :read_directory
|
99
|
+
|
100
|
+
def file_info(path)
|
101
|
+
ret = nil
|
102
|
+
FFI::MemoryPointer.new(:pointer) do |p_fileinfo|
|
103
|
+
err = C.afc_get_file_info(self, path, p_fileinfo)
|
104
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
105
|
+
ret = _infolist_to_hash(p_fileinfo)
|
106
|
+
|
107
|
+
# convert string values to something more useful
|
108
|
+
ret[:st_ifmt] = ret[:st_ifmt].to_sym if ret[:st_ifmt]
|
109
|
+
|
110
|
+
[:st_blocks, :st_nlink, :st_size].each do |k|
|
111
|
+
ret[k] = ret[k].to_i if ret[k]
|
112
|
+
end
|
113
|
+
|
114
|
+
[:st_birthtime, :st_mtime].each do |k|
|
115
|
+
ret[k] = _afctime_to_time(ret[k])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
raise AFCError, "afc_get_file_info returned null info for path: #{path}" if ret.nil?
|
119
|
+
return ret
|
120
|
+
end
|
121
|
+
alias :stat :file_info
|
122
|
+
|
123
|
+
def touch(path)
|
124
|
+
open(path, 'a'){ }
|
125
|
+
return true
|
126
|
+
end
|
127
|
+
|
128
|
+
def make_directory(path)
|
129
|
+
err = C.afc_make_directory(self, path)
|
130
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
131
|
+
return true
|
132
|
+
end
|
133
|
+
alias :mkdir :make_directory
|
134
|
+
|
135
|
+
def symlink(from, to)
|
136
|
+
err = C.afc_make_link(self, :SYMLINK, from, to)
|
137
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
138
|
+
return true
|
139
|
+
end
|
140
|
+
alias :ln_s :symlink
|
141
|
+
|
142
|
+
def hardlink(from, to)
|
143
|
+
err = C.afc_make_link(self, :HARDLINK, from, to)
|
144
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
145
|
+
return true
|
146
|
+
end
|
147
|
+
alias :ln :hardlink
|
148
|
+
|
149
|
+
def rename_path(from, to)
|
150
|
+
err = C.afc_rename_path(self, from, to)
|
151
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
152
|
+
return true
|
153
|
+
end
|
154
|
+
alias :mv :rename_path
|
155
|
+
|
156
|
+
def remove_path(path)
|
157
|
+
err = C.afc_remove_path(self, path)
|
158
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
159
|
+
return true
|
160
|
+
end
|
161
|
+
alias :rm :remove_path
|
162
|
+
|
163
|
+
def truncate(path, size)
|
164
|
+
err = C.afc_truncate(self, path, size)
|
165
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
166
|
+
return true
|
167
|
+
end
|
168
|
+
|
169
|
+
def cat(path, chunksz=nil, &block)
|
170
|
+
AFCFile.open(self, path, 'r') { |f| return f.read_all(chunksz, &block) }
|
171
|
+
end
|
172
|
+
|
173
|
+
def size(path)
|
174
|
+
res = file_info(path)
|
175
|
+
return res[:st_size].to_i
|
176
|
+
end
|
177
|
+
|
178
|
+
def mtime(path)
|
179
|
+
info = file_info(path)
|
180
|
+
return info[:st_mtime]
|
181
|
+
end
|
182
|
+
|
183
|
+
def ctime(path)
|
184
|
+
info = file_info(path)
|
185
|
+
return info[:st_birthtime]
|
186
|
+
end
|
187
|
+
|
188
|
+
def put_path(frompath, topath, chunksz=nil)
|
189
|
+
chunksz ||= AFC_DEFAULT_CHUNKSIZE
|
190
|
+
wlen = 0
|
191
|
+
|
192
|
+
File.open(frompath, 'r') do |from|
|
193
|
+
AFCFile.open(self, topath, 'w') do |to|
|
194
|
+
while chunk = from.read(chunksz)
|
195
|
+
to.write(chunk)
|
196
|
+
yield chunk.size if block_given?
|
197
|
+
wlen+=chunk.size
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
return wlen
|
203
|
+
end
|
204
|
+
|
205
|
+
def getpath(frompath, topath, chunksz=nil)
|
206
|
+
wlen = 0
|
207
|
+
AFCFile.open(self, frompath, 'r') do |from|
|
208
|
+
File.open(topath, 'w') do |to|
|
209
|
+
from.read_all(chunksz) do |chunk|
|
210
|
+
to.write(chunk)
|
211
|
+
yield chunk.size if block_given?
|
212
|
+
wlen += chunk.size
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
return wlen
|
217
|
+
end
|
218
|
+
|
219
|
+
def set_file_time(path, time)
|
220
|
+
tval = case time
|
221
|
+
when Time
|
222
|
+
_time_to_afctime(time)
|
223
|
+
when DateTime
|
224
|
+
_time_to_afctime(time.to_time)
|
225
|
+
else
|
226
|
+
time
|
227
|
+
end
|
228
|
+
err = C.afc_set_file_time(self, path, tval)
|
229
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
230
|
+
return true
|
231
|
+
end
|
232
|
+
|
233
|
+
def open(path, mode=nil, &block)
|
234
|
+
AFCFile.open(self,path,mode,&block)
|
235
|
+
end
|
236
|
+
|
237
|
+
private
|
238
|
+
def _afctime_to_time(timestr)
|
239
|
+
# using DateTime to ensure handling as UTC
|
240
|
+
DateTime.strptime(timestr[0..-10], "%s").to_time
|
241
|
+
end
|
242
|
+
|
243
|
+
def _time_to_afctime(timeval)
|
244
|
+
timeval.utc.to_i * 1000000000
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# short name alias to AFCClient
|
249
|
+
AFC = AFCClient
|
250
|
+
|
251
|
+
class AFCFile
|
252
|
+
def self.open(afcclient, path, mode=:RDONLY)
|
253
|
+
m = case mode
|
254
|
+
when Symbol
|
255
|
+
mode
|
256
|
+
when 'r',nil
|
257
|
+
:RDONLY
|
258
|
+
when 'r+'
|
259
|
+
:RW
|
260
|
+
when 'w'
|
261
|
+
:WRONLY
|
262
|
+
when 'w+'
|
263
|
+
:WR
|
264
|
+
when 'a'
|
265
|
+
:APPEND
|
266
|
+
when 'a+'
|
267
|
+
:RDAPPEND
|
268
|
+
else
|
269
|
+
raise ArgumentError, "invalid file mode: #{mode.inspect}"
|
270
|
+
end
|
271
|
+
|
272
|
+
afcfile=nil
|
273
|
+
FFI::MemoryPointer.new(:uint64) do |p_handle|
|
274
|
+
err =C.afc_file_open(afcclient, path, m, p_handle)
|
275
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
276
|
+
afcfile = new(afcclient, p_handle.read_uint64)
|
277
|
+
end
|
278
|
+
|
279
|
+
begin
|
280
|
+
yield(afcfile)
|
281
|
+
ensure
|
282
|
+
afcfile.close unless afcfile.closed?
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def initialize(afcclient, handle)
|
287
|
+
@afcclient = afcclient
|
288
|
+
@handle = handle
|
289
|
+
@closed = false
|
290
|
+
end
|
291
|
+
|
292
|
+
def close
|
293
|
+
err = C.afc_file_close(@afcclient, @handle)
|
294
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
295
|
+
@closed = true
|
296
|
+
end
|
297
|
+
|
298
|
+
def closed?
|
299
|
+
@closed == true
|
300
|
+
end
|
301
|
+
|
302
|
+
def open?
|
303
|
+
not closed?
|
304
|
+
end
|
305
|
+
|
306
|
+
def lock(op)
|
307
|
+
err = C.afc_file_lock(@afcclient, @handle, op)
|
308
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
309
|
+
return true
|
310
|
+
end
|
311
|
+
|
312
|
+
def seek(offset, whence)
|
313
|
+
err = C.afc_file_seek(@afcclient, @handle, offset, whence)
|
314
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
315
|
+
end
|
316
|
+
|
317
|
+
def tell
|
318
|
+
FFI::MemoryPointer.new(:pointer) do |p_pos|
|
319
|
+
err = C.afc_file_tell(@afcclient, @handle, p_pos)
|
320
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
321
|
+
return p_pos.read_uint16
|
322
|
+
end
|
323
|
+
end
|
324
|
+
alias :pos :tell
|
325
|
+
|
326
|
+
def pos=(offset)
|
327
|
+
seek(offset, :SEEK_SET)
|
328
|
+
end
|
329
|
+
|
330
|
+
def rewind
|
331
|
+
self.pos=0
|
332
|
+
end
|
333
|
+
|
334
|
+
def read_all(chunksz=nil)
|
335
|
+
chunksz ||= AFC_DEFAULT_CHUNKSIZE
|
336
|
+
ret = nil
|
337
|
+
FFI::MemoryPointer.new(chunksz) do |buf|
|
338
|
+
FFI::MemoryPointer.new(:uint32) do |p_rlen|
|
339
|
+
while (err=C.afc_file_read(@afcclient, @handle, buf, buf.size, p_rlen)) == :SUCCESS
|
340
|
+
rlen = p_rlen.read_uint32
|
341
|
+
chunk = buf.read_bytes(rlen)
|
342
|
+
if block_given?
|
343
|
+
yield chunk
|
344
|
+
else
|
345
|
+
ret ||= StringIO.new unless block_given?
|
346
|
+
ret << chunk
|
347
|
+
end
|
348
|
+
break if rlen == 0
|
349
|
+
end
|
350
|
+
raise AFCError, "AFC error: #{err}" unless [:SUCCESS, :END_OF_DATA].include?(err)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
return ret.string unless ret.nil?
|
355
|
+
end
|
356
|
+
|
357
|
+
def read(len=nil, &block)
|
358
|
+
return read_all(nil, &block) if len.nil?
|
359
|
+
|
360
|
+
ret = nil
|
361
|
+
|
362
|
+
FFI::MemoryPointer.new(len) do |buf|
|
363
|
+
FFI::MemoryPointer.new(:uint32) do |p_rlen|
|
364
|
+
while (err=C.afc_file_read(@afcclient, @handle, buf, len, p_rlen)) == :SUCCESS
|
365
|
+
rlen = p_rlen.read_uint32
|
366
|
+
ret ||= StringIO.new
|
367
|
+
ret << buf.read_bytes(rlen)
|
368
|
+
len -= rlen
|
369
|
+
break if len <= 0
|
370
|
+
end
|
371
|
+
raise AFCError, "AFC error: #{err}" unless [:SUCCESS, :END_OF_DATA].include?(err)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
return ret.string unless ret.nil?
|
376
|
+
end
|
377
|
+
|
378
|
+
def write(data)
|
379
|
+
bytes_written = 0
|
380
|
+
FFI::MemoryPointer.from_bytes(data) do |p_data|
|
381
|
+
FFI::MemoryPointer.new(:uint32) do |p_wlen|
|
382
|
+
while bytes_written < p_data.size
|
383
|
+
err = C.afc_file_write(@afcclient, @handle, p_data, p_data.size, p_wlen)
|
384
|
+
raise AFCError, "AFC error: #{err}" if err != :SUCCESS
|
385
|
+
|
386
|
+
wlen = p_wlen.read_uint32
|
387
|
+
p_data += wlen
|
388
|
+
bytes_written += wlen
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
return bytes_written
|
393
|
+
end
|
394
|
+
|
395
|
+
end
|
396
|
+
|
397
|
+
module C
|
398
|
+
ffi_lib 'imobiledevice'
|
399
|
+
|
400
|
+
typedef enum(
|
401
|
+
:SUCCESS , 0,
|
402
|
+
:UNKNOWN_ERROR , 1,
|
403
|
+
:OP_HEADER_INVALID , 2,
|
404
|
+
:NO_RESOURCES , 3,
|
405
|
+
:READ_ERROR , 4,
|
406
|
+
:WRITE_ERROR , 5,
|
407
|
+
:UNKNOWN_PACKET_TYPE , 6,
|
408
|
+
:INVALID_ARG , 7,
|
409
|
+
:OBJECT_NOT_FOUND , 8,
|
410
|
+
:OBJECT_IS_DIR , 9,
|
411
|
+
:PERM_DENIED , 10,
|
412
|
+
:SERVICE_NOT_CONNECTED, 11,
|
413
|
+
:OP_TIMEOUT , 12,
|
414
|
+
:TOO_MUCH_DATA , 13,
|
415
|
+
:END_OF_DATA , 14,
|
416
|
+
:OP_NOT_SUPPORTED , 15,
|
417
|
+
:OBJECT_EXISTS , 16,
|
418
|
+
:OBJECT_BUSY , 17,
|
419
|
+
:NO_SPACE_LEFT , 18,
|
420
|
+
:OP_WOULD_BLOCK , 19,
|
421
|
+
:IO_ERROR , 20,
|
422
|
+
:OP_INTERRUPTED , 21,
|
423
|
+
:OP_IN_PROGRESS , 22,
|
424
|
+
:INTERNAL_ERROR , 23,
|
425
|
+
|
426
|
+
:MUX_ERROR , 30,
|
427
|
+
:NO_MEM , 31,
|
428
|
+
:NOT_ENOUGH_DATA , 32,
|
429
|
+
:DIR_NOT_EMPTY , 33,
|
430
|
+
), :afc_error_t
|
431
|
+
|
432
|
+
typedef enum(
|
433
|
+
:RDONLY , 0x00000001, # r O_RDONLY
|
434
|
+
:RW , 0x00000002, # r+ O_RDWR | O_CREAT
|
435
|
+
:WRONLY , 0x00000003, # w O_WRONLY | O_CREAT | O_TRUNC
|
436
|
+
:WR , 0x00000004, # w+ O_RDWR | O_CREAT | O_TRUNC
|
437
|
+
:APPEND , 0x00000005, # a O_WRONLY | O_APPEND | O_CREAT
|
438
|
+
:RDAPPEND , 0x00000006, # a+ O_RDWR | O_APPEND | O_CREAT
|
439
|
+
), :afc_file_mode_t
|
440
|
+
|
441
|
+
typedef enum(
|
442
|
+
:HARDLINK , 1,
|
443
|
+
:SYMLINK , 2,
|
444
|
+
), :afc_link_type_t
|
445
|
+
|
446
|
+
typedef enum(
|
447
|
+
:SHARED, (1 | 4),
|
448
|
+
:EXCLUSIVE, (2 | 4),
|
449
|
+
:UNLOCK, (8 | 4),
|
450
|
+
), :afc_lock_op_t;
|
451
|
+
|
452
|
+
typedef enum( :SEEK_SET, :SEEK_CUR, :SEEK_END ), :whence_t
|
453
|
+
|
454
|
+
# afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t *client);
|
455
|
+
attach_function :afc_client_new, [Idevice, LockdownServiceDescriptor, :pointer], :afc_error_t
|
456
|
+
|
457
|
+
# afc_error_t afc_client_free(afc_client_t client);
|
458
|
+
attach_function :afc_client_free, [AFCClient], :afc_error_t
|
459
|
+
|
460
|
+
# afc_error_t afc_get_device_info(afc_client_t client, char ***infos);
|
461
|
+
attach_function :afc_get_device_info, [AFCClient, :pointer], :afc_error_t
|
462
|
+
|
463
|
+
# afc_error_t afc_read_directory(afc_client_t client, const char *dir, char ***list);
|
464
|
+
attach_function :afc_read_directory, [AFCClient, :string, :pointer], :afc_error_t
|
465
|
+
|
466
|
+
# afc_error_t afc_get_file_info(afc_client_t client, const char *filename, char ***infolist);
|
467
|
+
attach_function :afc_get_file_info, [AFCClient, :string, :pointer], :afc_error_t
|
468
|
+
|
469
|
+
# afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle);
|
470
|
+
attach_function :afc_file_open, [AFCClient, :string, :afc_file_mode_t, :pointer], :afc_error_t
|
471
|
+
|
472
|
+
# afc_error_t afc_file_close(afc_client_t client, uint64_t handle);
|
473
|
+
attach_function :afc_file_close, [AFCClient, :uint64], :afc_error_t
|
474
|
+
|
475
|
+
# afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation);
|
476
|
+
attach_function :afc_file_lock, [AFCClient, :uint64, :afc_lock_op_t], :afc_error_t
|
477
|
+
|
478
|
+
# afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read);
|
479
|
+
attach_function :afc_file_read, [AFCClient, :uint64, :pointer, :uint32, :pointer], :afc_error_t
|
480
|
+
|
481
|
+
# afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written);
|
482
|
+
attach_function :afc_file_write, [AFCClient, :uint64, :pointer, :uint32, :pointer], :afc_error_t
|
483
|
+
|
484
|
+
# afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence);
|
485
|
+
attach_function :afc_file_seek, [AFCClient, :uint64, :int64, :whence_t], :afc_error_t
|
486
|
+
|
487
|
+
# afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position);
|
488
|
+
attach_function :afc_file_tell, [AFCClient, :uint64, :pointer], :afc_error_t
|
489
|
+
|
490
|
+
# afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize);
|
491
|
+
attach_function :afc_file_truncate, [AFCClient, :uint64, :uint64], :afc_error_t
|
492
|
+
|
493
|
+
# afc_error_t afc_remove_path(afc_client_t client, const char *path);
|
494
|
+
attach_function :afc_remove_path, [AFCClient, :string], :afc_error_t
|
495
|
+
|
496
|
+
# afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to);
|
497
|
+
attach_function :afc_rename_path, [AFCClient, :string, :string], :afc_error_t
|
498
|
+
|
499
|
+
# afc_error_t afc_make_directory(afc_client_t client, const char *dir);
|
500
|
+
attach_function :afc_make_directory, [AFCClient, :string], :afc_error_t
|
501
|
+
|
502
|
+
# afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize);
|
503
|
+
attach_function :afc_truncate, [AFCClient, :string, :uint64], :afc_error_t
|
504
|
+
|
505
|
+
# afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname);
|
506
|
+
attach_function :afc_make_link, [AFCClient, :afc_link_type_t, :string, :string], :afc_error_t
|
507
|
+
|
508
|
+
# afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime);
|
509
|
+
attach_function :afc_set_file_time, [AFCClient, :string, :uint64], :afc_error_t
|
510
|
+
|
511
|
+
# afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value);
|
512
|
+
attach_function :afc_get_device_info_key, [AFCClient, :string, :pointer], :afc_error_t
|
513
|
+
|
514
|
+
#afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client);
|
515
|
+
attach_function :afc_client_new_from_house_arrest_client, [HouseArrestClient, :pointer], :afc_error_t
|
516
|
+
|
517
|
+
end
|
518
|
+
end
|