mirror of
https://github.com/cmclark00/retro-imager.git
synced 2025-05-18 07:55:21 +01:00
127 lines
3.4 KiB
C++
127 lines
3.4 KiB
C++
|
/*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
* Copyright (C) 2020 Raspberry Pi (Trading) Limited
|
||
|
*/
|
||
|
|
||
|
#include "macfile.h"
|
||
|
#include <unistd.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <security/Authorization.h>
|
||
|
#include <QDebug>
|
||
|
|
||
|
MacFile::MacFile(QObject *parent)
|
||
|
: QFile(parent)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Prevent that Qt thinks /dev/rdisk does not permit seeks because it does not report size */
|
||
|
bool MacFile::isSequential() const
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool MacFile::authOpen(const QByteArray &filename)
|
||
|
{
|
||
|
int fd = -1;
|
||
|
|
||
|
QByteArray right = "sys.openfile.readwrite."+filename;
|
||
|
AuthorizationItem item = {right, 0, nullptr, 0};
|
||
|
AuthorizationRights rights = {1, &item};
|
||
|
AuthorizationFlags flags = kAuthorizationFlagInteractionAllowed |
|
||
|
kAuthorizationFlagExtendRights |
|
||
|
kAuthorizationFlagPreAuthorize;
|
||
|
AuthorizationRef authRef;
|
||
|
if (AuthorizationCreate(&rights, nullptr, flags, &authRef) != 0)
|
||
|
return false;
|
||
|
|
||
|
AuthorizationExternalForm externalForm;
|
||
|
if (AuthorizationMakeExternalForm(authRef, &externalForm) != 0)
|
||
|
{
|
||
|
AuthorizationFree(authRef, 0);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const char *cmd = "/usr/libexec/authopen";
|
||
|
QByteArray mode = QByteArray::number(O_RDWR);
|
||
|
int pipe[2];
|
||
|
int stdinpipe[2];
|
||
|
::socketpair(AF_UNIX, SOCK_STREAM, 0, pipe);
|
||
|
::pipe(stdinpipe);
|
||
|
pid_t pid = ::fork();
|
||
|
if (pid == 0)
|
||
|
{
|
||
|
// child
|
||
|
::close(pipe[0]);
|
||
|
::close(stdinpipe[1]);
|
||
|
::dup2(pipe[1], STDOUT_FILENO);
|
||
|
::dup2(stdinpipe[0], STDIN_FILENO);
|
||
|
::execl(cmd, cmd, "-stdoutpipe", "-extauth", "-o", mode.data(), filename.data(), NULL);
|
||
|
::exit(-1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
::close(pipe[1]);
|
||
|
::close(stdinpipe[0]);
|
||
|
::write(stdinpipe[1], externalForm.bytes, sizeof(externalForm.bytes));
|
||
|
::close(stdinpipe[1]);
|
||
|
|
||
|
const size_t bufSize = CMSG_SPACE(sizeof(int));
|
||
|
char buf[bufSize];
|
||
|
struct iovec io_vec[1];
|
||
|
io_vec[0].iov_base = buf;
|
||
|
io_vec[0].iov_len = bufSize;
|
||
|
const size_t cmsgSize = CMSG_SPACE(sizeof(int));
|
||
|
char cmsg[cmsgSize];
|
||
|
|
||
|
struct msghdr msg = {0};
|
||
|
msg.msg_iov = io_vec;
|
||
|
msg.msg_iovlen = 1;
|
||
|
msg.msg_control = cmsg;
|
||
|
msg.msg_controllen = cmsgSize;
|
||
|
|
||
|
ssize_t size;
|
||
|
do {
|
||
|
size = recvmsg(pipe[0], &msg, 0);
|
||
|
} while (size == -1 && errno == EINTR);
|
||
|
|
||
|
qDebug() << "RECEIVED SIZE:" << size;
|
||
|
|
||
|
if (size > 0) {
|
||
|
struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg);
|
||
|
if (chdr && chdr->cmsg_type == SCM_RIGHTS) {
|
||
|
qDebug() << "SCMRIGHTS";
|
||
|
fd = *( (int*) (CMSG_DATA(chdr)) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
qDebug() << "NOT SCMRIGHTS";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pid_t wpid;
|
||
|
int status;
|
||
|
|
||
|
do {
|
||
|
wpid = ::waitpid(pid, &status, 0);
|
||
|
} while (wpid == -1 && errno == EINTR);
|
||
|
|
||
|
if (wpid == -1)
|
||
|
{
|
||
|
qDebug() << "waitpid() failed executing authopen";
|
||
|
return false;
|
||
|
}
|
||
|
if (WEXITSTATUS(status))
|
||
|
{
|
||
|
qDebug() << "authopen returned failure code" << WEXITSTATUS(status);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
qDebug() << "fd received:" << fd;
|
||
|
}
|
||
|
AuthorizationFree(authRef, 0);
|
||
|
|
||
|
return open(fd, QIODevice::ReadWrite | QIODevice::ExistingOnly | QIODevice::Unbuffered, QFileDevice::AutoCloseHandle);
|
||
|
}
|