1
1
/*
2
2
* Fedora Media Writer
3
3
* Copyright (C) 2016 Martin Bříza <[email protected] >
4
+ * Copyright (C) 2020 Jan Grulich <[email protected] >
4
5
*
5
6
* This program is free software; you can redistribute it and/or
6
7
* modify it under the terms of the GNU General Public License
28
29
#include < QDebug>
29
30
30
31
#include < lzma.h>
32
+ #include < unistd.h>
33
+ #include < sys/socket.h>
34
+ #include < sys/stat.h>
35
+ #include < sys/types.h>
36
+ #include < fcntl.h>
31
37
32
38
#include " isomd5/libcheckisomd5.h"
33
39
40
+ AuthOpenProcess::AuthOpenProcess (int parentSocket, int clientSocket, const QString &device, QObject *parent)
41
+ : QProcess(parent)
42
+ , m_parentSocket(parentSocket)
43
+ , m_clientSocket(clientSocket)
44
+ {
45
+ setProgram (QStringLiteral (" /usr/libexec/authopen" ));
46
+ setArguments ({QStringLiteral (" -stdoutpipe" ), QStringLiteral (" -o" ), QString::number (O_RDWR), QStringLiteral (" /dev/r" ) + device});
47
+ }
48
+
49
+ void AuthOpenProcess::setupChildProcess ()
50
+ {
51
+ ::close (m_parentSocket);
52
+ ::dup2 (m_clientSocket, STDOUT_FILENO);
53
+ }
54
+
34
55
WriteJob::WriteJob (const QString &what, const QString &where)
35
56
: QObject(nullptr ), what(what), where(where)
36
57
{
@@ -55,20 +76,77 @@ int WriteJob::onMediaCheckAdvanced(long long offset, long long total) {
55
76
}
56
77
57
78
void WriteJob::work () {
79
+ int sockets[2 ];
80
+ int result = socketpair (AF_UNIX, SOCK_STREAM, 0 , sockets);
81
+ if (result == - 1 ) {
82
+ err << tr (" Unable to allocate socket pair" ) << " \n " ;
83
+ err.flush ();
84
+ return ;
85
+ }
86
+
87
+ QProcess diskUtil;
88
+ diskUtil.setProgram (" diskutil" );
89
+ diskUtil.setArguments (QStringList () << " unmountDisk" << where);
90
+ diskUtil.start ();
91
+ diskUtil.waitForFinished ();
92
+
93
+ AuthOpenProcess p (sockets[0 ], sockets[1 ], where);
94
+ p.start (QIODevice::ReadOnly);
95
+
96
+ close (sockets[1 ]);
97
+
98
+ int fd = -1 ;
99
+ const size_t bufferSize = sizeof (struct cmsghdr ) + sizeof (int );
100
+ char buffer[bufferSize];
101
+
102
+ struct iovec io_vec[1 ];
103
+ io_vec[0 ].iov_len = bufferSize;
104
+ io_vec[0 ].iov_base = buffer;
105
+
106
+ const socklen_t socketSize = static_cast <socklen_t >(CMSG_SPACE (sizeof (int )));
107
+ char cmsg_socket[socketSize];
108
+
109
+ struct msghdr message = { 0 };
110
+ message.msg_iov = io_vec;
111
+ message.msg_iovlen = 1 ;
112
+ message.msg_control = cmsg_socket;
113
+ message.msg_controllen = socketSize;
114
+
115
+ ssize_t size = recvmsg (sockets[0 ], &message, 0 );
116
+
117
+ if (size > 0 ) {
118
+ struct cmsghdr *socketHeader = CMSG_FIRSTHDR (&message);
119
+ if (socketHeader && socketHeader->cmsg_level == SOL_SOCKET && socketHeader->cmsg_type == SCM_RIGHTS) {
120
+ fd = *reinterpret_cast <int *>(CMSG_DATA (socketHeader));
121
+ }
122
+ }
123
+
124
+ p.waitForFinished ();
125
+
126
+ if (fd == -1 ) {
127
+ err << tr (" Unable to open destination for writing" ) << " \n " ;
128
+ err.flush ();
129
+ return ;
130
+ }
131
+
58
132
out << " WRITE\n " ;
59
133
out.flush ();
60
134
135
+ QFile target;
136
+ target.open (fd, QIODevice::ReadWrite, QFileDevice::AutoCloseHandle);
137
+
61
138
if (what.endsWith (" .xz" )) {
62
- if (!writeCompressed ()) {
139
+ if (!writeCompressed (target )) {
63
140
return ;
64
141
}
65
142
}
66
143
else {
67
- if (!writePlain ()) {
144
+ if (!writePlain (target )) {
68
145
return ;
69
146
}
70
147
}
71
- check ();
148
+
149
+ check (target);
72
150
}
73
151
74
152
void WriteJob::onFileChanged (const QString &path) {
@@ -80,24 +158,19 @@ void WriteJob::onFileChanged(const QString &path) {
80
158
work ();
81
159
}
82
160
83
- bool WriteJob::writePlain () {
161
+ bool WriteJob::writePlain (QFile &target ) {
84
162
qint64 bytesTotal = 0 ;
85
163
86
164
QFile source (what);
87
- QFile target (" /dev/r" +where);
88
165
QByteArray buffer (BLOCK_SIZE, 0 );
89
166
90
167
out << -1 << " \n " ;
91
168
out.flush ();
92
169
93
170
QProcess diskUtil;
94
171
diskUtil.setProgram (" diskutil" );
95
- diskUtil.setArguments (QStringList () << " unmountDisk" << where);
96
- diskUtil.start ();
97
- diskUtil.waitForFinished ();
98
172
99
173
source.open (QIODevice::ReadOnly);
100
- target.open (QIODevice::WriteOnly);
101
174
102
175
while (source.isReadable () && !source.atEnd () && target.isWritable ()) {
103
176
qint64 bytes = source.read (buffer.data (), BLOCK_SIZE);
@@ -129,7 +202,7 @@ bool WriteJob::writePlain() {
129
202
return true ;
130
203
}
131
204
132
- bool WriteJob::writeCompressed () {
205
+ bool WriteJob::writeCompressed (QFile &target ) {
133
206
qint64 totalRead = 0 ;
134
207
135
208
lzma_stream strm = LZMA_STREAM_INIT;
@@ -140,8 +213,6 @@ bool WriteJob::writeCompressed() {
140
213
141
214
QFile source (what);
142
215
source.open (QIODevice::ReadOnly);
143
- QFile target (" /dev/r" +where);
144
- target.open (QIODevice::WriteOnly);
145
216
146
217
ret = lzma_stream_decoder (&strm, MEDIAWRITER_LZMA_LIMIT, LZMA_CONCATENATED);
147
218
if (ret != LZMA_OK) {
@@ -210,9 +281,7 @@ bool WriteJob::writeCompressed() {
210
281
}
211
282
}
212
283
213
- void WriteJob::check () {
214
- QFile target (" /dev/r" +where);
215
- target.open (QIODevice::ReadOnly);
284
+ void WriteJob::check (QFile &target) {
216
285
out << " CHECK\n " ;
217
286
out.flush ();
218
287
switch (mediaCheckFD (target.handle (), &WriteJob::staticOnMediaCheckAdvanced, this )) {
0 commit comments