]> git.saurik.com Git - apple/hfs.git/blob - livefiles_hfs_plugin/lf_hfs_fsops_handler.c
hfs-522.100.5.tar.gz
[apple/hfs.git] / livefiles_hfs_plugin / lf_hfs_fsops_handler.c
1 /* Copyright © 2017-2018 Apple Inc. All rights reserved.
2 *
3 * lf_hfs_fsops_handler.c
4 * livefiles_hfs
5 *
6 * Created by Yakov Ben Zaken on 31/12/2017.
7 */
8
9 #include <sys/attr.h>
10 #include "lf_hfs.h"
11 #include "lf_hfs_fsops_handler.h"
12 #include "lf_hfs_dirops_handler.h"
13 #include "lf_hfs_fileops_handler.h"
14 #include "lf_hfs_logger.h"
15 #include "lf_hfs_cnode.h"
16 #include "lf_hfs_vnode.h"
17 #include "lf_hfs_endian.h"
18 #include "lf_hfs_vfsops.h"
19 #include "lf_hfs_vfsutils.h"
20 #include "lf_hfs_generic_buf.h"
21 #include "lf_hfs_raw_read_write.h"
22 #include "lf_hfs_journal.h"
23 #include "lf_hfs_vfsops.h"
24 #include "lf_hfs_mount.h"
25 #include "lf_hfs_readwrite_ops.h"
26
27 #include "lf_hfs_vnops.h"
28
29 static int
30 FSOPS_GetRootVnode(struct vnode* psDevVnode, struct vnode** ppsRootVnode)
31 {
32 return (hfs_vfs_root(psDevVnode->sFSParams.vnfs_mp, ppsRootVnode));
33 }
34
35 //---------------------------------- API Implementation ------------------------------------------
36
37 uint64_t FSOPS_GetOffsetFromClusterNum(vnode_t vp, uint64_t uClusterNum)
38 {
39 return (HFSTOVCB(vp->sFSParams.vnfs_mp->psHfsmount)->hfsPlusIOPosOffset + uClusterNum * HFSTOVCB(vp->sFSParams.vnfs_mp->psHfsmount)->blockSize);
40 }
41
42 int
43 LFHFS_Taste ( int iFd )
44 {
45 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_Taste %d\n", iFd);
46
47 int iError = 0;
48 u_int32_t log_blksize;
49 void* pvBuffer = NULL;
50
51 HFSMasterDirectoryBlock *psMasterBlock = hfs_malloc(kMDBSize);
52 if ( psMasterBlock == NULL )
53 {
54 iError = ENOMEM;
55 LFHFS_LOG(LEVEL_ERROR, "HFS_Taste: failed to malloc psMasterBlock\n");
56 goto exit;
57 }
58
59 /* Get the logical block size (treated as physical block size everywhere) */
60 if (ioctl(iFd, DKIOCGETBLOCKSIZE, &log_blksize))
61 {
62 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: DKIOCGETBLOCKSIZE failed - setting to default -512\n");
63 log_blksize = kMDBSize;
64 }
65
66 if (log_blksize == 0 || log_blksize > 1024*1024*1024)
67 {
68 LFHFS_LOG(LEVEL_ERROR, "hfs_mountfs: logical block size 0x%x looks bad. Not mounting.\n", log_blksize);
69 iError = ENXIO;
70 goto exit;
71 }
72
73 if (log_blksize > kMDBSize)
74 {
75 pvBuffer = hfs_malloc(log_blksize);
76 if ( pvBuffer == NULL )
77 {
78 iError = ENOMEM;
79 LFHFS_LOG(LEVEL_ERROR, "HFS_Taste: failed to malloc pvBuffer\n");
80 goto exit;
81 }
82 }
83 else
84 {
85 pvBuffer = (void*) psMasterBlock;
86 }
87
88 // Read VolumeHeader from offset 1024
89 off_t uVolHdrOffset = 1024;
90 off_t uBlockNum = uVolHdrOffset / log_blksize;
91 off_t uOffsetInBlock = uVolHdrOffset % log_blksize;
92
93 ssize_t iReadBytes = pread(iFd, pvBuffer, log_blksize, uBlockNum * log_blksize);
94 if ( iReadBytes < uOffsetInBlock + kMDBSize ) {
95 iError = (iReadBytes < 0) ? errno : EIO;
96 LFHFS_LOG(LEVEL_ERROR, "HFS_Taste: failed to read Master Directory Block with err %d (%ld)\n", iError, iReadBytes);
97
98 if (log_blksize > kMDBSize) {
99 hfs_free(pvBuffer);
100 }
101 goto exit;
102 }
103
104 if (log_blksize > kMDBSize) {
105 memcpy(psMasterBlock, pvBuffer + uOffsetInBlock, kMDBSize);
106 hfs_free(pvBuffer);
107 }
108
109 //Validate Signiture
110 uint32_t drSigWord = SWAP_BE16(psMasterBlock->drSigWord);
111 if ((drSigWord != kHFSPlusSigWord) &&
112 (drSigWord != kHFSXSigWord))
113 {
114 iError = EINVAL;
115 LFHFS_LOG(LEVEL_DEBUG, "HFS_Taste: invalid volume signature %d\n", SWAP_BE16(psMasterBlock->drSigWord));
116 goto exit;
117 }
118
119 exit:
120 if (psMasterBlock)
121 hfs_free(psMasterBlock);
122 return iError;
123 }
124
125 int
126 LFHFS_ScanVols (int iFd, UVFSScanVolsRequest *psRequest, UVFSScanVolsReply *psReply )
127 {
128 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_ScanVols\n");
129
130 if ( psRequest == NULL || psReply == NULL )
131 {
132 return EINVAL;
133 }
134 else if (psRequest->sr_volid > 0)
135 {
136 return UVFS_SCANVOLS_EOF_REACHED;
137 }
138
139 // Tell UVFS that we have a single, non-access controlled volume.
140 psReply->sr_volid = 0;
141 psReply->sr_volac = UAC_UNLOCKED;
142
143 return hfs_ScanVolGetVolName(iFd, psReply->sr_volname);
144 }
145
146 int
147 LFHFS_Init ( void )
148 {
149 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_Init\n");
150
151 int iErr = 0;
152
153 iErr = LFHFS_LoggerInit();
154 if ( iErr != 0 )
155 {
156 goto exit;
157 }
158
159 iErr = raw_readwrite_zero_fill_init();
160 if ( iErr != 0 )
161 {
162 goto exit;
163 }
164
165 hfs_chashinit();
166
167 // Initializing Buffer cache
168 lf_hfs_generic_buf_cache_init();
169
170 BTReserveSetup();
171
172 journal_init();
173
174 exit:
175 return iErr;
176 }
177
178 void
179 LFHFS_Fini ( void )
180 {
181 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_Fini\n");
182
183 raw_readwrite_zero_fill_de_init();
184
185 // De-Initializing Buffer cache
186 lf_hfs_generic_buf_cache_deinit();
187 }
188
189 int
190 LFHFS_Mount ( int iFd, UVFSVolumeId puVolId, UVFSMountFlags puMountFlags,
191 __unused UVFSVolumeCredential *psVolumeCreds, UVFSFileNode *ppsRootNode )
192 {
193 LFHFS_LOG(LEVEL_DEBUG, "HFS_Mount %d\n", iFd);
194 int iError = 0;
195
196 struct mount* psMount = hfs_mallocz(sizeof(struct mount));
197 struct vnode* psDevVnode = hfs_mallocz(sizeof(struct vnode));
198 struct cnode* psDevCnode = hfs_mallocz(sizeof(struct cnode));
199 struct filefork* psDevFileFork = hfs_mallocz(sizeof(struct filefork));
200 FileSystemRecord_s *psFSRecord = hfs_mallocz(sizeof(FileSystemRecord_s));
201
202 if ( psMount == NULL || psDevVnode == NULL || psDevCnode == NULL || psDevFileFork == NULL || psFSRecord == NULL )
203 {
204 iError = ENOMEM;
205 LFHFS_LOG(LEVEL_ERROR, "HFS_Mount: failed to malloc initial system files\n");
206 goto fail;
207 }
208
209 if (puVolId != 0)
210 {
211 iError = EINVAL;
212 LFHFS_LOG(LEVEL_ERROR, "HFS_Mount: unknown volume ID\n");
213 goto fail;
214 }
215
216 psFSRecord->iFD = iFd;
217 psDevVnode->psFSRecord = psFSRecord;
218 psDevVnode->sFSParams.vnfs_marksystem = 1;
219 psDevVnode->bIsMountVnode = true;
220
221 // Initializing inputs for hfs_mount
222 psDevFileFork->ff_data.cf_blocks = 3;
223 psDevFileFork->ff_data.cf_extents[0].blockCount = 1;
224 psDevFileFork->ff_data.cf_extents[0].startBlock = 0;
225
226 psDevVnode->sFSParams.vnfs_fsnode = psDevCnode;
227 psDevCnode->c_vp = psDevVnode;
228 psDevVnode->is_rsrc = false;
229 psDevCnode->c_datafork = psDevFileFork;
230 psDevVnode->sFSParams.vnfs_mp = psMount;
231
232 psMount->mnt_flag = (puMountFlags == UVFS_MOUNT_RDONLY)? MNT_RDONLY : 0;
233 // Calling to kext hfs_mount
234 iError = hfs_mount(psMount, psDevVnode, 0);
235 if (iError)
236 goto fail;
237
238 struct vnode* psRootVnode;
239 // Creating root vnode
240 iError = FSOPS_GetRootVnode(psDevVnode,&psRootVnode);
241 if (iError)
242 goto fail;
243 *ppsRootNode = (UVFSFileNode) psRootVnode;
244
245 goto end;
246
247 fail:
248 if (psFSRecord)
249 hfs_free(psFSRecord);
250 if (psMount)
251 hfs_free(psMount);
252 if (psDevVnode)
253 hfs_free(psDevVnode);
254 if (psDevCnode)
255 hfs_free(psDevCnode);
256 if (psDevFileFork)
257 hfs_free(psDevFileFork);
258 end:
259 return iError;
260 }
261
262 int
263 LFHFS_Unmount ( UVFSFileNode psRootNode, UVFSUnmountHint hint )
264 {
265 VERIFY_NODE_IS_VALID(psRootNode);
266 LFHFS_LOG(LEVEL_DEBUG, "HFS_Unmount (psRootNode %p) (hint %u)\n", psRootNode, hint);
267
268 int iError = 0;
269 struct vnode *psRootVnode = (struct vnode*) psRootNode;
270 FileSystemRecord_s *psFSRecord = VPTOFSRECORD(psRootVnode);
271 struct mount *psMount = psRootVnode->sFSParams.vnfs_mp;
272 struct cnode *psDevCnode = VTOHFS(psRootVnode)->hfs_devvp->sFSParams.vnfs_fsnode;
273 struct hfsmount *psHfsMp = psMount->psHfsmount;
274 psFSRecord->uUnmountHint = hint;
275
276 #if HFS_CRASH_TEST
277 CRASH_ABORT(CRASH_ABORT_ON_UNMOUNT, psHfsMp, NULL);
278 #endif
279
280 hfs_vnop_reclaim(psRootVnode);
281
282 if (!psHfsMp->jnl) {
283 hfs_flushvolumeheader(psHfsMp, HFS_FVH_SKIP_TRANSACTION | HFS_FVH_MARK_UNMOUNT);
284 }
285
286 hfs_unmount(psMount);
287
288 hfs_free(psFSRecord);
289 hfs_free(psMount);
290 hfs_free(psDevCnode->c_datafork);
291 hfs_free(psDevCnode);
292
293 return iError;
294 }
295
296 int
297 LFHFS_SetFSAttr ( UVFSFileNode psNode, const char *pcAttr, const UVFSFSAttributeValue *psAttrVal, size_t uLen, UVFSFSAttributeValue *psOutAttrVal, size_t uOutLen )
298 {
299 #pragma unused (psNode, pcAttr, psAttrVal, uLen)
300 VERIFY_NODE_IS_VALID(psNode);
301
302 if (pcAttr == NULL || psAttrVal == NULL || psOutAttrVal == NULL) return EINVAL;
303
304 if (strcmp(pcAttr, LI_FSATTR_PREALLOCATE) == 0)
305 {
306 if (uLen < sizeof (UVFSFSAttributeValue) || uOutLen < sizeof (UVFSFSAttributeValue))
307 return EINVAL;
308
309 LIFilePreallocateArgs_t* psPreAllocReq = (LIFilePreallocateArgs_t *) ((void *) psAttrVal->fsa_opaque);
310 LIFilePreallocateArgs_t* psPreAllocRes = (LIFilePreallocateArgs_t *) ((void *) psOutAttrVal->fsa_opaque);
311
312 memcpy (psPreAllocRes, psPreAllocReq, sizeof(LIFilePreallocateArgs_t));
313 return hfs_vnop_preallocate(psNode, psPreAllocReq, psPreAllocRes);
314 }
315
316 return ENOTSUP;
317 }
318
319 int
320 LFHFS_GetFSAttr ( UVFSFileNode psNode, const char *pcAttr, UVFSFSAttributeValue *psAttrVal, size_t uLen, size_t *puRetLen )
321 {
322 VERIFY_NODE_IS_VALID(psNode);
323 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_GetFSAttr (psNode %p)\n", psNode);
324
325 int iError = 0;
326 vnode_t psVnode = (vnode_t)psNode;
327 struct hfsmount *psMount = psVnode->sFSParams.vnfs_mp->psHfsmount;
328
329 if (strcmp(pcAttr, UVFS_FSATTR_PC_LINK_MAX)==0)
330 {
331 *puRetLen = sizeof(uint64_t);
332 if (uLen < *puRetLen)
333 {
334 return E2BIG;
335 }
336
337 if ( vnode_isreg(psVnode) )
338 {
339 psAttrVal->fsa_number = HFS_LINK_MAX;
340 }
341 else
342 {
343 psAttrVal->fsa_number = 1;
344 }
345 goto end;
346 }
347
348 if (strcmp(pcAttr, UVFS_FSATTR_PC_NAME_MAX)==0)
349 {
350 *puRetLen = sizeof(uint64_t);
351 if (uLen < *puRetLen)
352 {
353 return E2BIG;
354 }
355 psAttrVal->fsa_number = MAXPATHLEN;
356 goto end;
357 }
358
359 if (strcmp(pcAttr, UVFS_FSATTR_PC_NO_TRUNC)==0)
360 {
361 *puRetLen = sizeof(bool);
362 if (uLen < *puRetLen)
363 {
364 return E2BIG;
365 }
366 psAttrVal->fsa_bool = true;
367 goto end;
368 }
369
370 if (strcmp(pcAttr, UVFS_FSATTR_PC_FILESIZEBITS)==0)
371 {
372 // The number of bits used to represent the size (in bytes) of a file
373 *puRetLen = sizeof(uint64_t);
374 if (uLen < *puRetLen)
375 {
376 return E2BIG;
377 }
378 psAttrVal->fsa_number = 64;
379 goto end;
380 }
381
382 if (strcmp(pcAttr, UVFS_FSATTR_PC_XATTR_SIZE_BITS)==0)
383 {
384 // The number of bits used to represent the size (in bytes) of an extended attribute.
385 *puRetLen = sizeof(uint64_t);
386 if (uLen < *puRetLen)
387 {
388 return E2BIG;
389 }
390 psAttrVal->fsa_number = HFS_XATTR_SIZE_BITS;
391 goto end;
392 }
393
394 if (strcmp(pcAttr, UVFS_FSATTR_BLOCKSIZE)==0)
395 {
396 *puRetLen = sizeof(uint64_t);
397 if (uLen < *puRetLen)
398 {
399 return E2BIG;
400 }
401 psAttrVal->fsa_number = psMount->blockSize;
402 goto end;
403 }
404
405 if (strcmp(pcAttr, UVFS_FSATTR_IOSIZE)==0)
406 {
407 // Size (in bytes) of the optimal transfer block size
408 *puRetLen = sizeof(uint64_t);
409 if (uLen < *puRetLen)
410 {
411 return E2BIG;
412 }
413 psAttrVal->fsa_number = 1024*1024*128;
414 goto end;
415 }
416
417 if (strcmp(pcAttr, UVFS_FSATTR_TOTALBLOCKS)==0)
418 {
419 // Total number of file system blocks
420 *puRetLen = sizeof(uint64_t);
421 if (uLen < *puRetLen)
422 {
423 return E2BIG;
424 }
425 psAttrVal->fsa_number = psMount->totalBlocks;
426 goto end;
427 }
428
429 if (strcmp(pcAttr, UVFS_FSATTR_BLOCKSFREE)==0)
430 {
431 // Total number of free file system blocks
432 *puRetLen = sizeof(uint64_t);
433 if (uLen < *puRetLen)
434 {
435 return E2BIG;
436 }
437 psAttrVal->fsa_number = hfs_freeblks( psMount, 0 );
438 goto end;
439 }
440
441 if (strcmp(pcAttr, UVFS_FSATTR_BLOCKSAVAIL)==0)
442 {
443 // Total number of free file system blocks available for allocation to files (in our case - the same as UVFS_FSATTR_BLOCKSFREE)
444 *puRetLen = sizeof(uint64_t);
445 if (uLen < *puRetLen)
446 {
447 return E2BIG;
448 }
449 psAttrVal->fsa_number = hfs_freeblks( psMount, 1 );
450 goto end;
451 }
452
453 if (strcmp(pcAttr, UVFS_FSATTR_BLOCKSUSED)==0)
454 {
455 // Number of file system blocks currently allocated for some use (TOTAL_BLOCKS - BLOCKSAVAIL)
456 *puRetLen = sizeof(uint64_t);
457 if (uLen < *puRetLen)
458 {
459 return E2BIG;
460 }
461 psAttrVal->fsa_number = psMount->totalBlocks - hfs_freeblks( psMount, 1 );
462 goto end;
463 }
464
465 if (strcmp(pcAttr, UVFS_FSATTR_CNAME)==0)
466 {
467 char* pcName;
468 //The file name
469 if (IS_ROOT(psVnode))
470 pcName = "";
471 else
472 pcName = (char*) psVnode->sFSParams.vnfs_cnp->cn_nameptr;
473
474 if (pcName == NULL)
475 return EINVAL;
476
477 *puRetLen = strlen(pcName) + 1;
478 if (uLen < *puRetLen)
479 {
480 return E2BIG;
481 }
482 strlcpy(psAttrVal->fsa_string, pcName, *puRetLen);
483 return 0;
484 }
485
486 if (strcmp(pcAttr, UVFS_FSATTR_FSTYPENAME)==0)
487 {
488 *puRetLen = 4;
489 if (uLen < *puRetLen)
490 {
491 return E2BIG;
492 }
493 // A string representing the type of file system
494 strcpy(psAttrVal->fsa_string, "HFS");
495 *(psAttrVal->fsa_string+3) = 0; // Must be null terminated
496 goto end;
497 }
498
499 if (strcmp(pcAttr, UVFS_FSATTR_FSSUBTYPE)==0)
500 {
501 #define HFS_PLUS_STR "HFS Plus"
502 #define HFS_PLUS_JOURNALED_STR "HFS Plus (Journaled)"
503 #define HFS_PLUS_CASE_SENS_STR "HFS Plus (Case Sensitive)"
504 #define HFS_PLUS_CASE_SENS_JOURNALED_STR "HFS Plus (Case Sensitive, Journaled)"
505
506 char* pcFSSubType = HFS_PLUS_STR;
507 if ( (psMount->hfs_flags & HFS_CASE_SENSITIVE) && psMount->jnl )
508 {
509 pcFSSubType = HFS_PLUS_CASE_SENS_JOURNALED_STR;
510 }
511 else if ( psMount->hfs_flags & HFS_CASE_SENSITIVE )
512 {
513 pcFSSubType = HFS_PLUS_CASE_SENS_STR;
514 }
515 else if ( psMount->jnl )
516 {
517 pcFSSubType = HFS_PLUS_JOURNALED_STR;
518 }
519
520 *puRetLen = strlen( pcFSSubType ) + 1;
521 if ( uLen < *puRetLen )
522 {
523 return E2BIG;
524 }
525
526 strcpy( psAttrVal->fsa_string, pcFSSubType );
527 goto end;
528 }
529
530 if (strcmp(pcAttr, UVFS_FSATTR_VOLNAME)==0)
531 {
532 *puRetLen = strlen((char *)psMount->vcbVN)+1; // Add 1 for the NULL terminator
533 if (uLen < *puRetLen)
534 {
535 return E2BIG;
536 }
537 strcpy(psAttrVal->fsa_string, (char *)psMount->vcbVN);
538 goto end;
539 }
540
541 if (strcmp(pcAttr, UVFS_FSATTR_VOLUUID)==0)
542 {
543 *puRetLen = sizeof(uuid_t);
544 if (uLen < *puRetLen)
545 {
546 return E2BIG;
547 }
548 hfs_getvoluuid( psMount, psAttrVal->fsa_opaque );
549 goto end;
550 }
551
552 if (strcmp(pcAttr, UVFS_FSATTR_CAPS_FORMAT)==0)
553 {
554 // A bitmask indicating the capabilities of the volume format
555 *puRetLen = sizeof(uint64_t);
556 if (uLen < *puRetLen)
557 {
558 return E2BIG;
559 }
560
561 psAttrVal->fsa_number =
562 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
563 VOL_CAP_FMT_SYMBOLICLINKS |
564 VOL_CAP_FMT_HARDLINKS |
565 VOL_CAP_FMT_JOURNAL |
566 (psMount->jnl ? VOL_CAP_FMT_JOURNAL_ACTIVE : 0) |
567 (psMount->hfs_flags & HFS_CASE_SENSITIVE ? VOL_CAP_FMT_CASE_SENSITIVE : 0) |
568 VOL_CAP_FMT_CASE_PRESERVING |
569 VOL_CAP_FMT_2TB_FILESIZE |
570 VOL_CAP_FMT_HIDDEN_FILES |
571 /* XXX rdar://problem/48128963 VOL_CAP_FMT_PATH_FROM_ID */ 0;
572
573 goto end;
574 }
575
576 if (strcmp(pcAttr, UVFS_FSATTR_CAPS_INTERFACES)==0)
577 {
578 // A bitmask indicating the interface capabilities of the file system
579 *puRetLen = sizeof(uint64_t);
580 if (uLen < *puRetLen)
581 {
582 return E2BIG;
583 }
584
585 psAttrVal->fsa_number =
586 #if LF_HFS_NATIVE_SEARCHFS_SUPPORT
587 VOL_CAP_INT_SEARCHFS |
588 #endif
589 VOL_CAP_INT_EXTENDED_ATTR;
590
591 goto end;
592 }
593
594 if (strcmp(pcAttr, UVFS_FSATTR_LAST_MTIME)==0)
595 {
596 // system lsat mounted time
597 *puRetLen = sizeof(uint64_t);
598 if (uLen < *puRetLen)
599 {
600 return E2BIG;
601 }
602 psAttrVal->fsa_number = psMount->hfs_last_mounted_mtime;
603 goto end;
604 }
605
606 if (strcmp(pcAttr, UVFS_FSATTR_MOUNT_TIME)==0)
607 {
608 // system mount time
609 *puRetLen = sizeof(uint64_t);
610 if (uLen < *puRetLen)
611 {
612 return E2BIG;
613 }
614 psAttrVal->fsa_number = psMount->hfs_mount_time;
615 goto end;
616 }
617
618 iError = ENOTSUP;
619 end:
620 return iError;
621 }
622
623 // kHFSVolumeUnmountedMask: this bit is used to indicate whether the volume is dirty (for which fsck needs to run prior to mount) or clean.
624 // For non-journaled volumes:
625 // - Each operation that causes metadata modification clears this bit.
626 // - A Sync operation that takes place after all 'dirtying' operations are completed sets this bit.
627 // Syncronization between the 'dirtying' operations and the Sync is performed by the hfs_global_lock().
628 // For journaled volumes, the volume is considered clean after a journal has been committed to the media.
629 int LFHFS_Sync(UVFSFileNode psNode) {
630 VERIFY_NODE_IS_VALID(psNode);
631 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_Sync (psNode %p)\n", psNode);
632
633 int iErr = 0;
634 vnode_t psVnode = (vnode_t)psNode;
635 struct hfsmount *psMount = psVnode->sFSParams.vnfs_mp->psHfsmount;
636 bool bNeedUnlock = false;
637
638 lf_lck_mtx_lock(&psMount->sync_mutex);
639 psMount->hfs_syncer_thread = pthread_self();
640
641 if (psMount->jnl) {
642
643 hfs_flush(psMount, HFS_FLUSH_JOURNAL_META);
644
645 } else {
646
647 if (psMount->hfs_global_lockowner != pthread_self()) {
648 hfs_lock_global(psMount, HFS_EXCLUSIVE_LOCK);
649 bNeedUnlock = true;
650 }
651
652 hfs_flushvolumeheader(psMount, HFS_FVH_SKIP_TRANSACTION | HFS_FVH_MARK_UNMOUNT);
653
654 if (bNeedUnlock) {
655 hfs_unlock_global(psMount);
656 }
657 }
658
659 psMount->hfs_syncer_thread = NULL;
660 lf_lck_mtx_unlock(&psMount->sync_mutex);
661
662 return(iErr);
663 }
664
665 int
666 LFHFS_Check( int fdToCheck , __unused UVFSVolumeId volId,
667 __unused UVFSVolumeCredential *volumeCreds, check_flags_t how )
668 {
669 return fsck_hfs(fdToCheck, how);
670 }
671
672 UVFSFSOps HFS_fsOps = {
673 .fsops_version = UVFS_FSOPS_VERSION_CURRENT,
674
675 .fsops_init = LFHFS_Init,
676 .fsops_fini = LFHFS_Fini,
677
678 .fsops_taste = LFHFS_Taste,
679 .fsops_scanvols = LFHFS_ScanVols,
680 .fsops_mount = LFHFS_Mount,
681 .fsops_sync = LFHFS_Sync,
682 .fsops_unmount = LFHFS_Unmount,
683
684 .fsops_getfsattr = LFHFS_GetFSAttr,
685 .fsops_setfsattr = LFHFS_SetFSAttr,
686
687 .fsops_getattr = LFHFS_GetAttr,
688 .fsops_setattr = LFHFS_SetAttr,
689 .fsops_lookup = LFHFS_Lookup,
690 .fsops_reclaim = LFHFS_Reclaim,
691 .fsops_readlink = LFHFS_ReadLink,
692 .fsops_read = LFHFS_Read,
693 .fsops_write = LFHFS_Write,
694 .fsops_create = LFHFS_Create,
695 .fsops_mkdir = LFHFS_MkDir,
696 .fsops_symlink = LFHFS_SymLink,
697 .fsops_remove = LFHFS_Remove,
698 .fsops_rmdir = LFHFS_RmDir,
699 .fsops_rename = LFHFS_Rename,
700 .fsops_readdir = LFHFS_ReadDir,
701 .fsops_readdirattr = LFHFS_ReadDirAttr,
702 .fsops_link = LFHFS_Link,
703 .fsops_check = LFHFS_Check,
704
705 .fsops_getxattr = LFHFS_GetXAttr,
706 .fsops_setxattr = LFHFS_SetXAttr,
707 .fsops_listxattr = LFHFS_ListXAttr,
708
709 .fsops_scandir = LFHFS_ScanDir,
710 .fsops_scanids = LFHFS_ScanIDs,
711
712 .fsops_stream_lookup = LFHFS_StreamLookup,
713 .fsops_stream_reclaim = LFHFS_StreamReclaim,
714 .fsops_stream_read = LFHFS_StreamRead,
715 };
716
717 #if HFS_CRASH_TEST
718 CrashAbortFunction_FP gpsCrashAbortFunctionArray[CRASH_ABORT_LAST] = {0};
719 #endif
720
721 __attribute__((visibility("default")))
722 void
723 livefiles_plugin_init(UVFSFSOps **ops)
724 {
725 if (ops) {
726 *ops = &HFS_fsOps;
727 }
728
729 return;
730 }