1 /* Copyright © 2017-2018 Apple Inc. All rights reserved.
3 * lf_hfs_fileops_handler.c
6 * Created by Yakov Ben Zaken on 31/12/2017.
9 #include "lf_hfs_dirops_handler.h"
10 #include "lf_hfs_fileops_handler.h"
11 #include "lf_hfs_vnode.h"
12 #include "lf_hfs_lookup.h"
13 #include "lf_hfs_logger.h"
14 #include "lf_hfs_vnops.h"
15 #include "lf_hfs_vfsutils.h"
16 #include "lf_hfs_attrlist.h"
17 #include "lf_hfs_vfsops.h"
19 //---------------------------------- Functions Decleration ---------------------------------------
20 static int DIROPS_VerifyCookieAndVerifier(uint64_t uCookie
, vnode_t psParentVnode
, uint64_t uVerifier
);
21 //---------------------------------- Functions Implementation ------------------------------------
24 DIROPS_VerifyCookieAndVerifier(uint64_t uCookie
, vnode_t psParentVnode
, uint64_t uVerifier
)
27 struct cnode
* dcp
= VTOC(psParentVnode
);
31 if ( uVerifier
!= UVFS_DIRCOOKIE_VERIFIER_INITIAL
)
33 iError
= UVFS_READDIR_VERIFIER_MISMATCHED
;
37 else if (uCookie
== UVFS_DIRCOOKIE_EOF
)
39 iError
= UVFS_READDIR_EOF_REACHED
;
42 else if ( uVerifier
!= psParentVnode
->sExtraData
.sDirData
.uDirVersion
)
44 iError
= UVFS_READDIR_VERIFIER_MISMATCHED
;
48 cnid_t uChildIndex
= (cnid_t
)(uCookie
& HFS_INDEX_MASK
);
49 if (uChildIndex
> (dcp
->c_entries
+ 2))
50 { /* searching pass the last item */
51 iError
= UVFS_READDIR_BAD_COOKIE
;
58 int DIROPS_RemoveInternal( UVFSFileNode psDirNode
, const char *pcUTF8Name
)
61 vnode_t psParentVnode
= (vnode_t
)psDirNode
;
62 UVFSFileNode psFileNode
= {0};
64 if (!vnode_isdir(psParentVnode
))
69 iErr
= DIROPS_LookupInternal( psDirNode
, pcUTF8Name
, &psFileNode
);
74 vnode_t psVnode
= (vnode_t
)psFileNode
;
76 if (vnode_isdir(psVnode
))
81 struct componentname sCompName
= {0};
82 sCompName
.cn_nameiop
= DELETE
;
83 sCompName
.cn_flags
= ISLASTCN
;
84 sCompName
.cn_pnbuf
= (char *)pcUTF8Name
;
85 sCompName
.cn_pnlen
= (int)strlen(pcUTF8Name
);
86 sCompName
.cn_nameptr
= (char *)pcUTF8Name
;
87 sCompName
.cn_namelen
= (int)strlen(pcUTF8Name
);
88 sCompName
.cn_hash
= 0;
89 sCompName
.cn_consume
= (int)strlen(pcUTF8Name
);
91 iErr
= hfs_vnop_remove(psParentVnode
,psVnode
, &sCompName
, VNODE_REMOVE_NODELETEBUSY
| VNODE_REMOVE_SKIP_NAMESPACE_EVENT
);
93 LFHFS_Reclaim(psFileNode
);
99 int DIROPS_LookupInternal( UVFSFileNode psDirNode
, const char *pcUTF8Name
, UVFSFileNode
*ppsOutNode
)
102 // We are not supporting "." and ".." lookup.
103 if ( (strcmp( (char*)pcUTF8Name
, "." ) == 0) || (strcmp( (char*)pcUTF8Name
, ".." ) == 0) )
110 vnode_t psVnode
= (vnode_t
)psDirNode
;
112 if (!vnode_isdir(psVnode
))
118 struct componentname sCompName
= {0};
119 sCompName
.cn_nameiop
= LOOKUP
;
120 sCompName
.cn_flags
= ISLASTCN
;
121 sCompName
.cn_pnbuf
= (char *)pcUTF8Name
;
122 sCompName
.cn_pnlen
= (int)strlen(pcUTF8Name
);
123 sCompName
.cn_nameptr
= (char *)pcUTF8Name
;
124 sCompName
.cn_namelen
= (int)strlen(pcUTF8Name
);
125 sCompName
.cn_hash
= 0;
126 sCompName
.cn_consume
= (int)strlen(pcUTF8Name
);
128 iErr
= hfs_vnop_lookup( psVnode
, (vnode_t
*)ppsOutNode
, &sCompName
);
135 LFHFS_MkDir ( UVFSFileNode psDirNode
, const char *pcName
, const UVFSFileAttributes
*psFileAttr
, UVFSFileNode
*ppsOutNode
)
137 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_MkDir\n");
138 VERIFY_NODE_IS_VALID(psDirNode
);
141 vnode_t psParentVnode
= (vnode_t
)psDirNode
;
143 if (!vnode_isdir(psParentVnode
))
149 //@param cnp Name information for new directory.
150 struct componentname sNewDirComponentName
= {0};
151 sNewDirComponentName
.cn_nameptr
= (char*) pcName
;
152 sNewDirComponentName
.cn_namelen
= (int) strlen(pcName
);
154 iError
= hfs_vnop_mkdir(psParentVnode
,(vnode_t
*)ppsOutNode
, &sNewDirComponentName
, (UVFSFileAttributes
*) psFileAttr
);
161 LFHFS_RmDir ( UVFSFileNode psDirNode
, const char *pcUTF8Name
)
163 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_RmDir\n");
164 VERIFY_NODE_IS_VALID(psDirNode
);
167 vnode_t psParentVnode
= (vnode_t
)psDirNode
;
169 if (!vnode_isdir(psParentVnode
))
175 UVFSFileNode psFileNode
= {0};
176 struct componentname sCompName
= {0};
178 iErr
= DIROPS_LookupInternal( psDirNode
, pcUTF8Name
, &psFileNode
);
184 vnode_t psVnode
= (vnode_t
)psFileNode
;
186 sCompName
.cn_nameiop
= DELETE
;
187 sCompName
.cn_flags
= ISLASTCN
;
188 sCompName
.cn_pnbuf
= (char *)pcUTF8Name
;
189 sCompName
.cn_pnlen
= (int)strlen(pcUTF8Name
);
190 sCompName
.cn_nameptr
= (char *)pcUTF8Name
;
191 sCompName
.cn_namelen
= (int)strlen(pcUTF8Name
);
192 sCompName
.cn_hash
= 0;
193 sCompName
.cn_consume
= (int)strlen(pcUTF8Name
);
195 iErr
= hfs_vnop_rmdir(psParentVnode
, psVnode
, &sCompName
);
197 hfs_vnop_reclaim(psVnode
);
204 LFHFS_Remove ( UVFSFileNode psDirNode
, const char *pcUTF8Name
, __unused UVFSFileNode victimNode
)
206 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_Remove\n");
207 VERIFY_NODE_IS_VALID(psDirNode
);
209 int iErr
= DIROPS_RemoveInternal( psDirNode
, pcUTF8Name
);
214 LFHFS_Lookup ( UVFSFileNode psDirNode
, const char *pcUTF8Name
, UVFSFileNode
*ppsOutNode
)
216 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_Lookup\n");
217 VERIFY_NODE_IS_VALID(psDirNode
);
219 return DIROPS_LookupInternal( psDirNode
, pcUTF8Name
, ppsOutNode
);
223 LFHFS_ReadDir ( UVFSFileNode psDirNode
, void* pvBuf
, size_t iBufLen
, uint64_t uCookie
, size_t *iReadBytes
, uint64_t *puVerifier
)
225 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_ReadDir\n");
226 VERIFY_NODE_IS_VALID(psDirNode
);
230 struct vnode
* psParentVnode
= (struct vnode
*) psDirNode
;
232 if (iReadBytes
== NULL
|| puVerifier
== NULL
)
238 // Make sure the UVFSFileNode is a directory.
239 if ( !IS_DIR(psParentVnode
) )
241 LFHFS_LOG(LEVEL_ERROR
, "HFS_ReadDir node is not a directory.\n", ENOTDIR
);
245 // Make sure there is a place for at least one entry with maximal allowed name
246 uint64_t uMaxRecLen
= UVFS_DIRENTRY_RECLEN(MAX_UTF8_NAME_LENGTH
);
247 if ( iBufLen
< uMaxRecLen
)
252 iError
= DIROPS_VerifyCookieAndVerifier(uCookie
,psParentVnode
, *puVerifier
);
259 *puVerifier
= psParentVnode
->sExtraData
.sDirData
.uDirVersion
;
261 //Setting readDir Args
264 int flags
= VNODE_READDIR_EXTENDED
|VNODE_READDIR_REQSEEKOFF
;
265 ReadDirBuff_s sReadDirBuffer
= {0};
266 sReadDirBuffer
.pvBuffer
= pvBuf
;
267 sReadDirBuffer
.uBufferResid
= sReadDirBuffer
.uBufferSize
= iBufLen
;
269 iError
= hfs_vnop_readdir( psParentVnode
, &iEofflag
, &iNumdirent
, &sReadDirBuffer
, uCookie
, flags
);
278 iError
= UVFS_READDIR_EOF_REACHED
;
286 *iReadBytes
= sReadDirBuffer
.uBufferSize
- sReadDirBuffer
.uBufferResid
;
292 LFHFS_ReadDirAttr( UVFSFileNode psDirNode
, void *pvBuf
, size_t iBufLen
, uint64_t uCookie
, size_t *iReadBytes
, uint64_t *puVerifier
)
294 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_ReadDirAttr\n");
295 VERIFY_NODE_IS_VALID(psDirNode
);
299 struct vnode
* psParentVnode
= (struct vnode
*) psDirNode
;
301 if (iReadBytes
== NULL
|| puVerifier
== NULL
)
307 // Make sure the UVFSFileNode is a directory.
308 if ( !IS_DIR(psParentVnode
) )
310 LFHFS_LOG(LEVEL_ERROR
, "HFS_ReadDir node is not a directory.\n", ENOTDIR
);
314 // Make sure there is a place for at least one entry with maximal allowed name
315 uint64_t uMaxRecLen
= UVFS_DIRENTRY_RECLEN(MAX_UTF8_NAME_LENGTH
);
316 if ( iBufLen
< uMaxRecLen
)
321 iError
= DIROPS_VerifyCookieAndVerifier(uCookie
, psParentVnode
, *puVerifier
);
327 *puVerifier
= psParentVnode
->sExtraData
.sDirData
.uDirVersion
;
330 //Setting readDirAttr Args
333 ReadDirBuff_s sReadDirBuffer
= {0};
334 sReadDirBuffer
.pvBuffer
= pvBuf
;
335 sReadDirBuffer
.uBufferResid
= sReadDirBuffer
.uBufferSize
= iBufLen
;
337 iError
= hfs_vnop_readdirattr( psParentVnode
, &iEofflag
, &iNumdirent
, &sReadDirBuffer
, uCookie
);
346 iError
= UVFS_READDIR_EOF_REACHED
;
354 *iReadBytes
= sReadDirBuffer
.uBufferSize
- sReadDirBuffer
.uBufferResid
;
361 LFHFS_ScanDir(UVFSFileNode psDirNode
, scandir_matching_request_t
* psMatchingCriteria
, scandir_matching_reply_t
* psMatchingResult
)
363 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_ScanDir\n");
364 VERIFY_NODE_IS_VALID(psDirNode
);
367 struct vnode
* psParentVnode
= (struct vnode
*) psDirNode
;
368 // Make sure the UVFSFileNode is a directory.
369 if ( !IS_DIR(psParentVnode
) )
371 LFHFS_LOG(LEVEL_ERROR
, "LFHFS_ScanDir node is not a directory.\n", ENOTDIR
);
375 iErr
= DIROPS_VerifyCookieAndVerifier(psMatchingCriteria
->smr_start_cookie
, psParentVnode
, psMatchingCriteria
->smr_verifier
);
381 psMatchingResult
->smr_result_type
= 0;
382 psMatchingResult
->smr_verifier
= psParentVnode
->sExtraData
.sDirData
.uDirVersion
;
383 ScanDirRequest_s psScanDirRequest
= {.psMatchingCriteria
= psMatchingCriteria
, .psMatchingResult
= psMatchingResult
};
385 iErr
= hfs_scandir( psParentVnode
, &psScanDirRequest
);
391 int LFHFS_ScanIDs(UVFSFileNode psNode
,
392 __unused
uint64_t uRequestedAttributes
,
393 const uint64_t* puFileIDArray
,
394 unsigned int iFileIDCount
,
395 scanids_match_block_t fMatchCallback
)
398 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_ScanIDs\n");
399 VERIFY_NODE_IS_VALID(psNode
);
400 struct vnode
* psVnode
= (struct vnode
*) psNode
;
402 char* pcName
= malloc(sizeof(char)*MAX_UTF8_NAME_LENGTH
);
406 for (uint32_t uIDCounter
= 0; uIDCounter
< iFileIDCount
; uIDCounter
++)
408 memset(pcName
,0,sizeof(char)*MAX_UTF8_NAME_LENGTH
);
409 //if we got to the rootParentID just continue
410 if ((cnid_t
)puFileIDArray
[uIDCounter
] == kHFSRootParentID
)
413 UVFSFileAttributes sFileAttrs
;
414 error
= hfs_GetInfoByID(VTOHFS(psVnode
), (cnid_t
)puFileIDArray
[uIDCounter
], &sFileAttrs
, pcName
);
415 if (error
== ENOENT
) {
421 if ((cnid_t
)puFileIDArray
[uIDCounter
] == kHFSRootFolderID
) {
422 sFileAttrs
.fa_parentid
= sFileAttrs
.fa_fileid
;
424 LFHFS_LOG(LEVEL_DEBUG
, "scan found item %llu parent %llu",
425 sFileAttrs
.fa_parentid
, sFileAttrs
.fa_fileid
);
426 fMatchCallback((int) uIDCounter
, &sFileAttrs
, pcName
);
428 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_ScanIDs: hfs_GetInfoByID failed with error %u\n",error
);