]> git.saurik.com Git - apple/hfs.git/blob - livefiles_hfs_plugin/lf_hfs_raw_read_write.c
hfs-522.100.5.tar.gz
[apple/hfs.git] / livefiles_hfs_plugin / lf_hfs_raw_read_write.c
1 /* Copyright © 2017-2018 Apple Inc. All rights reserved.
2 *
3 * lf_hfs_raw_read_write.c
4 * livefiles_hfs
5 *
6 * Created by Or Haimovich on 19/3/18.
7 */
8
9 #include "lf_hfs_raw_read_write.h"
10 #include "lf_hfs_utils.h"
11 #include "lf_hfs_fsops_handler.h"
12 #include "lf_hfs_file_mgr_internal.h"
13 #include "lf_hfs_file_extent_mapping.h"
14 #include "lf_hfs_vfsutils.h"
15 #include <UserFS/UserVFS.h>
16
17 #define MAX_READ_WRITE_LENGTH (0x7ffff000)
18
19 #define ZERO_BUF_SIZE (1024*1024)
20
21 static void* gpvZeroBuf = NULL;
22
23
24 int
25 raw_readwrite_get_cluster_from_offset( vnode_t psVnode, uint64_t uWantedOffset, uint64_t* puStartCluster, uint64_t* puInClusterOffset, uint64_t* puContigousClustersInBytes )
26 {
27 uint32_t uSectorsInCluster = HFSTOVCB(psVnode->sFSParams.vnfs_mp->psHfsmount)->blockSize / HFSTOVCB(psVnode->sFSParams.vnfs_mp->psHfsmount)->hfs_physical_block_size;
28
29 uint64_t uStartSector = 0;
30 size_t uAvailableBytes = 0;
31
32 int iErr = MapFileBlockC( HFSTOVCB(psVnode->sFSParams.vnfs_mp->psHfsmount), VTOF(psVnode), MAX_READ_WRITE_LENGTH, uWantedOffset, (daddr64_t*)&uStartSector, &uAvailableBytes );
33 if ( iErr != 0 )
34 {
35 return iErr;
36 }
37
38 if (puStartCluster) {
39 *puStartCluster = uStartSector / uSectorsInCluster;
40 }
41
42 if (puInClusterOffset) {
43 *puInClusterOffset = (uStartSector % uSectorsInCluster) * HFSTOVCB(psVnode->sFSParams.vnfs_mp->psHfsmount)->hfs_physical_block_size;
44 }
45
46 if (puContigousClustersInBytes) {
47 *puContigousClustersInBytes = uAvailableBytes;
48 }
49 return iErr;
50 }
51
52 errno_t raw_readwrite_read_mount( vnode_t psMountVnode, uint64_t uBlockN, uint64_t uClusterSize, void* pvBuf, uint64_t uBufLen, uint64_t *puActuallyRead, uint64_t* puReadStartCluster ) {
53 int iErr = 0;
54 int iFD = VNODE_TO_IFD(psMountVnode);
55 uint64_t uWantedOffset = uBlockN * uClusterSize;
56
57 if (puReadStartCluster)
58 *puReadStartCluster = uBlockN;
59
60 hfs_assert( uBufLen >= uClusterSize );
61
62 ssize_t iReadBytes = pread(iFD, pvBuf, uBufLen, uWantedOffset);
63 if ( iReadBytes != (ssize_t)uBufLen )
64 {
65 iErr = ( (iReadBytes < 0) ? errno : EIO );
66 HFSLogLevel_e eLogLevel = (VNODE_TO_UNMOUNT_HINT(psMountVnode)==UVFSUnmountHintForce)?LEVEL_DEBUG:LEVEL_ERROR;
67 LFHFS_LOG( eLogLevel, "raw_readwrite_read_mount failed [%d]\n", iErr );
68 }
69
70 if (puActuallyRead)
71 *puActuallyRead = iReadBytes;
72
73 return iErr;
74 }
75
76 errno_t raw_readwrite_write_mount( vnode_t psMountVnode, uint64_t uBlockN, uint64_t uClusterSize, void* pvBuf, uint64_t uBufLen, uint64_t *piActuallyWritten, uint64_t* puWriteStartCluster ) {
77 int iErr = 0;
78 int iFD = VNODE_TO_IFD(psMountVnode);
79 uint64_t uWantedOffset = uBlockN * uClusterSize;
80 ssize_t uActuallyWritten = 0;
81
82 if (puWriteStartCluster)
83 *puWriteStartCluster = uBlockN;
84
85 hfs_assert( uBufLen >= uClusterSize );
86
87 uActuallyWritten = pwrite(iFD, pvBuf, (size_t)uBufLen, uWantedOffset);
88 if ( uActuallyWritten != (ssize_t)uBufLen ) {
89 iErr = ( (uActuallyWritten < 0) ? errno : EIO );
90 HFSLogLevel_e eLogLevel = (VNODE_TO_UNMOUNT_HINT(psMountVnode)==UVFSUnmountHintForce)?LEVEL_DEBUG:LEVEL_ERROR;
91 LFHFS_LOG( eLogLevel, "raw_readwrite_write_mount failed [%d]\n", iErr );
92 }
93
94 if (piActuallyWritten)
95 *piActuallyWritten = uActuallyWritten;
96
97 return iErr;
98 }
99
100 errno_t
101 raw_readwrite_read( vnode_t psVnode, uint64_t uOffset, void* pvBuf, uint64_t uLength, size_t *piActuallyRead, uint64_t* puReadStartCluster )
102 {
103 errno_t iErr = 0;
104 uint64_t uClusterSize = psVnode->sFSParams.vnfs_mp->psHfsmount->blockSize;
105 uint64_t uFileSize = ((struct filefork *)VTOF(psVnode))->ff_data.cf_blocks * uClusterSize;
106 uint64_t uActuallyRead = 0;
107 bool bFirstLoop = true;
108
109 *piActuallyRead = 0;
110 while ( *piActuallyRead < uLength )
111 {
112 uint64_t uCurrentCluster = 0;
113 uint64_t uInClusterOffset = 0;
114 uint64_t uContigousClustersInBytes = 0;
115
116 // Look for the location to read
117 iErr = raw_readwrite_get_cluster_from_offset( psVnode, uOffset, &uCurrentCluster, &uInClusterOffset, &uContigousClustersInBytes );
118 if ( iErr != 0 )
119 {
120 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_read: raw_readwrite_get_cluster_from_offset failed [%d]\n", iErr );
121 return iErr;
122 }
123
124 if ( bFirstLoop )
125 {
126 bFirstLoop = false;
127 if (puReadStartCluster)
128 *puReadStartCluster = uCurrentCluster;
129 }
130
131 // Stop reading if we've reached the end of the file
132 if ( (uContigousClustersInBytes == 0) || (uOffset >= uFileSize) )
133 {
134 break;
135 }
136
137 uint64_t uBytesToRead = MIN(uFileSize - uOffset, uLength - *piActuallyRead);
138
139 // Read data
140 iErr = raw_readwrite_read_internal( psVnode, uCurrentCluster, uContigousClustersInBytes, uOffset, uBytesToRead, pvBuf, &uActuallyRead );
141 if ( iErr != 0 )
142 {
143 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_read_internal: raw_readwrite_read_internal failed [%d]\n", iErr );
144 return iErr;
145 }
146
147 // Update the amount of bytes alreay read
148 *piActuallyRead += uActuallyRead;
149 // Update file offset
150 uOffset += uActuallyRead;
151 // Update buffer offset
152 pvBuf = (uint8_t*)pvBuf + uActuallyRead;
153 }
154
155 return iErr;
156 }
157
158 errno_t
159 raw_readwrite_read_internal( vnode_t psVnode, uint64_t uCluster, uint64_t uContigousClustersInBytes,
160 uint64_t uOffset, uint64_t uBytesToRead, void* pvBuf, uint64_t *piActuallyRead )
161 {
162 errno_t iErr = 0;
163 int iFD = VNODE_TO_IFD(psVnode);
164 struct hfsmount *hfsmp = VTOHFS(psVnode);
165 uint64_t uClusterSize = hfsmp->blockSize;
166 uint64_t uSectorSize = hfsmp->hfs_logical_block_size;
167 uint64_t uBytesToCopy = 0;
168
169 // Calculate offset - offset by sector and need to add the offset by sector
170 uint64_t uReadOffset = FSOPS_GetOffsetFromClusterNum( psVnode, uCluster ) + ( ROUND_DOWN(uOffset, uSectorSize) % uClusterSize );
171
172 // If offset not align to sector size, need to read only 1 sector and memcpy its end
173 if ( (uOffset % uSectorSize) != 0 )
174 {
175 void* pvBuffer = hfs_malloc(uSectorSize);
176 if (pvBuffer == NULL)
177 {
178 return ENOMEM;
179 }
180
181 uint64_t uInSectorOffset = uOffset % uSectorSize;
182 uBytesToCopy = MIN(uSectorSize - uInSectorOffset, uBytesToRead);
183
184 // Read the content of the file
185 ssize_t iReadBytes = pread( iFD, pvBuffer, uSectorSize, uReadOffset );
186 if ( iReadBytes != (ssize_t)uSectorSize )
187 {
188 iErr = ((iReadBytes < 0) ? errno : EIO);
189 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_read: pread failed to read wanted length\n" );
190 hfs_free(pvBuffer);
191 return iErr;
192 }
193 memcpy( (uint8_t *)pvBuf, (uint8_t *)pvBuffer+uInSectorOffset, uBytesToCopy );
194 hfs_free(pvBuffer);
195 }
196 // If uBytesToRead < uClusterSize, need to read 1 sector and memcpy the begining
197 else if (uBytesToRead < uSectorSize)
198 {
199 void* pvBuffer = hfs_malloc(uSectorSize);
200 if (pvBuffer == NULL)
201 {
202 return ENOMEM;
203 }
204
205 uBytesToCopy = uBytesToRead;
206
207 // Read the content of the file
208 ssize_t iReadBytes = pread( iFD, pvBuffer, uSectorSize, uReadOffset );
209 if ( iReadBytes != (ssize_t)uSectorSize )
210 {
211 iErr = ((iReadBytes < 0) ? errno : EIO);
212 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_read: pread failed to read wanted length\n" );
213 hfs_free(pvBuffer);
214 return iErr;
215 }
216
217 memcpy((uint8_t *)pvBuf, pvBuffer, uBytesToCopy);
218 hfs_free(pvBuffer);
219 }
220 // Can read buffer size chunk
221 else
222 {
223 uint64_t uAvailSectors = uContigousClustersInBytes / uSectorSize;
224 uint64_t uRemainingSectors = uBytesToRead / uSectorSize;
225
226 uBytesToCopy = MIN(uAvailSectors, uRemainingSectors) * uSectorSize;
227 uBytesToCopy = MIN( uBytesToCopy, MAX_READ_WRITE_LENGTH );
228
229 assert( (uBytesToCopy % uSectorSize) == 0 );
230 assert( (uReadOffset % uSectorSize) == 0 );
231
232 ssize_t iReadBytes = pread( iFD,(uint8_t *)pvBuf, (size_t)uBytesToCopy, uReadOffset ) ;
233 if ( iReadBytes != (ssize_t)uBytesToCopy )
234 {
235 iErr = ((iReadBytes < 0) ? errno : EIO);
236 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_read: pread failed to read wanted length\n" );
237 return iErr;
238 }
239 }
240
241 // Update the amount of bytes alreay read
242 *piActuallyRead = uBytesToCopy;
243
244 return iErr;
245 }
246
247 errno_t
248 raw_readwrite_write( vnode_t psVnode, uint64_t uOffset, void* pvBuf, uint64_t uLength, uint64_t *piActuallyWritten )
249 {
250 errno_t iErr = 0;
251 uint64_t uClusterSize = psVnode->sFSParams.vnfs_mp->psHfsmount->blockSize;
252 uint64_t uFileSize = ((struct filefork *)VTOF(psVnode))->ff_data.cf_blocks * uClusterSize;
253 uint64_t uActuallyWritten = 0;
254
255 *piActuallyWritten = 0;
256
257 // Fill the buffer until the buffer is full or till the end of the file
258 while ( *piActuallyWritten < uLength )
259 {
260 uint64_t uCurrentCluster = 0;
261 uint64_t uInClusterOffset = 0;
262 uint64_t uContigousClustersInBytes = 0;
263
264 iErr = raw_readwrite_get_cluster_from_offset(psVnode, uOffset, &uCurrentCluster, &uInClusterOffset, &uContigousClustersInBytes );
265 if ( iErr != 0 )
266 {
267 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_write: raw_readwrite_get_cluster_from_offset failed [%d]\n", iErr );
268 return iErr;
269 }
270
271 // Stop writing if we've reached the end of the file
272 if ( (uContigousClustersInBytes == 0) || (uOffset >= uFileSize) )
273 {
274 break;
275 }
276
277 /* Calculate how many bytes are still missing to add to the device
278 * If offset near end of file need to set only (uFileSize - uOffset)
279 * else need to write as much as left (uLength - uAcctuallyRead)
280 */
281 uint64_t uBytesToWrite = MIN(uFileSize - uOffset, uLength - *piActuallyWritten);
282
283 // Write data
284 iErr = raw_readwrite_write_internal( psVnode, uCurrentCluster, uContigousClustersInBytes, uOffset, uBytesToWrite, pvBuf, &uActuallyWritten );
285 if ( iErr != 0 )
286 {
287 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_read_internal: raw_readwrite_read_internal failed [%d]\n", iErr );
288 return iErr;
289 }
290
291 // Update the amount of bytes alreay written
292 *piActuallyWritten += uActuallyWritten;
293 // Update file offset
294 uOffset += uActuallyWritten;
295 // Update buffer offset
296 pvBuf = (uint8_t*)pvBuf + uActuallyWritten;
297 }
298
299 return iErr;
300 }
301
302 errno_t
303 raw_readwrite_write_internal( vnode_t psVnode, uint64_t uCluster, uint64_t uContigousClustersInBytes,
304 uint64_t uOffset, uint64_t uBytesToWrite, void* pvBuf, uint64_t *piActuallyWritten )
305 {
306 errno_t iErr = 0;
307 int iFD = VNODE_TO_IFD(psVnode);
308 struct hfsmount *hfsmp = VTOHFS(psVnode);
309 uint64_t uClusterSize = hfsmp->blockSize;
310 uint64_t uSectorSize = hfsmp->hfs_logical_block_size;
311 uint64_t uBytesToCopy = 0;
312
313 // Calculate offset - offset by sector and need to add the offset by sector
314 uint64_t uWriteOffset = FSOPS_GetOffsetFromClusterNum( psVnode, uCluster ) + ( ROUND_DOWN(uOffset, uSectorSize) % uClusterSize );
315
316 // If offset not align to sector size, need to read the existing data
317 // memcpy it's beginning and write back to the device
318 if ( (uOffset % uSectorSize) != 0 )
319 {
320 void* pvBuffer = hfs_malloc(uSectorSize);
321 if (pvBuffer == NULL)
322 {
323 return ENOMEM;
324 }
325
326 uint64_t uInSectorOffset = uOffset % uSectorSize;
327 uBytesToCopy = MIN( uBytesToWrite, uSectorSize - uInSectorOffset );
328
329 // Read the content of the existing file
330 ssize_t iReadBytes = pread(iFD, pvBuffer, uSectorSize, uWriteOffset);
331 if ( iReadBytes != (ssize_t)uSectorSize )
332 {
333 iErr = (iReadBytes < 0) ? errno : EIO;
334 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_write: pread failed to read wanted length\n" );
335 hfs_free(pvBuffer);
336 return iErr;
337 }
338
339 // memcpy the data from the given buffer
340 memcpy((uint8_t *)pvBuffer+uInSectorOffset, pvBuf, uBytesToCopy);
341
342 // Write the data into the device
343 ssize_t iWriteBytes = pwrite(iFD, pvBuffer, uSectorSize, uWriteOffset);
344 if ( iWriteBytes != (ssize_t)uSectorSize )
345 {
346 iErr = (iWriteBytes < 0) ? errno : EIO;
347 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_write: pwrite failed to write wanted length\n" );
348 hfs_free(pvBuffer);
349 return iErr;
350 }
351
352 hfs_free(pvBuffer);
353 }
354 // If uBytesToWrite < uSectorSize, need to R/M/W 1 sector.
355 else if ( uBytesToWrite < uSectorSize )
356 {
357 void* pvBuffer = hfs_malloc(uSectorSize);
358 if (pvBuffer == NULL)
359 {
360 return ENOMEM;
361 }
362
363 uBytesToCopy = uBytesToWrite;
364
365 // Read the content of the existing file
366 ssize_t iReadBytes = pread(iFD, pvBuffer, uSectorSize, uWriteOffset);
367 if ( iReadBytes != (ssize_t)uSectorSize )
368 {
369 iErr = (iReadBytes < 0) ? errno : EIO;
370 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_write: pread failed to read wanted length\n" );
371 hfs_free(pvBuffer);
372 return iErr;
373 }
374
375 // memcpy the last data
376 memcpy(pvBuffer, (uint8_t *)pvBuf, uBytesToCopy);
377
378 // Write the content to the file
379 ssize_t iWriteBytes = pwrite(iFD, pvBuffer, uSectorSize, uWriteOffset);
380 if ( iWriteBytes != (ssize_t)uSectorSize)
381 {
382 iErr = (iWriteBytes < 0) ? errno : EIO;
383 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_write: pwrite failed to write wanted length\n" );
384 hfs_free(pvBuffer);
385 return iErr;
386 }
387
388 hfs_free(pvBuffer);
389 }
390 // Can write buffer size chunk
391 else
392 {
393 uint64_t uAvailSectors = uContigousClustersInBytes / uSectorSize;
394 uint64_t uRemainingSectors = uBytesToWrite / uSectorSize;
395
396 uBytesToCopy = MIN(uAvailSectors, uRemainingSectors) * uSectorSize;
397 uBytesToCopy = MIN( uBytesToCopy, MAX_READ_WRITE_LENGTH );
398
399 assert( (uBytesToCopy % uSectorSize) == 0 );
400 assert( (uWriteOffset % uSectorSize) == 0 );
401
402 ssize_t iWriteBytes = pwrite(iFD, (uint8_t *)pvBuf, uBytesToCopy, uWriteOffset) ;
403 if ( iWriteBytes != (ssize_t) uBytesToCopy)
404 {
405 iErr = (iWriteBytes < 0) ? errno : EIO;
406 LFHFS_LOG( LEVEL_ERROR, "raw_readwrite_write: pwrite failed to write wanted length\n" );
407 return iErr;
408 }
409 }
410
411 // Update the amount of bytes alreay written
412 *piActuallyWritten = uBytesToCopy;
413
414 return iErr;
415 }
416
417 int
418 raw_readwrite_zero_fill_init()
419 {
420 if ( gpvZeroBuf )
421 {
422 return 0;
423 }
424
425 gpvZeroBuf = hfs_malloc( ZERO_BUF_SIZE );
426 if ( gpvZeroBuf == NULL )
427 {
428 return ENOMEM;
429 }
430
431 memset( gpvZeroBuf, 0, ZERO_BUF_SIZE );
432
433 return 0;
434 }
435
436 void
437 raw_readwrite_zero_fill_de_init()
438 {
439 if ( gpvZeroBuf )
440 {
441 hfs_free( gpvZeroBuf );
442 }
443
444 gpvZeroBuf = NULL;
445 }
446
447 int
448 raw_readwrite_zero_fill_fill( hfsmount_t* psMount, uint64_t uBlock, uint32_t uContigBlocks )
449 {
450 int iErr = 0;
451 int64_t lWriteSize = 0;
452 uint64_t uCurWriteOffset = 0;
453 uint64_t uCurWriteLen = 0;
454 uint64_t uDataWriten = 0;
455
456 if ( gpvZeroBuf == NULL )
457 {
458 iErr = EINVAL;
459 goto exit;
460 }
461
462 uint64_t uLength = uContigBlocks*psMount->blockSize;
463 uint64_t uOffset = psMount->hfsPlusIOPosOffset + uBlock*psMount->blockSize;
464
465 while ( uDataWriten < uLength )
466 {
467 uCurWriteOffset = uOffset+uDataWriten;
468 uCurWriteLen = MIN( (uLength - uDataWriten), ZERO_BUF_SIZE );
469
470 lWriteSize = pwrite( psMount->hfs_devvp->psFSRecord->iFD, gpvZeroBuf, uCurWriteLen, uCurWriteOffset );
471 if ( lWriteSize != (int64_t)uCurWriteLen )
472 {
473 iErr = errno;
474 goto exit;
475 }
476
477 uDataWriten += uCurWriteLen;
478 }
479
480 exit:
481 return iErr;
482 }
483
484 errno_t
485 raw_readwrite_zero_fill_last_block_suffix( vnode_t psVnode )
486 {
487
488 int iErr = 0;
489 int iFD = (VPTOFSRECORD(psVnode))->iFD;
490 struct filefork *fp = VTOF(psVnode);
491 uint32_t uBlockSize = HFSTOVCB(psVnode->sFSParams.vnfs_mp->psHfsmount)->blockSize;
492 uint32_t uBytesToKeep = fp->ff_size % uBlockSize;
493 uint64_t uBlockN = 0;
494 uint64_t uContigousClustersInBytes;
495 uint64_t uInClusterOffset;
496
497 uint8_t* puClusterData = NULL;
498
499 iErr = raw_readwrite_get_cluster_from_offset(psVnode, fp->ff_size - uBytesToKeep, &uBlockN, &uInClusterOffset, &uContigousClustersInBytes);
500 if ( iErr != 0 )
501 {
502 goto exit;
503 }
504
505 // Allocate buffer for cluster.
506 puClusterData = hfs_malloc( uBlockSize );
507 if ( puClusterData == NULL )
508 {
509 iErr = ENOMEM;
510 goto exit;
511 }
512
513 // Read the last cluster.
514 size_t uBytesRead = pread( iFD, puClusterData, uBlockSize, FSOPS_GetOffsetFromClusterNum( psVnode, uBlockN ) );
515 if ( uBytesRead != uBlockSize )
516 {
517 iErr = errno;
518 goto exit;
519 }
520
521 memset( puClusterData+uBytesToKeep, 0, uBlockSize-uBytesToKeep );
522
523 // Write the last cluster.
524 size_t uBytesWrite = pwrite( iFD, puClusterData, uBlockSize, FSOPS_GetOffsetFromClusterNum( psVnode, uBlockN ) );
525 if ( uBytesWrite != uBlockSize )
526 {
527 iErr = errno;
528 goto exit;
529 }
530
531 exit:
532 if ( puClusterData )
533 hfs_free( puClusterData );
534
535 return iErr;
536 }
537