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