mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-04-05 04:59:05 +08:00
use libarchive (#134)
This commit is contained in:
@@ -435,6 +435,7 @@ echo "[7/7] Installing LaunchDaemons..."
|
||||
VPHONED_SRC="$SCRIPT_DIR/vphoned"
|
||||
VPHONED_BIN="$VPHONED_SRC/vphoned"
|
||||
VPHONED_SRCS=(
|
||||
"$VPHONED_SRC/unarchive.m"
|
||||
"$VPHONED_SRC/vphoned.m"
|
||||
"$VPHONED_SRC/vphoned_install.m"
|
||||
"$VPHONED_SRC/vphoned_protocol.m"
|
||||
@@ -458,7 +459,9 @@ if [[ "$needs_vphoned_build" == "1" ]]; then
|
||||
echo " Building vphoned for arm64..."
|
||||
xcrun -sdk iphoneos clang -arch arm64 -Os -fobjc-arc \
|
||||
-I"$VPHONED_SRC" \
|
||||
-I"$VPHONED_SRC/vendor/libarchive" \
|
||||
-o "$VPHONED_BIN" "${VPHONED_SRCS[@]}" \
|
||||
-larchive \
|
||||
-framework Foundation \
|
||||
-framework Security \
|
||||
-framework CoreServices
|
||||
|
||||
@@ -437,6 +437,7 @@ echo "[7/7] Installing LaunchDaemons..."
|
||||
VPHONED_SRC="$SCRIPT_DIR/vphoned"
|
||||
VPHONED_BIN="$VPHONED_SRC/vphoned"
|
||||
VPHONED_SRCS=(
|
||||
"$VPHONED_SRC/unarchive.m"
|
||||
"$VPHONED_SRC/vphoned.m"
|
||||
"$VPHONED_SRC/vphoned_install.m"
|
||||
"$VPHONED_SRC/vphoned_protocol.m"
|
||||
@@ -460,7 +461,9 @@ if [[ "$needs_vphoned_build" == "1" ]]; then
|
||||
echo " Building vphoned for arm64..."
|
||||
xcrun -sdk iphoneos clang -arch arm64 -Os -fobjc-arc \
|
||||
-I"$VPHONED_SRC" \
|
||||
-I"$VPHONED_SRC/vendor/libarchive" \
|
||||
-o "$VPHONED_BIN" "${VPHONED_SRCS[@]}" \
|
||||
-larchive \
|
||||
-framework Foundation \
|
||||
-framework Security \
|
||||
-framework CoreServices
|
||||
|
||||
@@ -190,9 +190,20 @@ ssh_cmd "/bin/chmod 0755 /mnt1/sbin/launchd"
|
||||
|
||||
echo " [+] launchd patched"
|
||||
|
||||
# ═══════════ JB-2 INSTALL PROCURSUS BOOTSTRAP ══════════════════
|
||||
# ═══════════ JB-2 INSTALL IOSBINPACK64 ════════════════════════
|
||||
echo ""
|
||||
echo "[JB-2] Installing procursus bootstrap..."
|
||||
echo "[JB-2] Installing iosbinpack64..."
|
||||
|
||||
scp_to "$INPUT_DIR/jb/iosbinpack64.tar" "/mnt1"
|
||||
ssh_cmd "/usr/bin/tar --preserve-permissions --no-overwrite-dir \
|
||||
-xf /mnt1/iosbinpack64.tar -C /mnt1"
|
||||
ssh_cmd "/bin/rm -f /mnt1/iosbinpack64.tar"
|
||||
|
||||
echo " [+] iosbinpack64 installed"
|
||||
|
||||
# ═══════════ JB-3 INSTALL PROCURSUS BOOTSTRAP ══════════════════
|
||||
echo ""
|
||||
echo "[JB-3] Installing procursus bootstrap..."
|
||||
|
||||
remote_mount /dev/disk1s5 /mnt5
|
||||
BOOT_HASH="$(get_boot_manifest_hash)"
|
||||
@@ -230,12 +241,12 @@ rm -f "$BOOTSTRAP_TAR"
|
||||
|
||||
echo " [+] procursus bootstrap installed"
|
||||
|
||||
# ═══════════ JB-3 DEPLOY BASEBIN HOOKS ═════════════════════════
|
||||
# ═══════════ JB-4 DEPLOY BASEBIN HOOKS ═════════════════════════
|
||||
BASEBIN_DIR="$JB_INPUT_DIR/basebin"
|
||||
|
||||
if [[ -d "$BASEBIN_DIR" ]]; then
|
||||
echo ""
|
||||
echo "[JB-3] Deploying BaseBin hooks to /cores/..."
|
||||
echo "[JB-4] Deploying BaseBin hooks to /cores/..."
|
||||
|
||||
# Clean previous dylibs before re-uploading
|
||||
echo " Cleaning old /cores/ dylibs..."
|
||||
|
||||
@@ -14,8 +14,10 @@ $(OUT): $(SRCS) $(wildcard *.h)
|
||||
@echo "=== Building vphoned (arm64, iphoneos) ==="
|
||||
xcrun -sdk iphoneos clang -arch arm64 -Os -fobjc-arc \
|
||||
-I. \
|
||||
-Ivendor/libarchive \
|
||||
-DVPHONED_BUILD_HASH='"$(GIT_HASH)"' \
|
||||
-o $@ $(SRCS) \
|
||||
-larchive \
|
||||
-framework Foundation \
|
||||
-framework Security \
|
||||
-framework CoreServices
|
||||
|
||||
3
scripts/vphoned/unarchive.h
Normal file
3
scripts/vphoned/unarchive.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern int extract(NSString* fileToExtract, NSString* extractionPath);
|
||||
87
scripts/vphoned/unarchive.m
Normal file
87
scripts/vphoned/unarchive.m
Normal file
@@ -0,0 +1,87 @@
|
||||
#import "unarchive.h"
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
static int
|
||||
copy_data(struct archive *ar, struct archive *aw)
|
||||
{
|
||||
int r;
|
||||
const void *buff;
|
||||
size_t size;
|
||||
la_int64_t offset;
|
||||
|
||||
for (;;) {
|
||||
r = archive_read_data_block(ar, &buff, &size, &offset);
|
||||
if (r == ARCHIVE_EOF)
|
||||
return (ARCHIVE_OK);
|
||||
if (r < ARCHIVE_OK)
|
||||
return (r);
|
||||
r = archive_write_data_block(aw, buff, size, offset);
|
||||
if (r < ARCHIVE_OK) {
|
||||
fprintf(stderr, "%s\n", archive_error_string(aw));
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int extract(NSString* fileToExtract, NSString* extractionPath)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive *ext;
|
||||
struct archive_entry *entry;
|
||||
int flags;
|
||||
int r;
|
||||
|
||||
/* Select which attributes we want to restore. */
|
||||
flags = ARCHIVE_EXTRACT_TIME;
|
||||
flags |= ARCHIVE_EXTRACT_PERM;
|
||||
flags |= ARCHIVE_EXTRACT_ACL;
|
||||
flags |= ARCHIVE_EXTRACT_FFLAGS;
|
||||
|
||||
a = archive_read_new();
|
||||
archive_read_support_format_all(a);
|
||||
archive_read_support_filter_all(a);
|
||||
ext = archive_write_disk_new();
|
||||
archive_write_disk_set_options(ext, flags);
|
||||
archive_write_disk_set_standard_lookup(ext);
|
||||
if ((r = archive_read_open_filename(a, fileToExtract.fileSystemRepresentation, 10240)))
|
||||
return 1;
|
||||
for (;;)
|
||||
{
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF)
|
||||
break;
|
||||
if (r < ARCHIVE_OK)
|
||||
fprintf(stderr, "%s\n", archive_error_string(a));
|
||||
if (r < ARCHIVE_WARN)
|
||||
return 1;
|
||||
|
||||
NSString* currentFile = [NSString stringWithUTF8String:archive_entry_pathname(entry)];
|
||||
NSString* fullOutputPath = [extractionPath stringByAppendingPathComponent:currentFile];
|
||||
//printf("extracting %@ to %@\n", currentFile, fullOutputPath);
|
||||
archive_entry_set_pathname(entry, fullOutputPath.fileSystemRepresentation);
|
||||
|
||||
r = archive_write_header(ext, entry);
|
||||
if (r < ARCHIVE_OK)
|
||||
fprintf(stderr, "%s\n", archive_error_string(ext));
|
||||
else if (archive_entry_size(entry) > 0) {
|
||||
r = copy_data(a, ext);
|
||||
if (r < ARCHIVE_OK)
|
||||
fprintf(stderr, "%s\n", archive_error_string(ext));
|
||||
if (r < ARCHIVE_WARN)
|
||||
return 1;
|
||||
}
|
||||
r = archive_write_finish_entry(ext);
|
||||
if (r < ARCHIVE_OK)
|
||||
fprintf(stderr, "%s\n", archive_error_string(ext));
|
||||
if (r < ARCHIVE_WARN)
|
||||
return 1;
|
||||
}
|
||||
archive_read_close(a);
|
||||
archive_read_free(a);
|
||||
archive_write_close(ext);
|
||||
archive_write_free(ext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1265
scripts/vphoned/vendor/libarchive/archive.h
vendored
Normal file
1265
scripts/vphoned/vendor/libarchive/archive.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
763
scripts/vphoned/vendor/libarchive/archive_entry.h
vendored
Normal file
763
scripts/vphoned/vendor/libarchive/archive_entry.h
vendored
Normal file
@@ -0,0 +1,763 @@
|
||||
/*-
|
||||
* Copyright (c) 2003-2008 Tim Kientzle
|
||||
* Copyright (c) 2016 Martin Matuska
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ARCHIVE_ENTRY_H_INCLUDED
|
||||
#define ARCHIVE_ENTRY_H_INCLUDED
|
||||
|
||||
/* Note: Compiler will complain if this does not match archive.h! */
|
||||
#define ARCHIVE_VERSION_NUMBER 3008004
|
||||
|
||||
/*
|
||||
* Note: archive_entry.h is for use outside of libarchive; the
|
||||
* configuration headers (config.h, archive_platform.h, etc.) are
|
||||
* purely internal. Do NOT use HAVE_XXX configuration macros to
|
||||
* control the behavior of this header! If you must conditionalize,
|
||||
* use predefined compiler and/or platform macros.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h> /* for wchar_t */
|
||||
#include <stdint.h> /* for C99 int64_t, etc. */
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* time_t is slated to be removed from public includes in 4.0 */
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Get a suitable 64-bit integer type. */
|
||||
#if !defined(__LA_INT64_T_DEFINED)
|
||||
# if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
#define __LA_INT64_T la_int64_t
|
||||
# endif
|
||||
#define __LA_INT64_T_DEFINED
|
||||
# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
|
||||
typedef __int64 la_int64_t;
|
||||
typedef unsigned __int64 la_uint64_t;
|
||||
# else
|
||||
#include <unistd.h>
|
||||
# if defined(_SCO_DS) || defined(__osf__)
|
||||
typedef long long la_int64_t;
|
||||
typedef unsigned long long la_uint64_t;
|
||||
# else
|
||||
typedef int64_t la_int64_t;
|
||||
typedef uint64_t la_uint64_t;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The la_ssize_t should match the type used in 'struct stat' */
|
||||
#if !defined(__LA_SSIZE_T_DEFINED)
|
||||
/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */
|
||||
# if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
#define __LA_SSIZE_T la_ssize_t
|
||||
# endif
|
||||
#define __LA_SSIZE_T_DEFINED
|
||||
# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
|
||||
# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
|
||||
typedef ssize_t la_ssize_t;
|
||||
# elif defined(_WIN64)
|
||||
typedef __int64 la_ssize_t;
|
||||
# else
|
||||
typedef long la_ssize_t;
|
||||
# endif
|
||||
# else
|
||||
# include <unistd.h> /* ssize_t */
|
||||
typedef ssize_t la_ssize_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Get a suitable definition for mode_t */
|
||||
#if ARCHIVE_VERSION_NUMBER >= 3999000
|
||||
/* Switch to plain 'int' for libarchive 4.0. It's less broken than 'mode_t' */
|
||||
# define __LA_MODE_T int
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
|
||||
# define __LA_MODE_T unsigned short
|
||||
#else
|
||||
# define __LA_MODE_T mode_t
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Use the platform types for time_t */
|
||||
#define __LA_TIME_T time_t
|
||||
#else
|
||||
/* Use 64-bits integer types for time_t */
|
||||
#define __LA_TIME_T la_int64_t
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Use the platform types for dev_t */
|
||||
#define __LA_DEV_T dev_t
|
||||
#else
|
||||
/* Use 64-bits integer types for dev_t */
|
||||
#define __LA_DEV_T la_int64_t
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Libarchive 3.x used signed int64 for inode numbers */
|
||||
#define __LA_INO_T la_int64_t
|
||||
#else
|
||||
/* Switch to unsigned for libarchive 4.0 */
|
||||
#define __LA_INO_T la_uint64_t
|
||||
#endif
|
||||
|
||||
/* Large file support for Android */
|
||||
#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)
|
||||
#include "android_lf.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On Windows, define LIBARCHIVE_STATIC if you're building or using a
|
||||
* .lib. The default here assumes you're building a DLL. Only
|
||||
* libarchive source should ever define __LIBARCHIVE_BUILD.
|
||||
*/
|
||||
#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)
|
||||
# ifdef __LIBARCHIVE_BUILD
|
||||
# ifdef __GNUC__
|
||||
# define __LA_DECL __attribute__((dllexport)) extern
|
||||
# else
|
||||
# define __LA_DECL __declspec(dllexport)
|
||||
# endif
|
||||
# else
|
||||
# ifdef __GNUC__
|
||||
# define __LA_DECL
|
||||
# else
|
||||
# define __LA_DECL __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
#elif defined __LIBARCHIVE_ENABLE_VISIBILITY
|
||||
# define __LA_DECL __attribute__((visibility("default")))
|
||||
#else
|
||||
/* Static libraries on all platforms and shared libraries on non-Windows. */
|
||||
# define __LA_DECL
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 3 || \
|
||||
(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
# define __LA_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
# define __LA_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Description of an archive entry.
|
||||
*
|
||||
* You can think of this as "struct stat" with some text fields added in.
|
||||
*
|
||||
* TODO: Add "comment", "charset", and possibly other entries that are
|
||||
* supported by "pax interchange" format. However, GNU, ustar, cpio,
|
||||
* and other variants don't support these features, so they're not an
|
||||
* excruciatingly high priority right now.
|
||||
*
|
||||
* TODO: "pax interchange" format allows essentially arbitrary
|
||||
* key/value attributes to be attached to any entry. Supporting
|
||||
* such extensions may make this library useful for special
|
||||
* applications (e.g., a package manager could attach special
|
||||
* package-management attributes to each entry).
|
||||
*/
|
||||
struct archive;
|
||||
struct archive_entry;
|
||||
|
||||
/*
|
||||
* File-type constants. These are returned from archive_entry_filetype()
|
||||
* and passed to archive_entry_set_filetype().
|
||||
*
|
||||
* These values match S_XXX defines on every platform I've checked,
|
||||
* including Windows, AIX, Linux, Solaris, and BSD. They're
|
||||
* (re)defined here because platforms generally don't define the ones
|
||||
* they don't support. For example, Windows doesn't define S_IFLNK or
|
||||
* S_IFBLK. Instead of having a mass of conditional logic and system
|
||||
* checks to define any S_XXX values that aren't supported locally,
|
||||
* I've just defined a new set of such constants so that
|
||||
* libarchive-based applications can manipulate and identify archive
|
||||
* entries properly even if the hosting platform can't store them on
|
||||
* disk.
|
||||
*
|
||||
* These values are also used directly within some portable formats,
|
||||
* such as cpio. If you find a platform that varies from these, the
|
||||
* correct solution is to leave these alone and translate from these
|
||||
* portable values to platform-native values when entries are read from
|
||||
* or written to disk.
|
||||
*/
|
||||
/*
|
||||
* In libarchive 4.0, we can drop the casts here.
|
||||
* They're needed to work around Borland C's broken mode_t.
|
||||
*/
|
||||
#define AE_IFMT ((__LA_MODE_T)0170000)
|
||||
#define AE_IFREG ((__LA_MODE_T)0100000)
|
||||
#define AE_IFLNK ((__LA_MODE_T)0120000)
|
||||
#define AE_IFSOCK ((__LA_MODE_T)0140000)
|
||||
#define AE_IFCHR ((__LA_MODE_T)0020000)
|
||||
#define AE_IFBLK ((__LA_MODE_T)0060000)
|
||||
#define AE_IFDIR ((__LA_MODE_T)0040000)
|
||||
#define AE_IFIFO ((__LA_MODE_T)0010000)
|
||||
|
||||
/*
|
||||
* Symlink types
|
||||
*/
|
||||
#define AE_SYMLINK_TYPE_UNDEFINED 0
|
||||
#define AE_SYMLINK_TYPE_FILE 1
|
||||
#define AE_SYMLINK_TYPE_DIRECTORY 2
|
||||
|
||||
/*
|
||||
* Basic object manipulation
|
||||
*/
|
||||
|
||||
__LA_DECL struct archive_entry *archive_entry_clear(struct archive_entry *);
|
||||
/* The 'clone' function does a deep copy; all of the strings are copied too. */
|
||||
__LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_free(struct archive_entry *);
|
||||
__LA_DECL struct archive_entry *archive_entry_new(void);
|
||||
|
||||
/*
|
||||
* This form of archive_entry_new2() will pull character-set
|
||||
* conversion information from the specified archive handle. The
|
||||
* older archive_entry_new(void) form is equivalent to calling
|
||||
* archive_entry_new2(NULL) and will result in the use of an internal
|
||||
* default character-set conversion.
|
||||
*/
|
||||
__LA_DECL struct archive_entry *archive_entry_new2(struct archive *);
|
||||
|
||||
/*
|
||||
* Retrieve fields from an archive_entry.
|
||||
*
|
||||
* There are a number of implicit conversions among these fields. For
|
||||
* example, if a regular string field is set and you read the _w wide
|
||||
* character field, the entry will implicitly convert narrow-to-wide
|
||||
* using the current locale. Similarly, dev values are automatically
|
||||
* updated when you write devmajor or devminor and vice versa.
|
||||
*
|
||||
* In addition, fields can be "set" or "unset." Unset string fields
|
||||
* return NULL, non-string fields have _is_set() functions to test
|
||||
* whether they've been set. You can "unset" a string field by
|
||||
* assigning NULL; non-string fields have _unset() functions to
|
||||
* unset them.
|
||||
*
|
||||
* Note: There is one ambiguity in the above; string fields will
|
||||
* also return NULL when implicit character set conversions fail.
|
||||
* This is usually what you want.
|
||||
*/
|
||||
__LA_DECL __LA_TIME_T archive_entry_atime(struct archive_entry *);
|
||||
__LA_DECL long archive_entry_atime_nsec(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_atime_is_set(struct archive_entry *);
|
||||
__LA_DECL __LA_TIME_T archive_entry_birthtime(struct archive_entry *);
|
||||
__LA_DECL long archive_entry_birthtime_nsec(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_birthtime_is_set(struct archive_entry *);
|
||||
__LA_DECL __LA_TIME_T archive_entry_ctime(struct archive_entry *);
|
||||
__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_ctime_is_set(struct archive_entry *);
|
||||
__LA_DECL __LA_DEV_T archive_entry_dev(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_dev_is_set(struct archive_entry *);
|
||||
__LA_DECL __LA_DEV_T archive_entry_devmajor(struct archive_entry *);
|
||||
__LA_DECL __LA_DEV_T archive_entry_devminor(struct archive_entry *);
|
||||
__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_filetype_is_set(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_fflags(struct archive_entry *,
|
||||
unsigned long * /* set */,
|
||||
unsigned long * /* clear */);
|
||||
__LA_DECL const char *archive_entry_fflags_text(struct archive_entry *);
|
||||
__LA_DECL la_int64_t archive_entry_gid(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_gid_is_set(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_gname(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_gname_utf8(struct archive_entry *);
|
||||
__LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_set_link_to_hardlink(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_hardlink(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_hardlink_utf8(struct archive_entry *);
|
||||
__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_hardlink_is_set(struct archive_entry *);
|
||||
__LA_DECL __LA_INO_T archive_entry_ino(struct archive_entry *);
|
||||
__LA_DECL __LA_INO_T archive_entry_ino64(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_ino_is_set(struct archive_entry *);
|
||||
__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *);
|
||||
__LA_DECL time_t archive_entry_mtime(struct archive_entry *);
|
||||
__LA_DECL long archive_entry_mtime_nsec(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_mtime_is_set(struct archive_entry *);
|
||||
__LA_DECL unsigned int archive_entry_nlink(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_pathname(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_pathname_utf8(struct archive_entry *);
|
||||
__LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *);
|
||||
__LA_DECL __LA_MODE_T archive_entry_perm(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_perm_is_set(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_rdev_is_set(struct archive_entry *);
|
||||
__LA_DECL __LA_DEV_T archive_entry_rdev(struct archive_entry *);
|
||||
__LA_DECL __LA_DEV_T archive_entry_rdevmajor(struct archive_entry *);
|
||||
__LA_DECL __LA_DEV_T archive_entry_rdevminor(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *);
|
||||
__LA_DECL const wchar_t *archive_entry_sourcepath_w(struct archive_entry *);
|
||||
__LA_DECL la_int64_t archive_entry_size(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_size_is_set(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_strmode(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_set_link_to_symlink(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_symlink(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_symlink_utf8(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_symlink_type(struct archive_entry *);
|
||||
__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *);
|
||||
__LA_DECL la_int64_t archive_entry_uid(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_uid_is_set(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_uname(struct archive_entry *);
|
||||
__LA_DECL const char *archive_entry_uname_utf8(struct archive_entry *);
|
||||
__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_is_data_encrypted(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_is_metadata_encrypted(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_is_encrypted(struct archive_entry *);
|
||||
|
||||
/*
|
||||
* Set fields in an archive_entry.
|
||||
*
|
||||
* Note: Before libarchive 2.4, there were 'set' and 'copy' versions
|
||||
* of the string setters. 'copy' copied the actual string, 'set' just
|
||||
* stored the pointer. In libarchive 2.4 and later, strings are
|
||||
* always copied.
|
||||
*/
|
||||
|
||||
__LA_DECL void archive_entry_set_atime(struct archive_entry *, __LA_TIME_T, long);
|
||||
__LA_DECL void archive_entry_unset_atime(struct archive_entry *);
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *);
|
||||
#endif
|
||||
__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, __LA_TIME_T, long);
|
||||
__LA_DECL void archive_entry_unset_birthtime(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_set_ctime(struct archive_entry *, __LA_TIME_T, long);
|
||||
__LA_DECL void archive_entry_unset_ctime(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_set_dev(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_devminor(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int);
|
||||
__LA_DECL void archive_entry_set_fflags(struct archive_entry *,
|
||||
unsigned long /* set */, unsigned long /* clear */);
|
||||
/* Returns pointer to start of first invalid token, or NULL if none. */
|
||||
/* Note that all recognized tokens are processed, regardless. */
|
||||
__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *,
|
||||
const char *);
|
||||
__LA_DECL const char *archive_entry_copy_fflags_text_len(struct archive_entry *,
|
||||
const char *, size_t);
|
||||
__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
|
||||
const wchar_t *);
|
||||
__LA_DECL void archive_entry_set_gid(struct archive_entry *, la_int64_t);
|
||||
__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_gname_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
|
||||
__LA_DECL int archive_entry_update_gname_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_hardlink_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
|
||||
__LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INO_T);
|
||||
__LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INO_T);
|
||||
__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_link_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);
|
||||
__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T);
|
||||
__LA_DECL void archive_entry_set_mtime(struct archive_entry *, __LA_TIME_T, long);
|
||||
__LA_DECL void archive_entry_unset_mtime(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int);
|
||||
__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_pathname_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
|
||||
__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T);
|
||||
__LA_DECL void archive_entry_set_rdev(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_size(struct archive_entry *, la_int64_t);
|
||||
__LA_DECL void archive_entry_unset_size(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_sourcepath_w(struct archive_entry *, const wchar_t *);
|
||||
__LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_symlink_type(struct archive_entry *, int);
|
||||
__LA_DECL void archive_entry_set_symlink_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
|
||||
__LA_DECL int archive_entry_update_symlink_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_uid(struct archive_entry *, la_int64_t);
|
||||
__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_uname_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
|
||||
__LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_is_data_encrypted(struct archive_entry *, char is_encrypted);
|
||||
__LA_DECL void archive_entry_set_is_metadata_encrypted(struct archive_entry *, char is_encrypted);
|
||||
/*
|
||||
* Routines to bulk copy fields to/from a platform-native "struct
|
||||
* stat." Libarchive used to just store a struct stat inside of each
|
||||
* archive_entry object, but this created issues when trying to
|
||||
* manipulate archives on systems different than the ones they were
|
||||
* created on.
|
||||
*
|
||||
* TODO: On Linux and other LFS systems, provide both stat32 and
|
||||
* stat64 versions of these functions and all of the macro glue so
|
||||
* that archive_entry_stat is magically defined to
|
||||
* archive_entry_stat32 or archive_entry_stat64 as appropriate.
|
||||
*/
|
||||
__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
|
||||
|
||||
/*
|
||||
* Storage for Mac OS-specific AppleDouble metadata information.
|
||||
* Apple-format tar files store a separate binary blob containing
|
||||
* encoded metadata with ACL, extended attributes, etc.
|
||||
* This provides a place to store that blob.
|
||||
*/
|
||||
|
||||
__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *);
|
||||
__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);
|
||||
|
||||
/*
|
||||
* Digest routine. This is used to query the raw hex digest for the
|
||||
* given entry. The type of digest is provided as an argument.
|
||||
*/
|
||||
#define ARCHIVE_ENTRY_DIGEST_MD5 0x00000001
|
||||
#define ARCHIVE_ENTRY_DIGEST_RMD160 0x00000002
|
||||
#define ARCHIVE_ENTRY_DIGEST_SHA1 0x00000003
|
||||
#define ARCHIVE_ENTRY_DIGEST_SHA256 0x00000004
|
||||
#define ARCHIVE_ENTRY_DIGEST_SHA384 0x00000005
|
||||
#define ARCHIVE_ENTRY_DIGEST_SHA512 0x00000006
|
||||
|
||||
__LA_DECL const unsigned char * archive_entry_digest(struct archive_entry *, int /* type */);
|
||||
__LA_DECL int archive_entry_set_digest(struct archive_entry *, int, const unsigned char *);
|
||||
|
||||
/*
|
||||
* ACL routines. This used to simply store and return text-format ACL
|
||||
* strings, but that proved insufficient for a number of reasons:
|
||||
* = clients need control over uname/uid and gname/gid mappings
|
||||
* = there are many different ACL text formats
|
||||
* = would like to be able to read/convert archives containing ACLs
|
||||
* on platforms that lack ACL libraries
|
||||
*
|
||||
* This last point, in particular, forces me to implement a reasonably
|
||||
* complete set of ACL support routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Permission bits.
|
||||
*/
|
||||
#define ARCHIVE_ENTRY_ACL_EXECUTE 0x00000001
|
||||
#define ARCHIVE_ENTRY_ACL_WRITE 0x00000002
|
||||
#define ARCHIVE_ENTRY_ACL_READ 0x00000004
|
||||
#define ARCHIVE_ENTRY_ACL_READ_DATA 0x00000008
|
||||
#define ARCHIVE_ENTRY_ACL_LIST_DIRECTORY 0x00000008
|
||||
#define ARCHIVE_ENTRY_ACL_WRITE_DATA 0x00000010
|
||||
#define ARCHIVE_ENTRY_ACL_ADD_FILE 0x00000010
|
||||
#define ARCHIVE_ENTRY_ACL_APPEND_DATA 0x00000020
|
||||
#define ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY 0x00000020
|
||||
#define ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS 0x00000040
|
||||
#define ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS 0x00000080
|
||||
#define ARCHIVE_ENTRY_ACL_DELETE_CHILD 0x00000100
|
||||
#define ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES 0x00000200
|
||||
#define ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES 0x00000400
|
||||
#define ARCHIVE_ENTRY_ACL_DELETE 0x00000800
|
||||
#define ARCHIVE_ENTRY_ACL_READ_ACL 0x00001000
|
||||
#define ARCHIVE_ENTRY_ACL_WRITE_ACL 0x00002000
|
||||
#define ARCHIVE_ENTRY_ACL_WRITE_OWNER 0x00004000
|
||||
#define ARCHIVE_ENTRY_ACL_SYNCHRONIZE 0x00008000
|
||||
|
||||
#define ARCHIVE_ENTRY_ACL_PERMS_POSIX1E \
|
||||
(ARCHIVE_ENTRY_ACL_EXECUTE \
|
||||
| ARCHIVE_ENTRY_ACL_WRITE \
|
||||
| ARCHIVE_ENTRY_ACL_READ)
|
||||
|
||||
#define ARCHIVE_ENTRY_ACL_PERMS_NFS4 \
|
||||
(ARCHIVE_ENTRY_ACL_EXECUTE \
|
||||
| ARCHIVE_ENTRY_ACL_READ_DATA \
|
||||
| ARCHIVE_ENTRY_ACL_LIST_DIRECTORY \
|
||||
| ARCHIVE_ENTRY_ACL_WRITE_DATA \
|
||||
| ARCHIVE_ENTRY_ACL_ADD_FILE \
|
||||
| ARCHIVE_ENTRY_ACL_APPEND_DATA \
|
||||
| ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY \
|
||||
| ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS \
|
||||
| ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS \
|
||||
| ARCHIVE_ENTRY_ACL_DELETE_CHILD \
|
||||
| ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES \
|
||||
| ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES \
|
||||
| ARCHIVE_ENTRY_ACL_DELETE \
|
||||
| ARCHIVE_ENTRY_ACL_READ_ACL \
|
||||
| ARCHIVE_ENTRY_ACL_WRITE_ACL \
|
||||
| ARCHIVE_ENTRY_ACL_WRITE_OWNER \
|
||||
| ARCHIVE_ENTRY_ACL_SYNCHRONIZE)
|
||||
|
||||
/*
|
||||
* Inheritance values (NFS4 ACLs only); included in permset.
|
||||
*/
|
||||
#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x01000000
|
||||
#define ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT 0x02000000
|
||||
#define ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT 0x04000000
|
||||
#define ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT 0x08000000
|
||||
#define ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY 0x10000000
|
||||
#define ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS 0x20000000
|
||||
#define ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS 0x40000000
|
||||
|
||||
#define ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 \
|
||||
(ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT \
|
||||
| ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT \
|
||||
| ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT \
|
||||
| ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY \
|
||||
| ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS \
|
||||
| ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS \
|
||||
| ARCHIVE_ENTRY_ACL_ENTRY_INHERITED)
|
||||
|
||||
/* We need to be able to specify combinations of these. */
|
||||
#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 0x00000100 /* POSIX.1e only */
|
||||
#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 0x00000200 /* POSIX.1e only */
|
||||
#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 0x00000400 /* NFS4 only */
|
||||
#define ARCHIVE_ENTRY_ACL_TYPE_DENY 0x00000800 /* NFS4 only */
|
||||
#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 0x00001000 /* NFS4 only */
|
||||
#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 0x00002000 /* NFS4 only */
|
||||
#define ARCHIVE_ENTRY_ACL_TYPE_POSIX1E (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \
|
||||
| ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
|
||||
#define ARCHIVE_ENTRY_ACL_TYPE_NFS4 (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \
|
||||
| ARCHIVE_ENTRY_ACL_TYPE_DENY \
|
||||
| ARCHIVE_ENTRY_ACL_TYPE_AUDIT \
|
||||
| ARCHIVE_ENTRY_ACL_TYPE_ALARM)
|
||||
|
||||
/* Tag values mimic POSIX.1e */
|
||||
#define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */
|
||||
#define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */
|
||||
#define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */
|
||||
#define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */
|
||||
#define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access (POSIX.1e only) */
|
||||
#define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public (POSIX.1e only) */
|
||||
#define ARCHIVE_ENTRY_ACL_EVERYONE 10107 /* Everyone (NFS4 only) */
|
||||
|
||||
/*
|
||||
* Set the ACL by clearing it and adding entries one at a time.
|
||||
* Unlike the POSIX.1e ACL routines, you must specify the type
|
||||
* (access/default) for each entry. Internally, the ACL data is just
|
||||
* a soup of entries. API calls here allow you to retrieve just the
|
||||
* entries of interest. This design (which goes against the spirit of
|
||||
* POSIX.1e) is useful for handling archive formats that combine
|
||||
* default and access information in a single ACL list.
|
||||
*/
|
||||
__LA_DECL void archive_entry_acl_clear(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_acl_add_entry(struct archive_entry *,
|
||||
int /* type */, int /* permset */, int /* tag */,
|
||||
int /* qual */, const char * /* name */);
|
||||
__LA_DECL int archive_entry_acl_add_entry_w(struct archive_entry *,
|
||||
int /* type */, int /* permset */, int /* tag */,
|
||||
int /* qual */, const wchar_t * /* name */);
|
||||
|
||||
/*
|
||||
* To retrieve the ACL, first "reset", then repeatedly ask for the
|
||||
* "next" entry. The want_type parameter allows you to request only
|
||||
* certain types of entries.
|
||||
*/
|
||||
__LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */);
|
||||
__LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */,
|
||||
int * /* type */, int * /* permset */, int * /* tag */,
|
||||
int * /* qual */, const char ** /* name */);
|
||||
|
||||
/*
|
||||
* Construct a text-format ACL. The flags argument is a bitmask that
|
||||
* can include any of the following:
|
||||
*
|
||||
* Flags only for archive entries with POSIX.1e ACL:
|
||||
* ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries.
|
||||
* ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries.
|
||||
* ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
|
||||
* default ACL entry.
|
||||
* ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and
|
||||
* "mask" entries.
|
||||
*
|
||||
* Flags only for archive entries with NFSv4 ACL:
|
||||
* ARCHIVE_ENTRY_ACL_STYLE_COMPACT - Do not output the minus character for
|
||||
* unset permissions and flags in NFSv4 ACL permission and flag fields
|
||||
*
|
||||
* Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL:
|
||||
* ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
|
||||
* each ACL entry.
|
||||
* ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma
|
||||
* instead of newline.
|
||||
*/
|
||||
#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 0x00000001
|
||||
#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 0x00000002
|
||||
#define ARCHIVE_ENTRY_ACL_STYLE_SOLARIS 0x00000004
|
||||
#define ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA 0x00000008
|
||||
#define ARCHIVE_ENTRY_ACL_STYLE_COMPACT 0x00000010
|
||||
|
||||
__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *,
|
||||
la_ssize_t * /* len */, int /* flags */);
|
||||
__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *,
|
||||
la_ssize_t * /* len */, int /* flags */);
|
||||
__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *,
|
||||
const wchar_t * /* wtext */, int /* type */);
|
||||
__LA_DECL int archive_entry_acl_from_text(struct archive_entry *,
|
||||
const char * /* text */, int /* type */);
|
||||
|
||||
/* Deprecated constants */
|
||||
#define OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
|
||||
#define OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
|
||||
|
||||
/* Deprecated functions */
|
||||
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
|
||||
int /* flags */) __LA_DEPRECATED;
|
||||
__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
|
||||
int /* flags */) __LA_DEPRECATED;
|
||||
|
||||
/* Return bitmask of ACL types in an archive entry */
|
||||
__LA_DECL int archive_entry_acl_types(struct archive_entry *);
|
||||
|
||||
/* Return a count of entries matching 'want_type' */
|
||||
__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */);
|
||||
|
||||
/* Return an opaque ACL object. */
|
||||
/* There's not yet anything clients can actually do with this... */
|
||||
struct archive_acl;
|
||||
__LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *);
|
||||
|
||||
/*
|
||||
* extended attributes
|
||||
*/
|
||||
|
||||
__LA_DECL void archive_entry_xattr_clear(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_xattr_add_entry(struct archive_entry *,
|
||||
const char * /* name */, const void * /* value */,
|
||||
size_t /* size */);
|
||||
|
||||
/*
|
||||
* To retrieve the xattr list, first "reset", then repeatedly ask for the
|
||||
* "next" entry.
|
||||
*/
|
||||
|
||||
__LA_DECL int archive_entry_xattr_count(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_xattr_reset(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_xattr_next(struct archive_entry *,
|
||||
const char ** /* name */, const void ** /* value */, size_t *);
|
||||
|
||||
/*
|
||||
* sparse
|
||||
*/
|
||||
|
||||
__LA_DECL void archive_entry_sparse_clear(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_sparse_add_entry(struct archive_entry *,
|
||||
la_int64_t /* offset */, la_int64_t /* length */);
|
||||
|
||||
/*
|
||||
* To retrieve the xattr list, first "reset", then repeatedly ask for the
|
||||
* "next" entry.
|
||||
*/
|
||||
|
||||
__LA_DECL int archive_entry_sparse_count(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_sparse_reset(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_sparse_next(struct archive_entry *,
|
||||
la_int64_t * /* offset */, la_int64_t * /* length */);
|
||||
|
||||
/*
|
||||
* Utility to match up hardlinks.
|
||||
*
|
||||
* The 'struct archive_entry_linkresolver' is a cache of archive entries
|
||||
* for files with multiple links. Here's how to use it:
|
||||
* 1. Create a lookup object with archive_entry_linkresolver_new()
|
||||
* 2. Tell it the archive format you're using.
|
||||
* 3. Hand each archive_entry to archive_entry_linkify().
|
||||
* That function will return 0, 1, or 2 entries that should
|
||||
* be written.
|
||||
* 4. Call archive_entry_linkify(resolver, NULL) until
|
||||
* no more entries are returned.
|
||||
* 5. Call archive_entry_linkresolver_free(resolver) to free resources.
|
||||
*
|
||||
* The entries returned have their hardlink and size fields updated
|
||||
* appropriately. If an entry is passed in that does not refer to
|
||||
* a file with multiple links, it is returned unchanged. The intention
|
||||
* is that you should be able to simply filter all entries through
|
||||
* this machine.
|
||||
*
|
||||
* To make things more efficient, be sure that each entry has a valid
|
||||
* nlinks value. The hardlink cache uses this to track when all links
|
||||
* have been found. If the nlinks value is zero, it will keep every
|
||||
* name in the cache indefinitely, which can use a lot of memory.
|
||||
*
|
||||
* Note that archive_entry_size() is reset to zero if the file
|
||||
* body should not be written to the archive. Pay attention!
|
||||
*/
|
||||
struct archive_entry_linkresolver;
|
||||
|
||||
/*
|
||||
* There are three different strategies for marking hardlinks.
|
||||
* The descriptions below name them after the best-known
|
||||
* formats that rely on each strategy:
|
||||
*
|
||||
* "Old cpio" is the simplest, it always returns any entry unmodified.
|
||||
* As far as I know, only cpio formats use this. Old cpio archives
|
||||
* store every link with the full body; the onus is on the dearchiver
|
||||
* to detect and properly link the files as they are restored.
|
||||
* "tar" is also pretty simple; it caches a copy the first time it sees
|
||||
* any link. Subsequent appearances are modified to be hardlink
|
||||
* references to the first one without any body. Used by all tar
|
||||
* formats, although the newest tar formats permit the "old cpio" strategy
|
||||
* as well. This strategy is very simple for the dearchiver,
|
||||
* and reasonably straightforward for the archiver.
|
||||
* "new cpio" is trickier. It stores the body only with the last
|
||||
* occurrence. The complication is that we might not
|
||||
* see every link to a particular file in a single session, so
|
||||
* there's no easy way to know when we've seen the last occurrence.
|
||||
* The solution here is to queue one link until we see the next.
|
||||
* At the end of the session, you can enumerate any remaining
|
||||
* entries by calling archive_entry_linkify(NULL) and store those
|
||||
* bodies. If you have a file with three links l1, l2, and l3,
|
||||
* you'll get the following behavior if you see all three links:
|
||||
* linkify(l1) => NULL (the resolver stores l1 internally)
|
||||
* linkify(l2) => l1 (resolver stores l2, you write l1)
|
||||
* linkify(l3) => l2, l3 (all links seen, you can write both).
|
||||
* If you only see l1 and l2, you'll get this behavior:
|
||||
* linkify(l1) => NULL
|
||||
* linkify(l2) => l1
|
||||
* linkify(NULL) => l2 (at end, you retrieve remaining links)
|
||||
* As the name suggests, this strategy is used by newer cpio variants.
|
||||
* It's noticeably more complex for the archiver, slightly more complex
|
||||
* for the dearchiver than the tar strategy, but makes it straightforward
|
||||
* to restore a file using any link by simply continuing to scan until
|
||||
* you see a link that is stored with a body. In contrast, the tar
|
||||
* strategy requires you to rescan the archive from the beginning to
|
||||
* correctly extract an arbitrary link.
|
||||
*/
|
||||
|
||||
__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void);
|
||||
__LA_DECL void archive_entry_linkresolver_set_strategy(
|
||||
struct archive_entry_linkresolver *, int /* format_code */);
|
||||
__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
|
||||
__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *,
|
||||
struct archive_entry **, struct archive_entry **);
|
||||
__LA_DECL struct archive_entry *archive_entry_partial_links(
|
||||
struct archive_entry_linkresolver *res, unsigned int *links);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This is meaningless outside of this header. */
|
||||
#undef __LA_DECL
|
||||
|
||||
#endif /* !ARCHIVE_ENTRY_H_INCLUDED */
|
||||
@@ -16,10 +16,8 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <spawn.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#import "vphoned_protocol.h"
|
||||
@@ -83,211 +81,6 @@ static const char *self_executable_path(void) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// MARK: - TrollStore Lite Install
|
||||
|
||||
static NSString *find_trollstore_lite_helper(void) {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSArray<NSString *> *fixedPaths = @[
|
||||
@"/Applications/TrollStoreLite.app/trollstorehelper",
|
||||
@"/var/jb/Applications/TrollStoreLite.app/trollstorehelper",
|
||||
];
|
||||
for (NSString *path in fixedPaths) {
|
||||
if ([fm isExecutableFileAtPath:path]) return path;
|
||||
}
|
||||
|
||||
NSString *bundleRoot = @"/var/containers/Bundle/Application";
|
||||
NSDirectoryEnumerator<NSString *> *enumerator = [fm enumeratorAtPath:bundleRoot];
|
||||
for (NSString *relativePath in enumerator) {
|
||||
if ([relativePath hasSuffix:@"TrollStoreLite.app/trollstorehelper"]) {
|
||||
NSString *fullPath = [bundleRoot stringByAppendingPathComponent:relativePath];
|
||||
if ([fm isExecutableFileAtPath:fullPath]) return fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
static NSString *trollstore_lite_marker_path_for_container(NSString *containerPath) {
|
||||
return [containerPath stringByAppendingPathComponent:@"_TrollStoreLite"];
|
||||
}
|
||||
|
||||
static NSDictionary *info_dictionary_for_app_path(NSString *appPath) {
|
||||
if (appPath.length == 0) return nil;
|
||||
return [NSDictionary dictionaryWithContentsOfFile:[appPath stringByAppendingPathComponent:@"Info.plist"]];
|
||||
}
|
||||
|
||||
static NSString *find_trollstore_lite_app_path_for_bundle_id(NSString *bundleId) {
|
||||
if (bundleId.length == 0) return nil;
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSString *bundleRoot = @"/var/containers/Bundle/Application";
|
||||
NSArray<NSString *> *containers = [fm contentsOfDirectoryAtPath:bundleRoot error:nil];
|
||||
for (NSString *container in containers) {
|
||||
NSString *containerPath = [bundleRoot stringByAppendingPathComponent:container];
|
||||
BOOL isDirectory = NO;
|
||||
if (![fm fileExistsAtPath:containerPath isDirectory:&isDirectory] || !isDirectory) continue;
|
||||
if (![fm fileExistsAtPath:trollstore_lite_marker_path_for_container(containerPath)]) continue;
|
||||
|
||||
NSArray<NSString *> *items = [fm contentsOfDirectoryAtPath:containerPath error:nil];
|
||||
for (NSString *item in items) {
|
||||
if (![item.pathExtension isEqualToString:@"app"]) continue;
|
||||
NSString *appPath = [containerPath stringByAppendingPathComponent:item];
|
||||
NSString *candidateBundleId = info_dictionary_for_app_path(appPath)[@"CFBundleIdentifier"];
|
||||
if ([candidateBundleId isEqualToString:bundleId]) {
|
||||
return appPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
static NSString *read_all_from_fd(int fd) {
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
uint8_t buf[4096];
|
||||
ssize_t n = 0;
|
||||
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
[data appendBytes:buf length:(NSUInteger)n];
|
||||
}
|
||||
if (data.length == 0) return @"";
|
||||
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
return string ?: @"";
|
||||
}
|
||||
|
||||
static int run_process_with_output(NSString *path, NSArray<NSString *> *args, NSString **output) {
|
||||
NSUInteger argc = args.count + 2;
|
||||
char **argv = calloc(argc, sizeof(char *));
|
||||
if (!argv) return ENOMEM;
|
||||
|
||||
argv[0] = strdup(path.fileSystemRepresentation);
|
||||
for (NSUInteger i = 0; i < args.count; i++) {
|
||||
argv[i + 1] = strdup(args[i].fileSystemRepresentation);
|
||||
}
|
||||
argv[argc - 1] = NULL;
|
||||
|
||||
int pipeFds[2] = {-1, -1};
|
||||
if (pipe(pipeFds) != 0) {
|
||||
for (NSUInteger i = 0; i < argc - 1; i++) free(argv[i]);
|
||||
free(argv);
|
||||
return errno;
|
||||
}
|
||||
|
||||
posix_spawn_file_actions_t actions;
|
||||
posix_spawn_file_actions_init(&actions);
|
||||
posix_spawn_file_actions_adddup2(&actions, pipeFds[1], STDOUT_FILENO);
|
||||
posix_spawn_file_actions_adddup2(&actions, pipeFds[1], STDERR_FILENO);
|
||||
posix_spawn_file_actions_addclose(&actions, pipeFds[0]);
|
||||
|
||||
pid_t pid = 0;
|
||||
int spawnError = posix_spawn(&pid, path.fileSystemRepresentation, &actions, NULL, argv, NULL);
|
||||
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
close(pipeFds[1]);
|
||||
|
||||
NSString *captured = read_all_from_fd(pipeFds[0]);
|
||||
close(pipeFds[0]);
|
||||
|
||||
int status = 0;
|
||||
if (spawnError == 0) {
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
spawnError = errno;
|
||||
}
|
||||
}
|
||||
|
||||
for (NSUInteger i = 0; i < argc - 1; i++) free(argv[i]);
|
||||
free(argv);
|
||||
|
||||
if (output) *output = captured;
|
||||
|
||||
if (spawnError != 0) return spawnError;
|
||||
if (WIFEXITED(status)) return WEXITSTATUS(status);
|
||||
if (WIFSIGNALED(status)) return 128 + WTERMSIG(status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static NSDictionary *handle_trollstore_install(NSDictionary *msg) {
|
||||
id reqId = msg[@"id"];
|
||||
NSString *ipaPath = msg[@"path"];
|
||||
NSString *bundleId = msg[@"bundle_id"];
|
||||
NSString *registration = msg[@"registration"];
|
||||
if (ipaPath.length == 0) {
|
||||
NSMutableDictionary *r = vp_make_response(@"err", reqId);
|
||||
r[@"msg"] = @"missing ipa path";
|
||||
return r;
|
||||
}
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:ipaPath]) {
|
||||
NSMutableDictionary *r = vp_make_response(@"err", reqId);
|
||||
r[@"msg"] = [NSString stringWithFormat:@"IPA not found: %@", ipaPath];
|
||||
return r;
|
||||
}
|
||||
|
||||
NSString *helperPath = find_trollstore_lite_helper();
|
||||
if (helperPath.length == 0) {
|
||||
NSMutableDictionary *r = vp_make_response(@"err", reqId);
|
||||
r[@"msg"] = @"TrollStore Lite helper not found in guest";
|
||||
return r;
|
||||
}
|
||||
|
||||
NSString *output = @"";
|
||||
int ret = run_process_with_output(helperPath, @[ @"install", ipaPath ], &output);
|
||||
if (ret != 0) {
|
||||
NSMutableDictionary *r = vp_make_response(@"err", reqId);
|
||||
NSString *trimmed = [output stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
if (trimmed.length > 4000) {
|
||||
trimmed = [trimmed substringToIndex:4000];
|
||||
}
|
||||
r[@"msg"] = trimmed.length > 0
|
||||
? [NSString stringWithFormat:@"trollstorehelper returned %d\n%@", ret, trimmed]
|
||||
: [NSString stringWithFormat:@"trollstorehelper returned %d", ret];
|
||||
return r;
|
||||
}
|
||||
|
||||
if ([registration isEqualToString:@"User"] && bundleId.length > 0) {
|
||||
NSString *appPath = nil;
|
||||
for (int attempt = 0; attempt < 10; attempt++) {
|
||||
appPath = find_trollstore_lite_app_path_for_bundle_id(bundleId);
|
||||
if (appPath.length > 0) break;
|
||||
usleep(200 * 1000);
|
||||
}
|
||||
|
||||
if (appPath.length == 0) {
|
||||
NSMutableDictionary *r = vp_make_response(@"err", reqId);
|
||||
r[@"msg"] = [NSString stringWithFormat:@"installed but failed to locate app path for %@", bundleId];
|
||||
return r;
|
||||
}
|
||||
|
||||
NSString *registrationOutput = @"";
|
||||
int registrationRet = run_process_with_output(
|
||||
helperPath,
|
||||
@[ @"modify-registration", appPath, @"User" ],
|
||||
®istrationOutput
|
||||
);
|
||||
if (registrationRet != 0) {
|
||||
NSMutableDictionary *r = vp_make_response(@"err", reqId);
|
||||
NSString *trimmed = [registrationOutput stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
if (trimmed.length > 4000) {
|
||||
trimmed = [trimmed substringToIndex:4000];
|
||||
}
|
||||
r[@"msg"] = trimmed.length > 0
|
||||
? [NSString stringWithFormat:@"installed, but switch-to-user failed (%d)\n%@", registrationRet, trimmed]
|
||||
: [NSString stringWithFormat:@"installed, but switch-to-user failed (%d)", registrationRet];
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:ipaPath error:nil];
|
||||
|
||||
NSMutableDictionary *r = vp_make_response(@"ok", reqId);
|
||||
if ([registration isEqualToString:@"User"]) {
|
||||
r[@"msg"] = [NSString stringWithFormat:@"Installed via TrollStore Lite and switched to User: %@", ipaPath.lastPathComponent];
|
||||
} else {
|
||||
r[@"msg"] = [NSString stringWithFormat:@"Installed via TrollStore Lite: %@", ipaPath.lastPathComponent];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// MARK: - Auto-update
|
||||
|
||||
/// Receive raw binary from host, write to CACHE_PATH, chmod +x.
|
||||
@@ -410,10 +203,6 @@ static NSDictionary *handle_command(NSDictionary *msg) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if ([type isEqualToString:@"tslite_install"]) {
|
||||
return handle_trollstore_install(msg);
|
||||
}
|
||||
|
||||
if ([type isEqualToString:@"ipa_install"]) {
|
||||
return vp_handle_custom_install(msg);
|
||||
}
|
||||
@@ -468,7 +257,6 @@ static BOOL handle_client(int fd) {
|
||||
NSMutableArray *caps = [NSMutableArray arrayWithObjects:@"hid", @"devmode", @"file", nil];
|
||||
if (vp_location_available()) [caps addObject:@"location"];
|
||||
if (vp_custom_installer_available()) [caps addObject:@"ipa_install"];
|
||||
if (find_trollstore_lite_helper()) [caps addObject:@"tslite_install"];
|
||||
|
||||
NSMutableDictionary *helloResp = [@{
|
||||
@"v": @PROTOCOL_VERSION,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#import "vphoned_install.h"
|
||||
#import "unarchive.h"
|
||||
|
||||
#import <Security/Security.h>
|
||||
#include <dlfcn.h>
|
||||
@@ -28,37 +29,17 @@ OSStatus SecStaticCodeCreateWithPathAndAttributes(
|
||||
OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags, CFDictionaryRef *information);
|
||||
extern CFStringRef kSecCodeInfoEntitlementsDict;
|
||||
|
||||
extern NSString *LSInstallTypeKey;
|
||||
|
||||
@interface LSBundleProxy : NSObject
|
||||
@property (nonatomic, readonly) NSString *bundleIdentifier;
|
||||
@property (nonatomic) NSURL *dataContainerURL;
|
||||
@property (nonatomic, readonly) NSURL *bundleContainerURL;
|
||||
- (NSString *)localizedName;
|
||||
@end
|
||||
|
||||
@interface LSApplicationProxy : LSBundleProxy
|
||||
@interface LSApplicationProxy : NSObject
|
||||
+ (instancetype)applicationProxyForIdentifier:(NSString *)identifier;
|
||||
+ (instancetype)applicationProxyForBundleURL:(NSURL *)bundleURL;
|
||||
@property NSURL *bundleURL;
|
||||
@property NSString *bundleType;
|
||||
@property NSString *canonicalExecutablePath;
|
||||
@property (nonatomic, readonly) NSDictionary *groupContainerURLs;
|
||||
@property (nonatomic, readonly) NSArray *plugInKitPlugins;
|
||||
@property (nonatomic, readonly) NSString *bundleIdentifier;
|
||||
@property (nonatomic, readonly) NSURL *bundleURL;
|
||||
@property (getter=isInstalled, nonatomic, readonly) BOOL installed;
|
||||
@property (getter=isPlaceholder, nonatomic, readonly) BOOL placeholder;
|
||||
@property (getter=isRestricted, nonatomic, readonly) BOOL restricted;
|
||||
@property (nonatomic, readonly) NSSet *claimedURLSchemes;
|
||||
@property (nonatomic, readonly) NSString *applicationType;
|
||||
@end
|
||||
|
||||
@interface LSApplicationWorkspace : NSObject
|
||||
+ (instancetype)defaultWorkspace;
|
||||
- (BOOL)registerApplicationDictionary:(NSDictionary *)dict;
|
||||
- (BOOL)unregisterApplication:(id)arg1;
|
||||
- (BOOL)installApplication:(NSURL *)appPackageURL withOptions:(NSDictionary *)options error:(NSError **)error;
|
||||
- (BOOL)uninstallApplication:(NSString *)appId withOptions:(NSDictionary *)options;
|
||||
- (void)enumerateApplicationsOfType:(NSUInteger)type block:(void (^)(LSApplicationProxy *))block;
|
||||
@end
|
||||
|
||||
@interface LSEnumerator : NSEnumerator
|
||||
@@ -242,16 +223,6 @@ static NSString *vp_find_ldid_path(void) {
|
||||
}
|
||||
|
||||
|
||||
static NSString *vp_find_tar_path(void) {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
for (NSString *path in @[@"/var/jb/usr/bin/tar", @"/usr/bin/tar"]) {
|
||||
if ([fm isExecutableFileAtPath:path]) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static SecStaticCodeRef vp_get_static_code_ref(NSString *binaryPath) {
|
||||
if (binaryPath.length == 0) return NULL;
|
||||
|
||||
@@ -343,8 +314,7 @@ static int vp_sign_binary(
|
||||
}
|
||||
|
||||
static int vp_sign_app(NSString *appPath, NSString *certPath, NSString *ldidPath, NSString **errorOutput) {
|
||||
NSDictionary *appInfoDict = vp_info_dictionary_for_app_path(appPath);
|
||||
if (!appInfoDict) {
|
||||
if (!vp_info_dictionary_for_app_path(appPath)) {
|
||||
if (errorOutput) *errorOutput = @"missing app Info.plist";
|
||||
return 172;
|
||||
}
|
||||
@@ -772,26 +742,12 @@ static int vp_install_app_from_package(
|
||||
|
||||
static int vp_extract_package_to_directory(
|
||||
NSString *fileToExtract,
|
||||
NSString *packageFormat,
|
||||
NSString *extractionPath,
|
||||
NSString **detailOutput
|
||||
) {
|
||||
NSString *extractorPath = vp_find_tar_path();
|
||||
if (extractorPath.length == 0) {
|
||||
if (detailOutput) *detailOutput = @"no tar extractor found in guest";
|
||||
return 168;
|
||||
}
|
||||
|
||||
if (packageFormat.length > 0 && ![packageFormat isEqualToString:@"tar"]) {
|
||||
if (detailOutput) *detailOutput = [NSString stringWithFormat:@"unsupported package format: %@", packageFormat];
|
||||
return 168;
|
||||
}
|
||||
|
||||
NSArray<NSString *> *args = @[ @"-xf", fileToExtract, @"-C", extractionPath ];
|
||||
NSString *output = @"";
|
||||
int ret = vp_run_process_with_output(extractorPath, args, &output);
|
||||
int ret = extract(fileToExtract, extractionPath);
|
||||
if (ret != 0) {
|
||||
if (detailOutput) *detailOutput = output.length > 0 ? output : @"extractor returned a non-zero exit status";
|
||||
if (detailOutput) *detailOutput = @"libarchive extract() failed";
|
||||
return 168;
|
||||
}
|
||||
return 0;
|
||||
@@ -799,8 +755,7 @@ static int vp_extract_package_to_directory(
|
||||
|
||||
BOOL vp_custom_installer_available(void) {
|
||||
vp_load_private_frameworks();
|
||||
return vp_find_tar_path().length > 0
|
||||
&& NSClassFromString(@"MCMAppContainer") != Nil
|
||||
return NSClassFromString(@"MCMAppContainer") != Nil
|
||||
&& NSClassFromString(@"LSApplicationWorkspace") != Nil;
|
||||
}
|
||||
|
||||
@@ -809,7 +764,6 @@ NSDictionary *vp_handle_custom_install(NSDictionary *msg) {
|
||||
id reqId = msg[@"id"];
|
||||
NSString *ipaPath = msg[@"path"];
|
||||
NSString *registration = msg[@"registration"];
|
||||
NSString *packageFormat = msg[@"package_format"];
|
||||
NSString *certPath = msg[@"cert_path"];
|
||||
NSString *ldidPath = vp_find_ldid_path();
|
||||
BOOL forceSystem = [registration isEqualToString:@"System"];
|
||||
@@ -827,7 +781,6 @@ NSDictionary *vp_handle_custom_install(NSDictionary *msg) {
|
||||
if (!vp_custom_installer_available()) {
|
||||
NSMutableDictionary *response = vp_make_response(@"err", reqId);
|
||||
NSMutableArray<NSString *> *missing = [NSMutableArray array];
|
||||
if (vp_find_tar_path().length == 0) [missing addObject:@"extractor(tar)"];
|
||||
if (NSClassFromString(@"MCMAppContainer") == Nil) [missing addObject:@"MCMAppContainer"];
|
||||
if (NSClassFromString(@"LSApplicationWorkspace") == Nil) [missing addObject:@"LSApplicationWorkspace"];
|
||||
NSString *detail = missing.count > 0 ? [missing componentsJoinedByString:@", "] : @"unknown";
|
||||
@@ -851,7 +804,7 @@ NSDictionary *vp_handle_custom_install(NSDictionary *msg) {
|
||||
}
|
||||
|
||||
NSString *detail = @"";
|
||||
int extractRet = vp_extract_package_to_directory(ipaPath, packageFormat, tmpPackagePath, &detail);
|
||||
int extractRet = vp_extract_package_to_directory(ipaPath, tmpPackagePath, &detail);
|
||||
int installRet = 0;
|
||||
if (extractRet == 0) {
|
||||
installRet = vp_install_app_from_package(tmpPackagePath, forceSystem, certPath, ldidPath, &detail);
|
||||
|
||||
@@ -107,43 +107,6 @@ class VPhoneControl {
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func runHostProcess(executableURL: URL, arguments: [String]) throws -> String {
|
||||
let process = Process()
|
||||
process.executableURL = executableURL
|
||||
process.arguments = arguments
|
||||
|
||||
let stdout = Pipe()
|
||||
let stderr = Pipe()
|
||||
process.standardOutput = stdout
|
||||
process.standardError = stderr
|
||||
|
||||
try process.run()
|
||||
process.waitUntilExit()
|
||||
|
||||
let output = String(data: stdout.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
|
||||
let errorOutput = String(data: stderr.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
|
||||
if process.terminationStatus == 0 {
|
||||
return output
|
||||
}
|
||||
let detail = errorOutput.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
throw ControlError.protocolError(detail.isEmpty ? "host tool failed: \(executableURL.lastPathComponent)" : detail)
|
||||
}
|
||||
|
||||
private static func buildInstallArchive(fromIPA ipaURL: URL) throws -> URL {
|
||||
let fm = FileManager.default
|
||||
let tempRoot = fm.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
||||
let extractDir = tempRoot.appendingPathComponent("extract", isDirectory: true)
|
||||
try fm.createDirectory(at: extractDir, withIntermediateDirectories: true)
|
||||
|
||||
let dittoURL = URL(fileURLWithPath: "/usr/bin/ditto")
|
||||
_ = try runHostProcess(executableURL: dittoURL, arguments: ["-x", "-k", ipaURL.path, extractDir.path])
|
||||
|
||||
let tarURL = tempRoot.appendingPathComponent("package.tar")
|
||||
let tarTool = URL(fileURLWithPath: "/usr/bin/tar")
|
||||
_ = try runHostProcess(executableURL: tarTool, arguments: ["-cf", tarURL.path, "-C", extractDir.path, "."])
|
||||
return tarURL
|
||||
}
|
||||
|
||||
// MARK: - Guest Binary Hash
|
||||
|
||||
private func loadGuestBinary() {
|
||||
@@ -448,19 +411,15 @@ class VPhoneControl {
|
||||
}
|
||||
|
||||
private func installIPAWithBuiltInInstaller(localURL: URL) async throws -> String {
|
||||
let archiveURL = try Self.buildInstallArchive(fromIPA: localURL)
|
||||
let data: Data
|
||||
do {
|
||||
data = try Data(contentsOf: archiveURL)
|
||||
data = try Data(contentsOf: localURL)
|
||||
} catch {
|
||||
throw ControlError.protocolError("failed to read install archive: \(error)")
|
||||
}
|
||||
defer {
|
||||
try? FileManager.default.removeItem(at: archiveURL.deletingLastPathComponent())
|
||||
throw ControlError.protocolError("failed to read IPA: \(error)")
|
||||
}
|
||||
|
||||
let remoteDir = "/var/mobile/Documents/vphone-installs"
|
||||
let remoteName = "\(UUID().uuidString)-\(localURL.deletingPathExtension().lastPathComponent).tar"
|
||||
let remoteName = "\(UUID().uuidString)-\(localURL.lastPathComponent)"
|
||||
let remotePath = "\(remoteDir)/\(remoteName)"
|
||||
|
||||
var cleanupPaths = [remotePath]
|
||||
@@ -479,7 +438,6 @@ class VPhoneControl {
|
||||
"t": "ipa_install",
|
||||
"path": remotePath,
|
||||
"registration": "User",
|
||||
"package_format": "tar",
|
||||
]
|
||||
|
||||
if let signCertURL = Self.signCertURL() {
|
||||
|
||||
Reference in New Issue
Block a user