appium-ios-remotexpc 0.9.0 → 0.10.1
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.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -0
- package/build/src/services/index.d.ts +2 -1
- package/build/src/services/index.d.ts.map +1 -1
- package/build/src/services/index.js +2 -1
- package/build/src/services/ios/afc/codec.d.ts +46 -0
- package/build/src/services/ios/afc/codec.d.ts.map +1 -0
- package/build/src/services/ios/afc/codec.js +263 -0
- package/build/src/services/ios/afc/constants.d.ts +11 -0
- package/build/src/services/ios/afc/constants.d.ts.map +1 -0
- package/build/src/services/ios/afc/constants.js +22 -0
- package/build/src/services/ios/afc/enums.d.ts +66 -0
- package/build/src/services/ios/afc/enums.d.ts.map +1 -0
- package/build/src/services/ios/afc/enums.js +70 -0
- package/build/src/services/ios/afc/index.d.ts +72 -0
- package/build/src/services/ios/afc/index.d.ts.map +1 -0
- package/build/src/services/ios/afc/index.js +385 -0
- package/build/src/services/ios/afc/stream-utils.d.ts +14 -0
- package/build/src/services/ios/afc/stream-utils.d.ts.map +1 -0
- package/build/src/services/ios/afc/stream-utils.js +60 -0
- package/build/src/services.d.ts +6 -0
- package/build/src/services.d.ts.map +1 -1
- package/build/src/services.js +13 -0
- package/package.json +2 -1
- package/src/services/index.ts +2 -0
- package/src/services/ios/afc/codec.ts +365 -0
- package/src/services/ios/afc/constants.ts +29 -0
- package/src/services/ios/afc/enums.ts +70 -0
- package/src/services/ios/afc/index.ts +511 -0
- package/src/services/ios/afc/stream-utils.ts +102 -0
- package/src/services.ts +15 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
|
|
3
|
+
import { createPlist } from '../../../lib/plist/plist-creator.js';
|
|
4
|
+
import { parsePlist } from '../../../lib/plist/unified-plist-parser.js';
|
|
5
|
+
import { AFCMAGIC, AFC_HEADER_SIZE, NULL_BYTE } from './constants.js';
|
|
6
|
+
import { AfcError, AfcFopenMode, AfcOpcode } from './enums.js';
|
|
7
|
+
|
|
8
|
+
export interface AfcHeader {
|
|
9
|
+
magic: Buffer;
|
|
10
|
+
entireLength: bigint;
|
|
11
|
+
thisLength: bigint;
|
|
12
|
+
packetNum: bigint;
|
|
13
|
+
operation: bigint;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AfcResponse {
|
|
17
|
+
status: AfcError;
|
|
18
|
+
data: Buffer;
|
|
19
|
+
operation: AfcOpcode;
|
|
20
|
+
rawHeader: AfcHeader;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function writeUInt64LE(value: bigint | number): Buffer {
|
|
24
|
+
const buf = Buffer.alloc(8);
|
|
25
|
+
buf.writeBigUInt64LE(BigInt(value), 0);
|
|
26
|
+
return buf;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function readUInt64LE(buf: Buffer, offset = 0): bigint {
|
|
30
|
+
return buf.readBigUInt64LE(offset);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function cstr(str: string): Buffer {
|
|
34
|
+
const s = Buffer.from(str, 'utf8');
|
|
35
|
+
return Buffer.concat([s, NULL_BYTE]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function encodeHeader(
|
|
39
|
+
op: AfcOpcode,
|
|
40
|
+
packetNum: bigint,
|
|
41
|
+
payloadLen: number,
|
|
42
|
+
thisLenOverride?: number,
|
|
43
|
+
): Buffer {
|
|
44
|
+
const entireLen = BigInt(AFC_HEADER_SIZE + payloadLen);
|
|
45
|
+
const thisLen = BigInt(thisLenOverride ?? AFC_HEADER_SIZE + payloadLen);
|
|
46
|
+
|
|
47
|
+
const header = Buffer.alloc(AFC_HEADER_SIZE);
|
|
48
|
+
// magic
|
|
49
|
+
AFCMAGIC.copy(header, 0);
|
|
50
|
+
// entire_length
|
|
51
|
+
writeUInt64LE(entireLen).copy(header, 8);
|
|
52
|
+
// this_length
|
|
53
|
+
writeUInt64LE(thisLen).copy(header, 16);
|
|
54
|
+
// packet_num
|
|
55
|
+
writeUInt64LE(packetNum).copy(header, 24);
|
|
56
|
+
// operation
|
|
57
|
+
writeUInt64LE(BigInt(op)).copy(header, 32);
|
|
58
|
+
|
|
59
|
+
return header;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Internal per-socket buffered reader to avoid re-emitting data and race conditions.
|
|
64
|
+
*/
|
|
65
|
+
type SocketWaiter = {
|
|
66
|
+
n: number;
|
|
67
|
+
resolve: (buf: Buffer) => void;
|
|
68
|
+
reject: (err: Error) => void;
|
|
69
|
+
timer?: NodeJS.Timeout;
|
|
70
|
+
};
|
|
71
|
+
type SocketState = {
|
|
72
|
+
buffer: Buffer;
|
|
73
|
+
waiters: SocketWaiter[];
|
|
74
|
+
onData: (chunk: Buffer) => void;
|
|
75
|
+
onError: (err: Error) => void;
|
|
76
|
+
onClose: () => void;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const SOCKET_STATES = new WeakMap<net.Socket, SocketState>();
|
|
80
|
+
|
|
81
|
+
function cleanupSocketState(socket: net.Socket, error?: Error): void {
|
|
82
|
+
const state = SOCKET_STATES.get(socket);
|
|
83
|
+
if (!state) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Remove all event listeners to prevent memory leaks
|
|
88
|
+
socket.removeListener('data', state.onData);
|
|
89
|
+
socket.removeListener('error', state.onError);
|
|
90
|
+
socket.removeListener('close', state.onClose);
|
|
91
|
+
socket.removeListener('end', state.onClose);
|
|
92
|
+
|
|
93
|
+
// Reject any pending waiters
|
|
94
|
+
const err = error || new Error('Socket closed');
|
|
95
|
+
while (state.waiters.length) {
|
|
96
|
+
const w = state.waiters.shift()!;
|
|
97
|
+
if (w.timer) {
|
|
98
|
+
clearTimeout(w.timer);
|
|
99
|
+
}
|
|
100
|
+
w.reject(err);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Remove from WeakMap
|
|
104
|
+
SOCKET_STATES.delete(socket);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function ensureSocketState(socket: net.Socket): SocketState {
|
|
108
|
+
let state = SOCKET_STATES.get(socket);
|
|
109
|
+
if (state) {
|
|
110
|
+
return state;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
state = {
|
|
114
|
+
buffer: Buffer.alloc(0),
|
|
115
|
+
waiters: [],
|
|
116
|
+
onData: (chunk: Buffer) => {
|
|
117
|
+
const st = SOCKET_STATES.get(socket);
|
|
118
|
+
if (!st) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
st.buffer = Buffer.concat([st.buffer, chunk]);
|
|
122
|
+
|
|
123
|
+
while (st.waiters.length && st.buffer.length >= st.waiters[0].n) {
|
|
124
|
+
const w = st.waiters.shift()!;
|
|
125
|
+
const out = st.buffer.subarray(0, w.n);
|
|
126
|
+
st.buffer = st.buffer.subarray(w.n);
|
|
127
|
+
if (w.timer) {
|
|
128
|
+
clearTimeout(w.timer);
|
|
129
|
+
}
|
|
130
|
+
w.resolve(out);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
onError: (err: Error) => {
|
|
134
|
+
cleanupSocketState(socket, err);
|
|
135
|
+
},
|
|
136
|
+
onClose: () => {
|
|
137
|
+
cleanupSocketState(socket);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
socket.on('data', state.onData);
|
|
142
|
+
socket.once('error', state.onError);
|
|
143
|
+
socket.once('close', state.onClose);
|
|
144
|
+
socket.once('end', state.onClose);
|
|
145
|
+
SOCKET_STATES.set(socket, state);
|
|
146
|
+
return state;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function readExact(
|
|
150
|
+
socket: net.Socket,
|
|
151
|
+
n: number,
|
|
152
|
+
timeoutMs = 30000,
|
|
153
|
+
): Promise<Buffer> {
|
|
154
|
+
const state = ensureSocketState(socket);
|
|
155
|
+
|
|
156
|
+
if (state.buffer.length >= n) {
|
|
157
|
+
const out = state.buffer.subarray(0, n);
|
|
158
|
+
state.buffer = state.buffer.subarray(n);
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return await new Promise<Buffer>((resolve, reject) => {
|
|
163
|
+
const waiter: SocketWaiter = { n, resolve, reject };
|
|
164
|
+
state.waiters.push(waiter);
|
|
165
|
+
waiter.timer = setTimeout(() => {
|
|
166
|
+
const idx = state.waiters.indexOf(waiter);
|
|
167
|
+
if (idx >= 0) {
|
|
168
|
+
state.waiters.splice(idx, 1);
|
|
169
|
+
reject(new Error(`readExact timeout after ${timeoutMs}ms`));
|
|
170
|
+
}
|
|
171
|
+
}, timeoutMs);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export async function readAfcHeader(socket: net.Socket): Promise<AfcHeader> {
|
|
176
|
+
const buf = await readExact(socket, AFC_HEADER_SIZE);
|
|
177
|
+
const magic = buf.subarray(0, 8);
|
|
178
|
+
if (!magic.equals(AFCMAGIC)) {
|
|
179
|
+
throw new Error(`Invalid AFC magic: ${magic.toString('hex')}`);
|
|
180
|
+
}
|
|
181
|
+
const entireLength = readUInt64LE(buf, 8);
|
|
182
|
+
const thisLength = readUInt64LE(buf, 16);
|
|
183
|
+
const packetNum = readUInt64LE(buf, 24);
|
|
184
|
+
const operation = readUInt64LE(buf, 32);
|
|
185
|
+
return {
|
|
186
|
+
magic,
|
|
187
|
+
entireLength,
|
|
188
|
+
thisLength,
|
|
189
|
+
packetNum,
|
|
190
|
+
operation,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export async function readAfcResponse(
|
|
195
|
+
socket: net.Socket,
|
|
196
|
+
): Promise<AfcResponse> {
|
|
197
|
+
const header = await readAfcHeader(socket);
|
|
198
|
+
const payloadLen = Number(header.entireLength - BigInt(AFC_HEADER_SIZE));
|
|
199
|
+
const payload =
|
|
200
|
+
payloadLen > 0 ? await readExact(socket, payloadLen) : Buffer.alloc(0);
|
|
201
|
+
const op = Number(header.operation) as AfcOpcode;
|
|
202
|
+
|
|
203
|
+
if (op === AfcOpcode.STATUS) {
|
|
204
|
+
const status = Number(readUInt64LE(payload.subarray(0, 8))) as AfcError;
|
|
205
|
+
return { status, data: Buffer.alloc(0), operation: op, rawHeader: header };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
status: AfcError.SUCCESS,
|
|
210
|
+
data: payload,
|
|
211
|
+
operation: op,
|
|
212
|
+
rawHeader: header,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export async function sendAfcPacket(
|
|
217
|
+
socket: net.Socket,
|
|
218
|
+
op: AfcOpcode,
|
|
219
|
+
packetNum: bigint,
|
|
220
|
+
payload: Buffer = Buffer.alloc(0),
|
|
221
|
+
thisLenOverride?: number,
|
|
222
|
+
): Promise<void> {
|
|
223
|
+
const header = encodeHeader(op, packetNum, payload.length, thisLenOverride);
|
|
224
|
+
await new Promise<void>((resolve, reject) => {
|
|
225
|
+
socket.write(header, (err) => {
|
|
226
|
+
if (err) {
|
|
227
|
+
return reject(err);
|
|
228
|
+
}
|
|
229
|
+
if (payload.length) {
|
|
230
|
+
socket.write(payload, (err2) => {
|
|
231
|
+
if (err2) {
|
|
232
|
+
return reject(err2);
|
|
233
|
+
}
|
|
234
|
+
resolve();
|
|
235
|
+
});
|
|
236
|
+
} else {
|
|
237
|
+
resolve();
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function parseCStringArray(buf: Buffer): string[] {
|
|
244
|
+
const parts: string[] = [];
|
|
245
|
+
let start = 0;
|
|
246
|
+
for (let i = 0; i < buf.length; i++) {
|
|
247
|
+
if (buf[i] === 0x00) {
|
|
248
|
+
const slice = buf.subarray(start, i);
|
|
249
|
+
parts.push(slice.toString('utf8'));
|
|
250
|
+
start = i + 1;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (start < buf.length) {
|
|
254
|
+
parts.push(buf.subarray(start).toString('utf8'));
|
|
255
|
+
}
|
|
256
|
+
while (parts.length && parts[parts.length - 1] === '') {
|
|
257
|
+
parts.pop();
|
|
258
|
+
}
|
|
259
|
+
return parts;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function parseKeyValueNullList(buf: Buffer): Record<string, string> {
|
|
263
|
+
const arr = parseCStringArray(buf);
|
|
264
|
+
if (arr.length % 2 !== 0) {
|
|
265
|
+
throw new Error('Invalid key/value AFC list (odd number of entries)');
|
|
266
|
+
}
|
|
267
|
+
return Object.fromEntries(
|
|
268
|
+
Array.from({ length: arr.length / 2 }, (_, i) => [
|
|
269
|
+
arr[i * 2],
|
|
270
|
+
arr[i * 2 + 1],
|
|
271
|
+
]),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function buildFopenPayload(mode: AfcFopenMode, path: string): Buffer {
|
|
276
|
+
return Buffer.concat([writeUInt64LE(mode), cstr(path)]);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function buildReadPayload(
|
|
280
|
+
handle: bigint | number,
|
|
281
|
+
size: bigint | number,
|
|
282
|
+
): Buffer {
|
|
283
|
+
return Buffer.concat([writeUInt64LE(handle), writeUInt64LE(BigInt(size))]);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function buildClosePayload(handle: bigint | number): Buffer {
|
|
287
|
+
return writeUInt64LE(handle);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function buildRemovePayload(path: string): Buffer {
|
|
291
|
+
return cstr(path);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export function buildMkdirPayload(path: string): Buffer {
|
|
295
|
+
return cstr(path);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export function buildStatPayload(path: string): Buffer {
|
|
299
|
+
return cstr(path);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export function buildRenamePayload(src: string, dst: string): Buffer {
|
|
303
|
+
return Buffer.concat([cstr(src), cstr(dst)]);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export function buildLinkPayload(
|
|
307
|
+
type: number,
|
|
308
|
+
target: string,
|
|
309
|
+
source: string,
|
|
310
|
+
): Buffer {
|
|
311
|
+
return Buffer.concat([writeUInt64LE(type), cstr(target), cstr(source)]);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Receive a single length-prefixed plist from the socket
|
|
316
|
+
*/
|
|
317
|
+
export async function recvOnePlist(socket: net.Socket): Promise<any> {
|
|
318
|
+
const lenBuf = await readExact(socket, 4);
|
|
319
|
+
const respLen = lenBuf.readUInt32BE(0);
|
|
320
|
+
const respBody = await readExact(socket, respLen);
|
|
321
|
+
return parsePlist(respBody);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export async function rsdHandshakeForRawService(
|
|
325
|
+
socket: net.Socket,
|
|
326
|
+
): Promise<void> {
|
|
327
|
+
const request = {
|
|
328
|
+
Label: 'appium-internal',
|
|
329
|
+
ProtocolVersion: '2',
|
|
330
|
+
Request: 'RSDCheckin',
|
|
331
|
+
};
|
|
332
|
+
const xml = createPlist(request);
|
|
333
|
+
const body = Buffer.from(xml, 'utf8');
|
|
334
|
+
const header = Buffer.alloc(4);
|
|
335
|
+
header.writeUInt32BE(body.length, 0);
|
|
336
|
+
await new Promise<void>((resolve, reject) => {
|
|
337
|
+
socket.write(Buffer.concat([header, body]), (err) =>
|
|
338
|
+
err ? reject(err) : resolve(),
|
|
339
|
+
);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
const first = await recvOnePlist(socket);
|
|
343
|
+
if (!first || first.Request !== 'RSDCheckin') {
|
|
344
|
+
throw new Error(`Invalid RSDCheckin response: ${JSON.stringify(first)}`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const second = await recvOnePlist(socket);
|
|
348
|
+
if (!second || second.Request !== 'StartService') {
|
|
349
|
+
throw new Error(`Invalid StartService response: ${JSON.stringify(second)}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export function nextReadChunkSize(left: bigint | number): number {
|
|
354
|
+
const leftNum = typeof left === 'bigint' ? Number(left) : left;
|
|
355
|
+
return leftNum;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Convert nanoseconds to milliseconds for Date construction
|
|
360
|
+
* @param nanoseconds - Time value in nanoseconds as a string
|
|
361
|
+
* @returns Time value in milliseconds
|
|
362
|
+
*/
|
|
363
|
+
export function nanosecondsToMilliseconds(nanoseconds: string): number {
|
|
364
|
+
return Number(BigInt(nanoseconds) / 1000000n);
|
|
365
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { AfcFopenMode } from './enums.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AFC protocol constants
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Magic bytes at start of every AFC header
|
|
8
|
+
export const AFCMAGIC = Buffer.from('CFA6LPAA', 'ascii');
|
|
9
|
+
|
|
10
|
+
// IO chunk sizes
|
|
11
|
+
export const MAXIMUM_READ_SIZE = 4 * 1024 * 1024; // 4 MiB
|
|
12
|
+
|
|
13
|
+
// Mapping of textual fopen modes to AFC modes
|
|
14
|
+
export const AFC_FOPEN_TEXTUAL_MODES: Record<string, AfcFopenMode> = {
|
|
15
|
+
r: AfcFopenMode.RDONLY,
|
|
16
|
+
'r+': AfcFopenMode.RW,
|
|
17
|
+
w: AfcFopenMode.WRONLY,
|
|
18
|
+
'w+': AfcFopenMode.WR,
|
|
19
|
+
a: AfcFopenMode.APPEND,
|
|
20
|
+
'a+': AfcFopenMode.RDAPPEND,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Header size: magic (8) + entire_length (8) + this_length (8) + packet_num (8) + operation (8)
|
|
24
|
+
export const AFC_HEADER_SIZE = 40;
|
|
25
|
+
|
|
26
|
+
// Override for WRITE packets' this_length
|
|
27
|
+
export const AFC_WRITE_THIS_LENGTH = 48;
|
|
28
|
+
|
|
29
|
+
export const NULL_BYTE = Buffer.from([0]);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enums for AFC protocol as defined by Apple's AFC service
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export enum AfcOpcode {
|
|
6
|
+
STATUS = 0x00000001,
|
|
7
|
+
DATA = 0x00000002,
|
|
8
|
+
READ_DIR = 0x00000003,
|
|
9
|
+
REMOVE_PATH = 0x00000008,
|
|
10
|
+
MAKE_DIR = 0x00000009,
|
|
11
|
+
GET_FILE_INFO = 0x0000000a,
|
|
12
|
+
GET_DEVINFO = 0x0000000b,
|
|
13
|
+
FILE_OPEN = 0x0000000d,
|
|
14
|
+
READ = 0x0000000f,
|
|
15
|
+
WRITE = 0x00000010,
|
|
16
|
+
FILE_CLOSE = 0x00000014,
|
|
17
|
+
RENAME_PATH = 0x00000018,
|
|
18
|
+
MAKE_LINK = 0x0000001c,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export enum AfcError {
|
|
22
|
+
SUCCESS = 0,
|
|
23
|
+
UNKNOWN_ERROR = 1,
|
|
24
|
+
OP_HEADER_INVALID = 2,
|
|
25
|
+
NO_RESOURCES = 3,
|
|
26
|
+
READ_ERROR = 4,
|
|
27
|
+
WRITE_ERROR = 5,
|
|
28
|
+
UNKNOWN_PACKET_TYPE = 6,
|
|
29
|
+
INVALID_ARG = 7,
|
|
30
|
+
OBJECT_NOT_FOUND = 8,
|
|
31
|
+
OBJECT_IS_DIR = 9,
|
|
32
|
+
PERM_DENIED = 10,
|
|
33
|
+
SERVICE_NOT_CONNECTED = 11,
|
|
34
|
+
OP_TIMEOUT = 12,
|
|
35
|
+
TOO_MUCH_DATA = 13,
|
|
36
|
+
END_OF_DATA = 14,
|
|
37
|
+
OP_NOT_SUPPORTED = 15,
|
|
38
|
+
OBJECT_EXISTS = 16,
|
|
39
|
+
OBJECT_BUSY = 17,
|
|
40
|
+
NO_SPACE_LEFT = 18,
|
|
41
|
+
OP_WOULD_BLOCK = 19,
|
|
42
|
+
IO_ERROR = 20,
|
|
43
|
+
OP_INTERRUPTED = 21,
|
|
44
|
+
OP_IN_PROGRESS = 22,
|
|
45
|
+
INTERNAL_ERROR = 23,
|
|
46
|
+
MUX_ERROR = 30,
|
|
47
|
+
NO_MEM = 31,
|
|
48
|
+
NOT_ENOUGH_DATA = 32,
|
|
49
|
+
DIR_NOT_EMPTY = 33,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export enum AfcLinkType {
|
|
53
|
+
HARDLINK = 1,
|
|
54
|
+
SYMLINK = 2,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export enum AfcFopenMode {
|
|
58
|
+
RDONLY = 0x00000001, // 'r'
|
|
59
|
+
RW = 0x00000002, // 'r+'
|
|
60
|
+
WRONLY = 0x00000003, // 'w'
|
|
61
|
+
WR = 0x00000004, // 'w+'
|
|
62
|
+
APPEND = 0x00000005, // 'a'
|
|
63
|
+
RDAPPEND = 0x00000006, // 'a+'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export enum AfcFileMode {
|
|
67
|
+
S_IFDIR = 'S_IFDIR',
|
|
68
|
+
S_IFREG = 'S_IFREG',
|
|
69
|
+
S_IFLNK = 'S_IFLNK',
|
|
70
|
+
}
|