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,152 @@
|
|
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/plist'
|
23
|
+
require 'idevice/idevice'
|
24
|
+
require 'idevice/lockdown'
|
25
|
+
|
26
|
+
module Idevice
|
27
|
+
class SbservicesError < IdeviceLibError
|
28
|
+
end
|
29
|
+
|
30
|
+
SBSError = SbservicesError
|
31
|
+
|
32
|
+
class SbservicesClient < C::ManagedOpaquePointer
|
33
|
+
include LibHelpers
|
34
|
+
|
35
|
+
def self.release(ptr)
|
36
|
+
C.sbservices_client_free(ptr) unless ptr.null?
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.attach(opts={})
|
40
|
+
_attach_helper("com.apple.springboardservices", opts) do |idevice, ldsvc, p_sbs|
|
41
|
+
err = C.sbservices_client_new(idevice, ldsvc, p_sbs)
|
42
|
+
raise SbservicesError, "Springboard Services Error: #{err}" if err != :SUCCESS
|
43
|
+
|
44
|
+
sbs = p_sbs.read_pointer
|
45
|
+
raise SBSError, "sbservices_client_new returned a NULL client" if sbs.null?
|
46
|
+
return new(sbs)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_icon_state
|
51
|
+
FFI::MemoryPointer.new(:pointer) do |p_state|
|
52
|
+
err = C.sbservices_get_icon_state(self, p_state, nil)
|
53
|
+
raise SbservicesError, "Springboard Services Error: #{err}" if err != :SUCCESS
|
54
|
+
return p_state.read_pointer.read_plist_t
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_icon_state(newstate)
|
59
|
+
err = C.sbservices_set_icon_state(self, Plist_t.from_ruby(newstate))
|
60
|
+
raise SbservicesError, "Springboard Services Error: #{err}" if err != :SUCCESS
|
61
|
+
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_icon_pngdata(bundleid)
|
66
|
+
FFI::MemoryPointer.new(:pointer) do |p_pngdata|
|
67
|
+
FFI::MemoryPointer.new(:uint64) do |p_pngsize|
|
68
|
+
err = C.sbservices_get_icon_pngdata(self, bundleid, p_pngdata, p_pngsize)
|
69
|
+
raise SbservicesError, "Springboard Services Error: #{err}" if err != :SUCCESS
|
70
|
+
|
71
|
+
pngdata = p_pngdata.read_pointer
|
72
|
+
unless pngdata.null?
|
73
|
+
ret=pngdata.read_bytes(p_pngsize.read_uint64)
|
74
|
+
C.free(pngdata)
|
75
|
+
return ret
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
INTERFACE_ORIENTATIONS = [
|
82
|
+
:UNKNOWN, # => 0,
|
83
|
+
:PORTRAIT, # => 1,
|
84
|
+
:PORTRAIT_UPSIDE_DOWN, # => 2,
|
85
|
+
:LANDSCAPE_RIGHT, # => 3,
|
86
|
+
:LANDSCAPE_LEFT, # => 4,
|
87
|
+
]
|
88
|
+
|
89
|
+
def get_interface_orientation
|
90
|
+
FFI::MemoryPointer.new(:int) do |p_orientation|
|
91
|
+
err = C.sbservices_get_interface_orientation(self, p_orientation)
|
92
|
+
raise SbservicesError, "Springboard Services Error: #{err}" if err != :SUCCESS
|
93
|
+
|
94
|
+
orientation = p_orientation.read_int
|
95
|
+
return (INTERFACE_ORIENTATIONS[orientation] or orientation)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_home_screen_wallpaper_pngdata
|
100
|
+
FFI::MemoryPointer.new(:pointer) do |p_pngdata|
|
101
|
+
FFI::MemoryPointer.new(:uint64) do |p_pngsize|
|
102
|
+
err = C.sbservices_get_home_screen_wallpaper_pngdata(self, p_pngdata, p_pngsize)
|
103
|
+
raise SbservicesError, "Springboard Services Error: #{err}" if err != :SUCCESS
|
104
|
+
|
105
|
+
pngdata = p_pngdata.read_pointer
|
106
|
+
unless pngdata.null?
|
107
|
+
ret=pngdata.read_bytes(p_pngsize.read_uint64)
|
108
|
+
C.free(pngdata)
|
109
|
+
return ret
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
SBSClient = SbservicesClient
|
118
|
+
|
119
|
+
module C
|
120
|
+
ffi_lib 'imobiledevice'
|
121
|
+
|
122
|
+
typedef enum(
|
123
|
+
:SUCCESS , 0,
|
124
|
+
:INVALID_ARG , -1,
|
125
|
+
:PLIST_ERROR , -2,
|
126
|
+
:CONN_FAILED , -3,
|
127
|
+
:UNKNOWN_ERROR, -256,
|
128
|
+
), :sbservices_error_t
|
129
|
+
|
130
|
+
#sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t service, sbservices_client_t *client);
|
131
|
+
attach_function :sbservices_client_new, [Idevice, LockdownServiceDescriptor, :pointer], :sbservices_error_t
|
132
|
+
|
133
|
+
#sbservices_error_t sbservices_client_free(sbservices_client_t client);
|
134
|
+
attach_function :sbservices_client_free, [SBSClient], :sbservices_error_t
|
135
|
+
|
136
|
+
#sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state, const char *format_version);
|
137
|
+
attach_function :sbservices_get_icon_state, [SBSClient, :pointer, :string], :sbservices_error_t
|
138
|
+
|
139
|
+
#sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate);
|
140
|
+
attach_function :sbservices_set_icon_state, [SBSClient, Plist_t], :sbservices_error_t
|
141
|
+
|
142
|
+
#sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize);
|
143
|
+
attach_function :sbservices_get_icon_pngdata, [SBSClient, :string, :pointer, :pointer], :sbservices_error_t
|
144
|
+
|
145
|
+
#sbservices_error_t sbservices_get_interface_orientation(sbservices_client_t client, sbservices_interface_orientation_t* interface_orientation);
|
146
|
+
attach_function :sbservices_get_interface_orientation, [SBSClient, :pointer], :sbservices_error_t
|
147
|
+
|
148
|
+
#sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize);
|
149
|
+
attach_function :sbservices_get_home_screen_wallpaper_pngdata, [SBSClient, :pointer, :pointer], :sbservices_error_t
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,88 @@
|
|
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
|
+
|
25
|
+
module Idevice
|
26
|
+
|
27
|
+
class ScreenShotrError < IdeviceLibError
|
28
|
+
end
|
29
|
+
|
30
|
+
class ScreenShotrClient < C::ManagedOpaquePointer
|
31
|
+
include LibHelpers
|
32
|
+
|
33
|
+
def self.release(ptr)
|
34
|
+
C.screenshotr_client_free(ptr) unless ptr.null?
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.attach(opts={})
|
38
|
+
_attach_helper("com.apple.mobile.screenshotr", opts) do |idevice, ldsvc, p_ss|
|
39
|
+
err = C.screenshotr_client_new(idevice, ldsvc, p_ss)
|
40
|
+
raise ScreenShotrError, "ScreenShotr Error: #{err}" if err != :SUCCESS
|
41
|
+
|
42
|
+
ss = p_ss.read_pointer
|
43
|
+
raies ScreenShotrError, "screenshotr_client_new returned a NULL client" if ss.null?
|
44
|
+
return new(ss)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def take_screenshot
|
49
|
+
FFI::MemoryPointer.new(:pointer) do |p_imgdata|
|
50
|
+
FFI::MemoryPointer.new(:uint64) do |p_imgsize|
|
51
|
+
err = C.screenshotr_take_screenshot(self, p_imgdata, p_imgsize)
|
52
|
+
raise ScreenShotrError, "ScreenShotr Error: #{err}" if err != :SUCCESS
|
53
|
+
|
54
|
+
imgdata = p_imgdata.read_pointer
|
55
|
+
unless imgdata.null?
|
56
|
+
ret=imgdata.read_bytes(p_imgsize.read_uint64)
|
57
|
+
C.free(imgdata)
|
58
|
+
return ret
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module C
|
66
|
+
ffi_lib 'imobiledevice'
|
67
|
+
|
68
|
+
typedef enum(
|
69
|
+
:SUCCESS , 0,
|
70
|
+
:INVALID_ARG , -1,
|
71
|
+
:PLIST_ERROR , -2,
|
72
|
+
:MUX_ERROR , -3,
|
73
|
+
:BAD_VERSION , -4,
|
74
|
+
:UNKNOWN_ERROR, -256,
|
75
|
+
), :screenshotr_error_t
|
76
|
+
|
77
|
+
#screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t service, screenshotr_client_t * client);
|
78
|
+
attach_function :screenshotr_client_new, [Idevice, LockdownServiceDescriptor, :pointer], :screenshotr_error_t
|
79
|
+
|
80
|
+
#screenshotr_error_t screenshotr_client_free(screenshotr_client_t client);
|
81
|
+
attach_function :screenshotr_client_free, [ScreenShotrClient], :screenshotr_error_t
|
82
|
+
|
83
|
+
#screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize);
|
84
|
+
attach_function :screenshotr_take_screenshot, [ScreenShotrClient, :pointer, :pointer], :screenshotr_error_t
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
@@ -0,0 +1,96 @@
|
|
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/plist'
|
23
|
+
require 'idevice/idevice'
|
24
|
+
require 'idevice/lockdown'
|
25
|
+
|
26
|
+
module Idevice
|
27
|
+
class WebInspectorError < IdeviceLibError
|
28
|
+
end
|
29
|
+
|
30
|
+
class WebInspectorClient < C::ManagedOpaquePointer
|
31
|
+
include LibHelpers
|
32
|
+
|
33
|
+
def self.release(ptr)
|
34
|
+
C.webinspector_client_free(ptr) unless ptr.null?
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.attach(opts={})
|
38
|
+
_attach_helper("com.apple.webinspector", opts) do |idevice, ldsvc, p_wic|
|
39
|
+
err = C.webinspector_client_new(idevice, ldsvc, p_wic)
|
40
|
+
raise WebInspectorError, "WebInspector error: #{err}" if err != :SUCCESS
|
41
|
+
|
42
|
+
wic = p_wic.read_pointer
|
43
|
+
raise WebInspectorError, "webinspector_client_new returned a NULL client" if wic.null?
|
44
|
+
|
45
|
+
return new(wic)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def send_plist(obj)
|
50
|
+
err = C.webinspector_send(self, Plist_t.from_ruby(obj))
|
51
|
+
raise WebInspectorError, "WebInspector error: #{err}" if err != :SUCCESS
|
52
|
+
return true
|
53
|
+
end
|
54
|
+
|
55
|
+
def receive_plist
|
56
|
+
FFI::MemoryPointer.new(:pointer) do |p_plist|
|
57
|
+
err = C.webinspector_receive(self, p_plist)
|
58
|
+
raise WebInspectorError, "WebInspector error: #{err}" if err != :SUCCESS
|
59
|
+
return p_plist.to_pointer.to_plist_t
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module C
|
65
|
+
|
66
|
+
typedef enum(
|
67
|
+
:SUCCESS , 0,
|
68
|
+
:INVALID_ARG , -1,
|
69
|
+
:PLIST_ERROR , -2,
|
70
|
+
:MUX_ERROR , -3,
|
71
|
+
:SSL_ERROR , -4,
|
72
|
+
:UNKNOWN_ERROR, -256,
|
73
|
+
), :webinspector_error_t
|
74
|
+
|
75
|
+
#webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service_descriptor_t service, webinspector_client_t * client);
|
76
|
+
attach_function :webinspector_client_new, [Idevice, LockdownServiceDescriptor, :pointer], :webinspector_error_t
|
77
|
+
|
78
|
+
#webinspector_error_t webinspector_client_start_service(idevice_t device, webinspector_client_t * client, const char* label);
|
79
|
+
attach_function :webinspector_client_start_service, [Idevice, :pointer, :string], :webinspector_error_t
|
80
|
+
|
81
|
+
#webinspector_error_t webinspector_client_free(webinspector_client_t client);
|
82
|
+
attach_function :webinspector_client_free, [WebInspectorClient], :webinspector_error_t
|
83
|
+
|
84
|
+
#webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist);
|
85
|
+
attach_function :webinspector_send, [WebInspectorClient, Plist_t], :webinspector_error_t
|
86
|
+
|
87
|
+
#webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t * plist);
|
88
|
+
attach_function :webinspector_receive, [WebInspectorClient, :pointer], :webinspector_error_t
|
89
|
+
|
90
|
+
#webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms);
|
91
|
+
attach_function :webinspector_receive_with_timeout, [WebInspectorClient, :pointer, :uint32], :webinspector_error_t
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
@@ -0,0 +1,409 @@
|
|
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_relative 'spec_helper'
|
22
|
+
require 'time'
|
23
|
+
|
24
|
+
describe Idevice::AFCClient do
|
25
|
+
before :all do
|
26
|
+
@fromfile = sample_file("plist.bin")
|
27
|
+
end
|
28
|
+
|
29
|
+
before :each do
|
30
|
+
@afc = Idevice::AFCClient.attach(idevice:shared_idevice)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should attach" do
|
34
|
+
@afc.should be_a Idevice::AFCClient
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return device info" do
|
38
|
+
result = @afc.device_info
|
39
|
+
result.should be_a Hash
|
40
|
+
result.keys.sort.should == [:FSBlockSize, :FSFreeBytes, :FSTotalBytes, :Model]
|
41
|
+
result[:FSBlockSize].should =~ /^\d+$/
|
42
|
+
result[:FSFreeBytes].should =~ /^\d+$/
|
43
|
+
result[:FSTotalBytes].should =~ /^\d+$/
|
44
|
+
result[:FSTotalBytes].to_i.should > result["FSFreeBytes"].to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return device info for specific keys" do
|
48
|
+
totbytes = @afc.device_info("FSTotalBytes")
|
49
|
+
totbytes.should be_a String
|
50
|
+
totbytes.should =~ /^\d+$/
|
51
|
+
|
52
|
+
freebytes = @afc.device_info("FSFreeBytes")
|
53
|
+
freebytes.should be_a String
|
54
|
+
freebytes.should =~ /^\d+$/
|
55
|
+
|
56
|
+
totbytes.to_i.should > freebytes.to_i
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should list directory contents" do
|
60
|
+
result = @afc.read_directory('/')
|
61
|
+
result.should be_a Array
|
62
|
+
result[0,2].should == ['.', '..']
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should raise an error listing an invalid directory" do
|
66
|
+
lambda{ @afc.read_directory('/TOTALLYNOTREALLYTHERE') }.should raise_error(Idevice::AFCError)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should get file information" do
|
70
|
+
result = @afc.file_info('/')
|
71
|
+
result.should be_a Hash
|
72
|
+
result.keys.sort.should == [:st_birthtime, :st_blocks, :st_ifmt, :st_mtime, :st_nlink, :st_size]
|
73
|
+
result[:st_ifmt].should == :S_IFDIR
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should raise an error getting info for an invalid path" do
|
77
|
+
lambda{ @afc.file_info('/TOTALLYNOTREALLYTHERE') }.should raise_error(Idevice::AFCError)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should remove a file path" do
|
81
|
+
remotepath='TOTALLYATESTFILECREATEDTEST'
|
82
|
+
|
83
|
+
@afc.put_path(@fromfile.to_s, remotepath).should == @fromfile.size
|
84
|
+
@afc.remove_path(remotepath).should be_true
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should remove an (empty) directory path" do
|
88
|
+
remotepath='TOTALLYATESTDIRCREATEDTEST'
|
89
|
+
@afc.make_directory(remotepath).should be_true
|
90
|
+
@afc.remove_path(remotepath).should be_true
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should rename a file path" do
|
94
|
+
remotepath='TOTALLYATESTFILECREATEDTEST'
|
95
|
+
renamepath = remotepath+'2'
|
96
|
+
|
97
|
+
begin
|
98
|
+
@afc.put_path(@fromfile.to_s, remotepath).should == @fromfile.size
|
99
|
+
originfo = @afc.file_info(remotepath)
|
100
|
+
@afc.rename_path(remotepath, renamepath).should be_true
|
101
|
+
lambda{ @afc.file_info(remotepath) }.should raise_error Idevice::AFCError
|
102
|
+
info = @afc.file_info(renamepath)
|
103
|
+
info.should == originfo
|
104
|
+
ensure
|
105
|
+
@afc.remove_path(remotepath) rescue nil
|
106
|
+
@afc.remove_path(renamepath).should be_true
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should rename a directory path" do
|
112
|
+
remotepath = 'TOTALLYATESTDIRCREATEDTEST'
|
113
|
+
renamepath = remotepath+'2'
|
114
|
+
begin
|
115
|
+
@afc.make_directory(remotepath).should be_true
|
116
|
+
originfo = @afc.file_info(remotepath)
|
117
|
+
@afc.rename_path(remotepath, renamepath).should be_true
|
118
|
+
lambda{ @afc.file_info(remotepath) }.should raise_error Idevice::AFCError
|
119
|
+
info = @afc.file_info(renamepath)
|
120
|
+
info.should == originfo
|
121
|
+
ensure
|
122
|
+
@afc.remove_path(remotepath) rescue nil
|
123
|
+
@afc.remove_path(renamepath).should be_true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should make a directory" do
|
128
|
+
remotepath = 'TOTALLYATESTDIR'
|
129
|
+
begin
|
130
|
+
@afc.make_directory(remotepath).should be_true
|
131
|
+
result = @afc.file_info(remotepath)
|
132
|
+
result[:st_ifmt].should == :S_IFDIR
|
133
|
+
ensure
|
134
|
+
@afc.remove_path(remotepath) rescue nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should make a symbolic link to a directory" do
|
139
|
+
begin
|
140
|
+
@afc.symlink('.', 'TOTALLYATESTSYMLINKTOCURRENTDIR').should be_true
|
141
|
+
result = @afc.file_info('TOTALLYATESTSYMLINKTOCURRENTDIR')
|
142
|
+
result[:st_ifmt].should == :S_IFLNK
|
143
|
+
ensure
|
144
|
+
@afc.remove_path('TOTALLYATESTSYMLINKTOCURRENTDIR') rescue nil
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should make a symbolic link to a file" do
|
149
|
+
remotefile = 'TOTALLYATESTFILE3'
|
150
|
+
remotelink = 'TOTEALLYATESTSYMLINK3'
|
151
|
+
|
152
|
+
begin
|
153
|
+
@afc.touch(remotefile).should be_true
|
154
|
+
@afc.symlink(remotefile, remotelink).should be_true
|
155
|
+
@afc.file_info(remotefile)[:st_ifmt].should == :S_IFREG
|
156
|
+
@afc.file_info(remotelink)[:st_ifmt].should == :S_IFLNK
|
157
|
+
|
158
|
+
# opening a symlinked file via AFC seems to give PERM_DENIED ?
|
159
|
+
#@afc.open(remotelink,'a'){|f| f.write("meep") }
|
160
|
+
#@afc.cat(remotefile).should == "meep"
|
161
|
+
|
162
|
+
#@afc.file_info(remotefile)[:st_ifmt].should == :S_IFREG
|
163
|
+
#@afc.file_info(remotelink)[:st_ifmt].should == :S_IFLNK
|
164
|
+
ensure
|
165
|
+
@afc.remove_path(remotefile) rescue nil
|
166
|
+
@afc.remove_path(remotelink) rescue nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should make a hard link to a file" do
|
171
|
+
remotefile = 'TOTALLYATESTFILE2'
|
172
|
+
remotelink = 'TOTEALLYATESTHARDLINK'
|
173
|
+
|
174
|
+
begin
|
175
|
+
@afc.touch(remotefile).should be_true
|
176
|
+
@afc.hardlink(remotefile, remotelink).should be_true
|
177
|
+
@afc.file_info(remotefile)[:st_ifmt].should == :S_IFREG
|
178
|
+
@afc.file_info(remotelink)[:st_ifmt].should == :S_IFREG
|
179
|
+
|
180
|
+
@afc.open(remotelink,'a'){|f| f.write("meep") }
|
181
|
+
@afc.cat(remotefile).should == "meep"
|
182
|
+
|
183
|
+
@afc.file_info(remotefile)[:st_ifmt].should == :S_IFREG
|
184
|
+
@afc.file_info(remotelink)[:st_ifmt].should == :S_IFREG
|
185
|
+
ensure
|
186
|
+
@afc.remove_path(remotefile) rescue nil
|
187
|
+
@afc.remove_path(remotelink) rescue nil
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should raise an error removing a non-existent path" do
|
192
|
+
lambda{ @afc.remove_path('TOTALLYNOTREALLYTHERE') }.should raise_error(Idevice::AFCError)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should put a file and cat it" do
|
196
|
+
remotepath = 'TESTFILEUPLOAD'
|
197
|
+
|
198
|
+
begin
|
199
|
+
@afc.put_path(@fromfile.to_s, remotepath).should == @fromfile.size
|
200
|
+
@afc.cat(remotepath).should == @fromfile.read()
|
201
|
+
ensure
|
202
|
+
@afc.remove_path(remotepath) rescue nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should put a file and cat it with a small chunk size" do
|
207
|
+
remotepath = 'TESTFILEUPLOAD'
|
208
|
+
|
209
|
+
begin
|
210
|
+
gotblock=false
|
211
|
+
@afc.put_path(@fromfile.to_s, remotepath, 2) do |chunksz|
|
212
|
+
gotblock=true
|
213
|
+
(0..2).should include(chunksz)
|
214
|
+
end.should == @fromfile.size
|
215
|
+
gotblock.should be_true
|
216
|
+
|
217
|
+
catsize = 0
|
218
|
+
catbuf = StringIO.new
|
219
|
+
gotblock=false
|
220
|
+
|
221
|
+
@afc.cat(remotepath, 2) do |chunk|
|
222
|
+
catbuf << chunk
|
223
|
+
catsize += chunk.size
|
224
|
+
gotblock=true
|
225
|
+
(0..2).should include(chunk.size)
|
226
|
+
end
|
227
|
+
|
228
|
+
catsize.should == @fromfile.size
|
229
|
+
catbuf.string.should == @fromfile.read()
|
230
|
+
gotblock.should be_true
|
231
|
+
ensure
|
232
|
+
@afc.remove_path(remotepath) rescue nil
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should get a file" do
|
237
|
+
tmpfile = Tempfile.new('TESTFILEUPLOADFORGETlocal')
|
238
|
+
tmppath = tmpfile.path
|
239
|
+
tmpfile.close
|
240
|
+
remotepath = 'TESTFILEUPLOADFORGET'
|
241
|
+
begin
|
242
|
+
@afc.put_path(@fromfile.to_s, remotepath).should == @fromfile.size
|
243
|
+
@afc.getpath(remotepath, tmppath).should == @fromfile.size
|
244
|
+
File.read(tmppath).should == @fromfile.read()
|
245
|
+
ensure
|
246
|
+
@afc.remove_path(remotepath) rescue nil
|
247
|
+
File.unlink(tmppath)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should truncate a file path" do
|
252
|
+
remotepath = 'TESTFILEUPLOADFORTRUNCATE'
|
253
|
+
|
254
|
+
begin
|
255
|
+
(@fromfile.size > 10).should be_true
|
256
|
+
@afc.put_path(@fromfile.to_s, remotepath).should == @fromfile.size
|
257
|
+
@afc.size(remotepath).should == @fromfile.size
|
258
|
+
@afc.truncate(remotepath, 10).should be_true
|
259
|
+
@afc.size(remotepath).should == 10
|
260
|
+
ensure
|
261
|
+
@afc.remove_path(remotepath) rescue nil
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should get file mtime" do
|
266
|
+
res = @afc.mtime('.')
|
267
|
+
res.should be_a Time
|
268
|
+
# between first iphone release and 30-sec from now
|
269
|
+
res.should > Time.parse("June 29, 2007")
|
270
|
+
res.should < (Time.now+30)
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should get file ctime" do
|
274
|
+
res = @afc.mtime('.')
|
275
|
+
res.should be_a Time
|
276
|
+
# between first iphone release and 30-sec from now
|
277
|
+
res.should > Time.parse("June 29, 2007")
|
278
|
+
res.should < (Time.now+30)
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should touch a file" do
|
282
|
+
remotefile = "TESTFILETOUCH"
|
283
|
+
begin
|
284
|
+
@afc.touch(remotefile).should be_true
|
285
|
+
@afc.cat(remotefile).should == ""
|
286
|
+
@afc.ctime(remotefile).should == @afc.mtime(remotefile)
|
287
|
+
ensure
|
288
|
+
@afc.remove_path(remotefile) rescue nil
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should set file time" do
|
293
|
+
remotefile = "TESTINGFILETIMESETTING"
|
294
|
+
settime = Time.parse("June 29, 2007 4:20 UTC")
|
295
|
+
begin
|
296
|
+
@afc.touch(remotefile).should be_true
|
297
|
+
@afc.ctime(remotefile).should_not == settime
|
298
|
+
@afc.mtime(remotefile).should_not == settime
|
299
|
+
|
300
|
+
@afc.set_file_time(remotefile, settime).should be_true
|
301
|
+
@afc.ctime(remotefile).should == settime
|
302
|
+
@afc.mtime(remotefile).should == settime
|
303
|
+
ensure
|
304
|
+
@afc.remove_path(remotefile) rescue nil
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should open a file and read all its contents" do
|
309
|
+
remotepath = 'TESTFILEUPLOADFOROPENANDREAD'
|
310
|
+
|
311
|
+
begin
|
312
|
+
@afc.put_path(@fromfile.to_s, remotepath).should == @fromfile.size
|
313
|
+
dat = @afc.open(remotepath, 'r') { |f| f.read() }
|
314
|
+
dat.should == @fromfile.read()
|
315
|
+
ensure
|
316
|
+
@afc.remove_path(remotepath) rescue nil
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should open a file and read a few bytes from it" do
|
321
|
+
remotepath = 'TESTFILEUPLOADFOROPENANDREAD'
|
322
|
+
|
323
|
+
begin
|
324
|
+
@afc.put_path(@fromfile.to_s, remotepath).should == @fromfile.size
|
325
|
+
@afc.open(remotepath, 'r') do |f|
|
326
|
+
f.read(6).should == "bplist"
|
327
|
+
end
|
328
|
+
ensure
|
329
|
+
@afc.remove_path(remotepath) rescue nil
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should open a file skip ahead a few bytes offset and read from it" do
|
334
|
+
remotepath = 'TESTFILEUPLOADFOROPENANDREADOFFSET'
|
335
|
+
|
336
|
+
begin
|
337
|
+
@afc.put_path(@fromfile.to_s, remotepath).should == @fromfile.size
|
338
|
+
@afc.open(remotepath, 'r') do |f|
|
339
|
+
f.pos=2
|
340
|
+
f.read(4).should == "list"
|
341
|
+
end
|
342
|
+
ensure
|
343
|
+
@afc.remove_path(remotepath) rescue nil
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
it "should open a file and write to it" do
|
348
|
+
remotepath = 'TESTFILEUPLOADFOROPENANDWRITE'
|
349
|
+
testdata = "hellotest"
|
350
|
+
|
351
|
+
begin
|
352
|
+
@afc.open(remotepath, 'w') do |f|
|
353
|
+
f.write(testdata).should == testdata.size
|
354
|
+
end
|
355
|
+
@afc.cat(remotepath).should == testdata
|
356
|
+
ensure
|
357
|
+
@afc.remove_path(remotepath) rescue nil
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should open a file and append to it" do
|
362
|
+
remotepath = 'TESTFILEUPLOADFOROPENANDAPEND'
|
363
|
+
testdata = "hellotest"
|
364
|
+
|
365
|
+
begin
|
366
|
+
@afc.open(remotepath, 'w') do |f|
|
367
|
+
f.write(testdata).should == testdata.size
|
368
|
+
end
|
369
|
+
@afc.cat(remotepath).should == testdata
|
370
|
+
@afc.open(remotepath, 'a') do |f|
|
371
|
+
f.pos.should == 0
|
372
|
+
f.pos+= testdata.size
|
373
|
+
f.pos.should == testdata.size
|
374
|
+
f.write(testdata).should == testdata.size
|
375
|
+
end
|
376
|
+
@afc.cat(remotepath).should == testdata + testdata
|
377
|
+
ensure
|
378
|
+
@afc.remove_path(remotepath) rescue nil
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
it "should open a file jump around positions and read/write to it" do
|
383
|
+
remotepath = 'TESTFILEUPLOADFOROPENANDWRITE'
|
384
|
+
testdata = "hellotest"
|
385
|
+
|
386
|
+
begin
|
387
|
+
@afc.open(remotepath, 'w') do |f|
|
388
|
+
f.write(testdata).should == testdata.size
|
389
|
+
end
|
390
|
+
@afc.open(remotepath, 'r+') do |f|
|
391
|
+
f.pos.should == 0
|
392
|
+
f.read().should == testdata
|
393
|
+
f.pos.should == testdata.size
|
394
|
+
f.rewind
|
395
|
+
f.pos.should == 0
|
396
|
+
f.seek(0, :SEEK_END)
|
397
|
+
f.pos.should == testdata.size
|
398
|
+
f.write(testdata).should == testdata.size
|
399
|
+
f.pos.should == testdata.size*2
|
400
|
+
f.rewind
|
401
|
+
f.read().should == testdata*2
|
402
|
+
end
|
403
|
+
@afc.cat(remotepath).should == testdata*2
|
404
|
+
ensure
|
405
|
+
@afc.remove_path(remotepath) rescue nil
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
end
|