]> git.saurik.com Git - apple/hfs.git/blob - livefiles_hfs_plugin/lf_hfs_dirops_handler.c
hfs-522.0.9.tar.gz
[apple/hfs.git] / livefiles_hfs_plugin / lf_hfs_dirops_handler.c
1 /* Copyright © 2017-2018 Apple Inc. All rights reserved.
2 *
3 * lf_hfs_fileops_handler.c
4 * livefiles_hfs
5 *
6 * Created by Yakov Ben Zaken on 31/12/2017.
7 */
8
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"
18
19 //---------------------------------- Functions Decleration ---------------------------------------
20 static int DIROPS_VerifyCookieAndVerifier(uint64_t uCookie, vnode_t psParentVnode, uint64_t uVerifier);
21 //---------------------------------- Functions Implementation ------------------------------------
22
23 static int
24 DIROPS_VerifyCookieAndVerifier(uint64_t uCookie, vnode_t psParentVnode, uint64_t uVerifier)
25 {
26 int iError = 0;
27 struct cnode* dcp = VTOC(psParentVnode);
28
29 if ( uCookie == 0 )
30 {
31 if ( uVerifier != UVFS_DIRCOOKIE_VERIFIER_INITIAL )
32 {
33 iError = UVFS_READDIR_VERIFIER_MISMATCHED;
34 goto exit;
35 }
36 }
37 else if (uCookie == UVFS_DIRCOOKIE_EOF)
38 {
39 iError = UVFS_READDIR_EOF_REACHED;
40 goto exit;
41 }
42 else if ( uVerifier != psParentVnode->sExtraData.sDirData.uDirVersion )
43 {
44 iError = UVFS_READDIR_VERIFIER_MISMATCHED;
45 goto exit;
46 }
47
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;
52 }
53
54 exit:
55 return iError;
56 }
57
58 int DIROPS_RemoveInternal( UVFSFileNode psDirNode, const char *pcUTF8Name )
59 {
60 int iErr = 0;
61 vnode_t psParentVnode = (vnode_t)psDirNode;
62 UVFSFileNode psFileNode = {0};
63
64 if (!vnode_isdir(psParentVnode))
65 {
66 return ENOTDIR;
67 }
68
69 iErr = DIROPS_LookupInternal( psDirNode, pcUTF8Name, &psFileNode );
70 if ( iErr != 0 )
71 {
72 goto exit;
73 }
74 vnode_t psVnode = (vnode_t)psFileNode;
75
76 if (vnode_isdir(psVnode))
77 {
78 return EISDIR;
79 }
80
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);
90
91 iErr = hfs_vnop_remove(psParentVnode,psVnode, &sCompName, VNODE_REMOVE_NODELETEBUSY | VNODE_REMOVE_SKIP_NAMESPACE_EVENT );
92
93 LFHFS_Reclaim(psFileNode);
94
95 exit:
96 return iErr;
97 }
98
99 int DIROPS_LookupInternal( UVFSFileNode psDirNode, const char *pcUTF8Name, UVFSFileNode *ppsOutNode )
100 {
101 int iErr = 0;
102 // We are not supporting "." and ".." lookup.
103 if ( (strcmp( (char*)pcUTF8Name, "." ) == 0) || (strcmp( (char*)pcUTF8Name, ".." ) == 0) )
104 {
105 *ppsOutNode = NULL;
106 iErr = EPERM;
107 goto exit;
108 }
109
110 vnode_t psVnode = (vnode_t)psDirNode;
111
112 if (!vnode_isdir(psVnode))
113 {
114 iErr = ENOTDIR;
115 goto exit;
116 }
117
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);
127
128 iErr = hfs_vnop_lookup( psVnode, (vnode_t*)ppsOutNode, &sCompName );
129
130 exit:
131 return iErr;
132 }
133
134 int
135 LFHFS_MkDir ( UVFSFileNode psDirNode, const char *pcName, const UVFSFileAttributes *psFileAttr, UVFSFileNode *ppsOutNode )
136 {
137 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_MkDir\n");
138 VERIFY_NODE_IS_VALID(psDirNode);
139
140 int iError = 0;
141 vnode_t psParentVnode = (vnode_t)psDirNode;
142
143 if (!vnode_isdir(psParentVnode))
144 {
145 iError = ENOTDIR;
146 goto exit;
147 }
148
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);
153
154 iError = hfs_vnop_mkdir(psParentVnode,(vnode_t*)ppsOutNode, &sNewDirComponentName, (UVFSFileAttributes *) psFileAttr);
155
156 exit:
157 return iError;
158 }
159
160 int
161 LFHFS_RmDir ( UVFSFileNode psDirNode, const char *pcUTF8Name )
162 {
163 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_RmDir\n");
164 VERIFY_NODE_IS_VALID(psDirNode);
165
166 int iErr = 0;
167 vnode_t psParentVnode = (vnode_t)psDirNode;
168
169 if (!vnode_isdir(psParentVnode))
170 {
171 iErr = ENOTDIR;
172 goto exit;
173 }
174
175 UVFSFileNode psFileNode = {0};
176 struct componentname sCompName = {0};
177
178 iErr = DIROPS_LookupInternal( psDirNode, pcUTF8Name, &psFileNode );
179 if ( iErr != 0 )
180 {
181 goto exit;
182 }
183
184 vnode_t psVnode = (vnode_t)psFileNode;
185
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);
194
195 iErr = hfs_vnop_rmdir(psParentVnode, psVnode, &sCompName);
196
197 hfs_vnop_reclaim(psVnode);
198
199 exit:
200 return iErr;
201 }
202
203 int
204 LFHFS_Remove ( UVFSFileNode psDirNode, const char *pcUTF8Name, __unused UVFSFileNode victimNode)
205 {
206 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_Remove\n");
207 VERIFY_NODE_IS_VALID(psDirNode);
208
209 int iErr = DIROPS_RemoveInternal( psDirNode, pcUTF8Name );
210 return iErr;
211 }
212
213 int
214 LFHFS_Lookup ( UVFSFileNode psDirNode, const char *pcUTF8Name, UVFSFileNode *ppsOutNode )
215 {
216 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_Lookup\n");
217 VERIFY_NODE_IS_VALID(psDirNode);
218
219 return DIROPS_LookupInternal( psDirNode, pcUTF8Name, ppsOutNode );
220 }
221
222 int
223 LFHFS_ReadDir ( UVFSFileNode psDirNode, void* pvBuf, size_t iBufLen, uint64_t uCookie, size_t *iReadBytes, uint64_t *puVerifier )
224 {
225 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_ReadDir\n");
226 VERIFY_NODE_IS_VALID(psDirNode);
227
228 int iError = 0;
229 *iReadBytes = 0;
230 struct vnode* psParentVnode = (struct vnode*) psDirNode;
231
232 if (iReadBytes == NULL || puVerifier == NULL)
233 {
234 return EINVAL;
235 }
236 *iReadBytes = 0;
237
238 // Make sure the UVFSFileNode is a directory.
239 if ( !IS_DIR(psParentVnode) )
240 {
241 LFHFS_LOG(LEVEL_ERROR, "HFS_ReadDir node is not a directory.\n", ENOTDIR);
242 return ENOTDIR;
243 }
244
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 )
248 {
249 return EINVAL;
250 }
251
252 iError = DIROPS_VerifyCookieAndVerifier(uCookie,psParentVnode, *puVerifier);
253 if ( iError != 0 )
254 {
255 goto exit;
256 }
257
258
259 *puVerifier = psParentVnode->sExtraData.sDirData.uDirVersion;
260
261 //Setting readDir Args
262 int iEofflag;
263 int iNumdirent;
264 int flags = VNODE_READDIR_EXTENDED|VNODE_READDIR_REQSEEKOFF;
265 ReadDirBuff_s sReadDirBuffer = {0};
266 sReadDirBuffer.pvBuffer = pvBuf;
267 sReadDirBuffer.uBufferResid = sReadDirBuffer.uBufferSize = iBufLen;
268
269 iError = hfs_vnop_readdir( psParentVnode, &iEofflag, &iNumdirent, &sReadDirBuffer, uCookie, flags);
270
271 if (iError)
272 goto exit;
273
274 if (iNumdirent == 0)
275 {
276 if (iEofflag)
277 {
278 iError = UVFS_READDIR_EOF_REACHED;
279 }
280 else
281 {
282 iError = EINVAL;
283 }
284 }
285
286 *iReadBytes = sReadDirBuffer.uBufferSize - sReadDirBuffer.uBufferResid;
287 exit:
288 return iError;
289 }
290
291 int
292 LFHFS_ReadDirAttr( UVFSFileNode psDirNode, void *pvBuf, size_t iBufLen, uint64_t uCookie, size_t *iReadBytes, uint64_t *puVerifier )
293 {
294 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_ReadDirAttr\n");
295 VERIFY_NODE_IS_VALID(psDirNode);
296
297 int iError = 0;
298 *iReadBytes = 0;
299 struct vnode* psParentVnode = (struct vnode*) psDirNode;
300
301 if (iReadBytes == NULL || puVerifier == NULL)
302 {
303 return EINVAL;
304 }
305 *iReadBytes = 0;
306
307 // Make sure the UVFSFileNode is a directory.
308 if ( !IS_DIR(psParentVnode) )
309 {
310 LFHFS_LOG(LEVEL_ERROR, "HFS_ReadDir node is not a directory.\n", ENOTDIR);
311 return ENOTDIR;
312 }
313
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 )
317 {
318 return EINVAL;
319 }
320
321 iError = DIROPS_VerifyCookieAndVerifier(uCookie, psParentVnode, *puVerifier);
322 if ( iError != 0 )
323 {
324 goto exit;
325 }
326
327 *puVerifier = psParentVnode->sExtraData.sDirData.uDirVersion;
328
329
330 //Setting readDirAttr Args
331 int iEofflag;
332 int iNumdirent;
333 ReadDirBuff_s sReadDirBuffer = {0};
334 sReadDirBuffer.pvBuffer = pvBuf;
335 sReadDirBuffer.uBufferResid = sReadDirBuffer.uBufferSize = iBufLen;
336
337 iError = hfs_vnop_readdirattr( psParentVnode, &iEofflag, &iNumdirent, &sReadDirBuffer, uCookie);
338
339 if (iError)
340 goto exit;
341
342 if (iNumdirent == 0)
343 {
344 if (iEofflag)
345 {
346 iError = UVFS_READDIR_EOF_REACHED;
347 }
348 else
349 {
350 iError = EINVAL;
351 }
352 }
353
354 *iReadBytes = sReadDirBuffer.uBufferSize - sReadDirBuffer.uBufferResid;
355
356 exit:
357 return iError;
358 }
359
360 int
361 LFHFS_ScanDir(UVFSFileNode psDirNode, scandir_matching_request_t* psMatchingCriteria, scandir_matching_reply_t* psMatchingResult)
362 {
363 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_ScanDir\n");
364 VERIFY_NODE_IS_VALID(psDirNode);
365
366 int iErr = 0;
367 struct vnode* psParentVnode = (struct vnode*) psDirNode;
368 // Make sure the UVFSFileNode is a directory.
369 if ( !IS_DIR(psParentVnode) )
370 {
371 LFHFS_LOG(LEVEL_ERROR, "LFHFS_ScanDir node is not a directory.\n", ENOTDIR);
372 return ENOTDIR;
373 }
374
375 iErr = DIROPS_VerifyCookieAndVerifier(psMatchingCriteria->smr_start_cookie, psParentVnode, psMatchingCriteria->smr_verifier);
376 if ( iErr != 0 )
377 {
378 goto exit;
379 }
380
381 psMatchingResult->smr_result_type = 0;
382 psMatchingResult->smr_verifier = psParentVnode->sExtraData.sDirData.uDirVersion;
383 ScanDirRequest_s psScanDirRequest = {.psMatchingCriteria = psMatchingCriteria, .psMatchingResult = psMatchingResult};
384
385 iErr = hfs_scandir( psParentVnode, &psScanDirRequest);
386
387 exit:
388 return iErr;
389 }
390
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)
396 {
397 int error = 0;
398 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_ScanIDs\n");
399 VERIFY_NODE_IS_VALID(psNode);
400 struct vnode* psVnode = (struct vnode*) psNode;
401
402 char* pcName = malloc(sizeof(char)*MAX_UTF8_NAME_LENGTH);
403 if (pcName == NULL)
404 return ENOMEM;
405
406 for (uint32_t uIDCounter = 0; uIDCounter < iFileIDCount; uIDCounter++)
407 {
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)
411 continue;
412
413 UVFSFileAttributes sFileAttrs;
414 error = hfs_GetInfoByID(VTOHFS(psVnode), (cnid_t)puFileIDArray[uIDCounter], &sFileAttrs, pcName);
415 if (error == ENOENT) {
416 error = 0;
417 continue;
418 }
419
420 if (!error) {
421 if ((cnid_t)puFileIDArray[uIDCounter] == kHFSRootFolderID) {
422 sFileAttrs.fa_parentid = sFileAttrs.fa_fileid;
423 }
424 LFHFS_LOG(LEVEL_DEBUG, "scan found item %llu parent %llu",
425 sFileAttrs.fa_parentid, sFileAttrs.fa_fileid);
426 fMatchCallback((int) uIDCounter, &sFileAttrs, pcName);
427 } else {
428 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_ScanIDs: hfs_GetInfoByID failed with error %u\n",error);
429 break;
430 }
431 }
432
433 free(pcName);
434 return error;
435 }