]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
9bccf70c | 2 | * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* @(#)hfs_vfsutils.c 4.0 | |
23 | * | |
9bccf70c | 24 | * (c) 1997-2002 Apple Computer, Inc. All Rights Reserved |
1c79356b A |
25 | * |
26 | * hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS. | |
27 | * | |
1c79356b A |
28 | */ |
29 | #include <sys/param.h> | |
30 | #include <sys/systm.h> | |
31 | #include <sys/kernel.h> | |
32 | #include <sys/malloc.h> | |
33 | #include <sys/stat.h> | |
1c79356b | 34 | #include <sys/mount.h> |
9bccf70c | 35 | #include <sys/namei.h> |
1c79356b A |
36 | #include <sys/lock.h> |
37 | #include <sys/buf.h> | |
38 | #include <sys/ubc.h> | |
39 | #include <sys/unistd.h> | |
40 | ||
41 | #include "hfs.h" | |
9bccf70c | 42 | #include "hfs_catalog.h" |
1c79356b A |
43 | #include "hfs_dbg.h" |
44 | #include "hfs_mount.h" | |
45 | #include "hfs_endian.h" | |
9bccf70c | 46 | #include "hfs_cnode.h" |
1c79356b A |
47 | |
48 | #include "hfscommon/headers/FileMgrInternal.h" | |
49 | #include "hfscommon/headers/BTreesInternal.h" | |
50 | #include "hfscommon/headers/HFSUnicodeWrappers.h" | |
51 | ||
1c79356b | 52 | |
1c79356b A |
53 | extern int count_lock_queue __P((void)); |
54 | extern uid_t console_user; | |
55 | ||
1c79356b A |
56 | |
57 | static void ReleaseMetaFileVNode(struct vnode *vp); | |
58 | ||
1c79356b A |
59 | u_int32_t GetLogicalBlockSize(struct vnode *vp); |
60 | ||
61 | /* BTree accessor routines */ | |
62 | extern OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block); | |
63 | extern OSStatus SetBTreeBlockSize(FileReference vp, ByteCount blockSize, ItemCount minBlockCount); | |
64 | extern OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF); | |
65 | extern OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options); | |
66 | ||
67 | //******************************************************************************* | |
68 | // Note: Finder information in the HFS/HFS+ metadata are considered opaque and | |
69 | // hence are not in the right byte order on little endian machines. It is | |
70 | // the responsibility of the finder and other clients to swap the data. | |
71 | //******************************************************************************* | |
72 | ||
73 | //******************************************************************************* | |
74 | // Routine: hfs_MountHFSVolume | |
75 | // | |
76 | // | |
77 | //******************************************************************************* | |
9bccf70c A |
78 | char hfs_catname[] = "Catalog B-tree"; |
79 | char hfs_extname[] = "Extents B-tree"; | |
80 | char hfs_vbmname[] = "Volume Bitmap"; | |
81 | ||
82 | char hfs_privdirname[] = | |
83 | "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data"; | |
1c79356b A |
84 | |
85 | OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb, | |
d52fe63f | 86 | struct proc *p) |
1c79356b | 87 | { |
9bccf70c A |
88 | ExtendedVCB *vcb = HFSTOVCB(hfsmp); |
89 | int error; | |
1c79356b | 90 | ByteCount utf8chars; |
9bccf70c A |
91 | struct cat_desc cndesc; |
92 | struct cat_attr cnattr; | |
93 | struct cat_fork fork; | |
1c79356b | 94 | |
9bccf70c A |
95 | /* Block size must be a multiple of 512 */ |
96 | if (SWAP_BE32(mdb->drAlBlkSiz) == 0 || | |
97 | (SWAP_BE32(mdb->drAlBlkSiz) & 0x01FF) != 0) | |
1c79356b A |
98 | return (EINVAL); |
99 | ||
1c79356b | 100 | /* don't mount a writeable volume if its dirty, it must be cleaned by fsck_hfs */ |
9bccf70c | 101 | if ((hfsmp->hfs_fs_ronly == 0) && ((SWAP_BE16(mdb->drAtrb) & kHFSVolumeUnmountedMask) == 0)) |
1c79356b A |
102 | return (EINVAL); |
103 | ||
104 | /* | |
105 | * The MDB seems OK: transfer info from it into VCB | |
106 | * Note - the VCB starts out clear (all zeros) | |
107 | * | |
108 | */ | |
9bccf70c A |
109 | vcb->vcbSigWord = SWAP_BE16 (mdb->drSigWord); |
110 | vcb->vcbCrDate = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drCrDate))); | |
0b4e3aa0 | 111 | vcb->localCreateDate = SWAP_BE32 (mdb->drCrDate); |
9bccf70c A |
112 | vcb->vcbLsMod = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drLsMod))); |
113 | vcb->vcbAtrb = SWAP_BE16 (mdb->drAtrb); | |
114 | vcb->vcbNmFls = SWAP_BE16 (mdb->drNmFls); | |
115 | vcb->vcbVBMSt = SWAP_BE16 (mdb->drVBMSt); | |
116 | vcb->nextAllocation = SWAP_BE16 (mdb->drAllocPtr); | |
117 | vcb->totalBlocks = SWAP_BE16 (mdb->drNmAlBlks); | |
118 | vcb->blockSize = SWAP_BE32 (mdb->drAlBlkSiz); | |
119 | vcb->vcbClpSiz = SWAP_BE32 (mdb->drClpSiz); | |
120 | vcb->vcbAlBlSt = SWAP_BE16 (mdb->drAlBlSt); | |
121 | vcb->vcbNxtCNID = SWAP_BE32 (mdb->drNxtCNID); | |
122 | vcb->freeBlocks = SWAP_BE16 (mdb->drFreeBks); | |
123 | vcb->vcbVolBkUp = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drVolBkUp))); | |
124 | vcb->vcbWrCnt = SWAP_BE32 (mdb->drWrCnt); | |
125 | vcb->vcbNmRtDirs = SWAP_BE16 (mdb->drNmRtDirs); | |
126 | vcb->vcbFilCnt = SWAP_BE32 (mdb->drFilCnt); | |
127 | vcb->vcbDirCnt = SWAP_BE32 (mdb->drDirCnt); | |
1c79356b | 128 | bcopy(mdb->drFndrInfo, vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo)); |
9bccf70c A |
129 | if (!hfsmp->hfs_fs_ronly) |
130 | vcb->vcbWrCnt++; /* Compensate for write of MDB on last flush */ | |
1c79356b A |
131 | |
132 | /* convert hfs encoded name into UTF-8 string */ | |
9bccf70c | 133 | error = hfs_to_utf8(vcb, mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN); |
1c79356b A |
134 | /* |
135 | * When an HFS name cannot be encoded with the current | |
136 | * volume encoding we use MacRoman as a fallback. | |
137 | */ | |
9bccf70c | 138 | if (error || (utf8chars == 0)) |
1c79356b A |
139 | (void) mac_roman_to_utf8(mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN); |
140 | ||
9bccf70c | 141 | hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size); |
0b4e3aa0 | 142 | vcb->vcbVBMIOSize = kHFSBlockSize; |
1c79356b | 143 | |
1c79356b A |
144 | VCB_LOCK_INIT(vcb); |
145 | ||
9bccf70c A |
146 | bzero(&cndesc, sizeof(cndesc)); |
147 | cndesc.cd_parentcnid = kRootParID; | |
148 | bzero(&cnattr, sizeof(cnattr)); | |
149 | cnattr.ca_nlink = 1; | |
150 | cnattr.ca_mode = S_IFREG; | |
151 | bzero(&fork, sizeof(fork)); | |
152 | ||
1c79356b | 153 | /* |
9bccf70c A |
154 | * Set up Extents B-tree vnode |
155 | */ | |
156 | cndesc.cd_nameptr = hfs_extname; | |
157 | cndesc.cd_namelen = strlen(hfs_extname); | |
158 | cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID; | |
159 | fork.cf_size = SWAP_BE32(mdb->drXTFlSize); | |
160 | fork.cf_blocks = fork.cf_size / vcb->blockSize; | |
161 | fork.cf_clump = SWAP_BE32(mdb->drXTClpSiz); | |
162 | fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drXTExtRec[0].startBlock); | |
163 | fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drXTExtRec[0].blockCount); | |
164 | fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drXTExtRec[1].startBlock); | |
165 | fork.cf_extents[1].blockCount = SWAP_BE16(mdb->drXTExtRec[1].blockCount); | |
166 | fork.cf_extents[2].startBlock = SWAP_BE16(mdb->drXTExtRec[2].startBlock); | |
167 | fork.cf_extents[2].blockCount = SWAP_BE16(mdb->drXTExtRec[2].blockCount); | |
168 | cnattr.ca_blocks = fork.cf_blocks; | |
169 | ||
170 | error = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &fork, | |
171 | &vcb->extentsRefNum); | |
172 | if (error) goto MtVolErr; | |
173 | error = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum), | |
174 | (KeyCompareProcPtr)CompareExtentKeys, | |
175 | GetBTreeBlock, ReleaseBTreeBlock, | |
176 | ExtendBTreeFile, SetBTreeBlockSize)); | |
177 | if (error) { | |
178 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
179 | goto MtVolErr; | |
180 | } | |
1c79356b A |
181 | |
182 | /* | |
183 | * Set up Catalog B-tree vnode... | |
184 | */ | |
9bccf70c A |
185 | cndesc.cd_nameptr = hfs_catname; |
186 | cndesc.cd_namelen = strlen(hfs_catname); | |
187 | cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID; | |
188 | fork.cf_size = SWAP_BE32(mdb->drCTFlSize); | |
189 | fork.cf_blocks = fork.cf_size / vcb->blockSize; | |
190 | fork.cf_clump = SWAP_BE32(mdb->drCTClpSiz); | |
191 | fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drCTExtRec[0].startBlock); | |
192 | fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drCTExtRec[0].blockCount); | |
193 | fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drCTExtRec[1].startBlock); | |
194 | fork.cf_extents[1].blockCount = SWAP_BE16(mdb->drCTExtRec[1].blockCount); | |
195 | fork.cf_extents[2].startBlock = SWAP_BE16(mdb->drCTExtRec[2].startBlock); | |
196 | fork.cf_extents[2].blockCount = SWAP_BE16(mdb->drCTExtRec[2].blockCount); | |
197 | cnattr.ca_blocks = fork.cf_blocks; | |
198 | ||
199 | error = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &fork, | |
200 | &vcb->catalogRefNum); | |
201 | if (error) { | |
202 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
203 | goto MtVolErr; | |
204 | } | |
205 | error = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum), | |
206 | (KeyCompareProcPtr)CompareCatalogKeys, | |
207 | GetBTreeBlock, ReleaseBTreeBlock, | |
208 | ExtendBTreeFile, SetBTreeBlockSize)); | |
209 | if (error) { | |
210 | VOP_UNLOCK(vcb->catalogRefNum, 0, p); | |
211 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
212 | goto MtVolErr; | |
213 | } | |
1c79356b A |
214 | |
215 | /* mark the volume dirty (clear clean unmount bit) */ | |
216 | vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; | |
217 | ||
1c79356b A |
218 | /* |
219 | * all done with b-trees so we can unlock now... | |
220 | */ | |
9bccf70c A |
221 | VOP_UNLOCK(vcb->catalogRefNum, 0, p); |
222 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
1c79356b | 223 | |
9bccf70c | 224 | if ( error == noErr ) |
1c79356b A |
225 | { |
226 | if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected | |
227 | { | |
228 | MarkVCBDirty( vcb ); // mark VCB dirty so it will be written | |
229 | } | |
230 | } | |
231 | goto CmdDone; | |
232 | ||
233 | //-- Release any resources allocated so far before exiting with an error: | |
9bccf70c | 234 | MtVolErr: |
1c79356b A |
235 | ReleaseMetaFileVNode(vcb->catalogRefNum); |
236 | ReleaseMetaFileVNode(vcb->extentsRefNum); | |
237 | ||
9bccf70c A |
238 | CmdDone: |
239 | return (error); | |
1c79356b A |
240 | } |
241 | ||
242 | //******************************************************************************* | |
243 | // Routine: hfs_MountHFSPlusVolume | |
244 | // | |
245 | // | |
246 | //******************************************************************************* | |
247 | ||
248 | OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, | |
9bccf70c | 249 | off_t embeddedOffset, u_int64_t disksize, struct proc *p) |
1c79356b | 250 | { |
9bccf70c A |
251 | register ExtendedVCB *vcb; |
252 | struct cat_desc cndesc; | |
253 | struct cat_attr cnattr; | |
254 | UInt32 blockSize; | |
255 | OSErr retval; | |
1c79356b | 256 | |
9bccf70c A |
257 | if (SWAP_BE16(vhp->signature) != kHFSPlusSigWord || |
258 | SWAP_BE16(vhp->version) != kHFSPlusVersion) | |
259 | return (EINVAL); | |
1c79356b | 260 | |
9bccf70c A |
261 | /* Block size must be at least 512 and a power of 2 */ |
262 | blockSize = SWAP_BE32(vhp->blockSize); | |
263 | if (blockSize < 512 || (blockSize & (blockSize-1)) != 0) | |
264 | return (EINVAL); | |
1c79356b A |
265 | |
266 | /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */ | |
9bccf70c | 267 | if (hfsmp->hfs_fs_ronly == 0 && (SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) == 0) |
1c79356b | 268 | return (EINVAL); |
d52fe63f A |
269 | |
270 | /* Make sure we can live with the physical block size. */ | |
271 | if ((disksize & (hfsmp->hfs_phys_block_size - 1)) || | |
272 | (embeddedOffset & (hfsmp->hfs_phys_block_size - 1)) || | |
273 | (SWAP_BE32(vhp->blockSize) < hfsmp->hfs_phys_block_size)) { | |
274 | return (ENXIO); | |
275 | } | |
1c79356b A |
276 | /* |
277 | * The VolumeHeader seems OK: transfer info from it into VCB | |
278 | * Note - the VCB starts out clear (all zeros) | |
279 | */ | |
280 | vcb = HFSTOVCB(hfsmp); | |
281 | ||
9bccf70c A |
282 | vcb->vcbSigWord = SWAP_BE16(vhp->signature); |
283 | vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate)); | |
284 | vcb->vcbAtrb = (UInt16)SWAP_BE32(vhp->attributes); | |
285 | vcb->vcbClpSiz = SWAP_BE32(vhp->rsrcClumpSize); | |
286 | vcb->vcbNxtCNID = SWAP_BE32(vhp->nextCatalogID); | |
287 | vcb->vcbVolBkUp = to_bsd_time(SWAP_BE32(vhp->backupDate)); | |
288 | vcb->vcbWrCnt = SWAP_BE32(vhp->writeCount); | |
289 | vcb->vcbFilCnt = SWAP_BE32(vhp->fileCount); | |
290 | vcb->vcbDirCnt = SWAP_BE32(vhp->folderCount); | |
1c79356b A |
291 | |
292 | /* copy 32 bytes of Finder info */ | |
293 | bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo)); | |
294 | ||
295 | vcb->vcbAlBlSt = 0; /* hfs+ allocation blocks start at first block of volume */ | |
9bccf70c A |
296 | if (!hfsmp->hfs_fs_ronly) |
297 | vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */ | |
1c79356b A |
298 | |
299 | VCB_LOCK_INIT(vcb); | |
300 | ||
9bccf70c A |
301 | /* Now fill in the Extended VCB info */ |
302 | vcb->nextAllocation = SWAP_BE32(vhp->nextAllocation); | |
303 | vcb->totalBlocks = SWAP_BE32(vhp->totalBlocks); | |
304 | vcb->freeBlocks = SWAP_BE32(vhp->freeBlocks); | |
305 | vcb->blockSize = SWAP_BE32(vhp->blockSize); | |
306 | vcb->encodingsBitmap = SWAP_BE64(vhp->encodingsBitmap); | |
307 | vcb->localCreateDate = SWAP_BE32(vhp->createDate); | |
1c79356b | 308 | |
9bccf70c | 309 | vcb->hfsPlusIOPosOffset = embeddedOffset; |
1c79356b | 310 | |
9bccf70c A |
311 | /* Default to no free block reserve */ |
312 | vcb->reserveBlocks = 0; | |
1c79356b | 313 | |
9bccf70c A |
314 | /* |
315 | * Update the logical block size in the mount struct | |
316 | * (currently set up from the wrapper MDB) using the | |
317 | * new blocksize value: | |
318 | */ | |
319 | hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size); | |
0b4e3aa0 | 320 | vcb->vcbVBMIOSize = min(vcb->blockSize, MAXPHYSIO); |
1c79356b | 321 | |
9bccf70c A |
322 | bzero(&cndesc, sizeof(cndesc)); |
323 | cndesc.cd_parentcnid = kRootParID; | |
324 | bzero(&cnattr, sizeof(cnattr)); | |
325 | cnattr.ca_nlink = 1; | |
326 | cnattr.ca_mode = S_IFREG; | |
1c79356b A |
327 | |
328 | /* | |
9bccf70c A |
329 | * Set up Extents B-tree vnode |
330 | */ | |
331 | cndesc.cd_nameptr = hfs_extname; | |
332 | cndesc.cd_namelen = strlen(hfs_extname); | |
333 | cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID; | |
334 | ||
335 | SWAP_HFS_PLUS_FORK_DATA (&vhp->extentsFile); | |
336 | cnattr.ca_blocks = vhp->extentsFile.totalBlocks; | |
337 | ||
338 | retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, | |
339 | (struct cat_fork *)&vhp->extentsFile, | |
340 | &vcb->extentsRefNum); | |
341 | SWAP_HFS_PLUS_FORK_DATA (&vhp->extentsFile); | |
342 | ||
1c79356b | 343 | if (retval) goto ErrorExit; |
9bccf70c A |
344 | retval = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum), |
345 | (KeyCompareProcPtr) CompareExtentKeysPlus, | |
346 | GetBTreeBlock, ReleaseBTreeBlock, | |
347 | ExtendBTreeFile, SetBTreeBlockSize)); | |
348 | if (retval) { | |
349 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
350 | goto ErrorExit; | |
351 | } | |
1c79356b A |
352 | |
353 | /* | |
9bccf70c | 354 | * Set up Catalog B-tree vnode |
1c79356b | 355 | */ |
9bccf70c A |
356 | cndesc.cd_nameptr = hfs_catname; |
357 | cndesc.cd_namelen = strlen(hfs_catname); | |
358 | cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID; | |
359 | ||
360 | SWAP_HFS_PLUS_FORK_DATA(&vhp->catalogFile); | |
361 | cnattr.ca_blocks = vhp->catalogFile.totalBlocks; | |
362 | ||
363 | retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, | |
364 | (struct cat_fork *)&vhp->catalogFile, | |
365 | &vcb->catalogRefNum); | |
366 | SWAP_HFS_PLUS_FORK_DATA(&vhp->catalogFile); | |
367 | if (retval) { | |
368 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
369 | goto ErrorExit; | |
370 | } | |
371 | retval = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum), | |
372 | (KeyCompareProcPtr) CompareExtendedCatalogKeys, | |
373 | GetBTreeBlock, ReleaseBTreeBlock, | |
374 | ExtendBTreeFile, SetBTreeBlockSize)); | |
375 | if (retval) { | |
376 | VOP_UNLOCK(vcb->catalogRefNum, 0, p); | |
377 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
378 | goto ErrorExit; | |
379 | } | |
1c79356b A |
380 | |
381 | /* | |
9bccf70c | 382 | * Set up Allocation file vnode |
1c79356b | 383 | */ |
9bccf70c A |
384 | cndesc.cd_nameptr = hfs_vbmname; |
385 | cndesc.cd_namelen = strlen(hfs_vbmname); | |
386 | cndesc.cd_cnid = cnattr.ca_fileid = kHFSAllocationFileID; | |
387 | ||
388 | SWAP_HFS_PLUS_FORK_DATA(&vhp->allocationFile); | |
389 | cnattr.ca_blocks = vhp->allocationFile.totalBlocks; | |
390 | ||
391 | retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, | |
392 | (struct cat_fork *)&vhp->allocationFile, | |
393 | &vcb->allocationsRefNum); | |
394 | SWAP_HFS_PLUS_FORK_DATA(&vhp->allocationFile); | |
395 | if (retval) { | |
396 | VOP_UNLOCK(vcb->catalogRefNum, 0, p); | |
397 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
398 | goto ErrorExit; | |
399 | } | |
400 | ||
401 | /* Pick up volume name and create date */ | |
402 | retval = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, &cnattr, NULL); | |
403 | if (retval) { | |
404 | VOP_UNLOCK(vcb->allocationsRefNum, 0, p); | |
405 | VOP_UNLOCK(vcb->catalogRefNum, 0, p); | |
406 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
407 | goto ErrorExit; | |
408 | } | |
409 | vcb->vcbCrDate = cnattr.ca_itime; | |
410 | vcb->volumeNameEncodingHint = cndesc.cd_encoding; | |
411 | bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen)); | |
412 | cat_releasedesc(&cndesc); | |
1c79356b A |
413 | |
414 | /* mark the volume dirty (clear clean unmount bit) */ | |
415 | vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; | |
416 | ||
1c79356b A |
417 | /* |
418 | * all done with metadata files so we can unlock now... | |
419 | */ | |
420 | VOP_UNLOCK(vcb->allocationsRefNum, 0, p); | |
421 | VOP_UNLOCK(vcb->catalogRefNum, 0, p); | |
422 | VOP_UNLOCK(vcb->extentsRefNum, 0, p); | |
423 | ||
9bccf70c A |
424 | /* setup private/hidden directory for unlinked files */ |
425 | hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb); | |
426 | ||
427 | if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected | |
1c79356b | 428 | { |
9bccf70c | 429 | MarkVCBDirty( vcb ); // mark VCB dirty so it will be written |
1c79356b | 430 | } |
1c79356b A |
431 | |
432 | return (0); | |
433 | ||
1c79356b A |
434 | ErrorExit: |
435 | /* | |
436 | * A fatal error occured and the volume cannot be mounted | |
437 | * release any resources that we aquired... | |
438 | */ | |
439 | ||
9bccf70c | 440 | InvalidateCatalogCache(vcb); |
1c79356b A |
441 | ReleaseMetaFileVNode(vcb->allocationsRefNum); |
442 | ReleaseMetaFileVNode(vcb->catalogRefNum); | |
443 | ReleaseMetaFileVNode(vcb->extentsRefNum); | |
444 | ||
445 | return (retval); | |
446 | } | |
447 | ||
448 | ||
449 | /* | |
450 | * ReleaseMetaFileVNode | |
451 | * | |
452 | * vp L - - | |
453 | */ | |
454 | static void ReleaseMetaFileVNode(struct vnode *vp) | |
455 | { | |
9bccf70c | 456 | struct filefork *fp; |
1c79356b | 457 | |
9bccf70c A |
458 | if (vp && (fp = VTOF(vp))) { |
459 | if (fp->fcbBTCBPtr != NULL) | |
460 | (void) BTClosePath(fp); | |
1c79356b A |
461 | |
462 | /* release the node even if BTClosePath fails */ | |
9bccf70c A |
463 | vrele(vp); |
464 | vgone(vp); | |
1c79356b | 465 | } |
1c79356b A |
466 | } |
467 | ||
468 | ||
469 | /************************************************************* | |
470 | * | |
471 | * Unmounts a hfs volume. | |
472 | * At this point vflush() has been called (to dump all non-metadata files) | |
473 | * | |
474 | *************************************************************/ | |
475 | ||
476 | short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p) | |
477 | { | |
9bccf70c A |
478 | ExtendedVCB *vcb = HFSTOVCB(hfsmp); |
479 | int retval = E_NONE; | |
1c79356b | 480 | |
1c79356b | 481 | InvalidateCatalogCache( vcb ); |
1c79356b A |
482 | |
483 | if (vcb->vcbSigWord == kHFSPlusSigWord) | |
484 | ReleaseMetaFileVNode(vcb->allocationsRefNum); | |
485 | ||
486 | ReleaseMetaFileVNode(vcb->catalogRefNum); | |
487 | ReleaseMetaFileVNode(vcb->extentsRefNum); | |
488 | ||
489 | return (retval); | |
490 | } | |
491 | ||
492 | ||
0b4e3aa0 | 493 | /* |
9bccf70c | 494 | * Some 3rd party kexts link against hfs_getcatalog so keep a stub for now. |
0b4e3aa0 | 495 | */ |
9bccf70c A |
496 | short |
497 | hfs_getcatalog(void *p1, u_long p2, void *p3, short p4, void *p5) | |
0b4e3aa0 | 498 | { |
9bccf70c | 499 | return ENOENT; |
0b4e3aa0 A |
500 | } |
501 | ||
502 | ||
9bccf70c | 503 | int overflow_extents(struct filefork *fp) |
1c79356b | 504 | { |
9bccf70c | 505 | u_long blocks; |
1c79356b | 506 | |
9bccf70c A |
507 | if (VTOVCB(FTOV(fp))->vcbSigWord == kHFSPlusSigWord) { |
508 | if (fp->ff_extents[7].blockCount == 0) | |
509 | return (0); | |
1c79356b | 510 | |
9bccf70c A |
511 | blocks = fp->ff_extents[0].blockCount + |
512 | fp->ff_extents[1].blockCount + | |
513 | fp->ff_extents[2].blockCount + | |
514 | fp->ff_extents[3].blockCount + | |
515 | fp->ff_extents[4].blockCount + | |
516 | fp->ff_extents[5].blockCount + | |
517 | fp->ff_extents[6].blockCount + | |
518 | fp->ff_extents[7].blockCount; | |
519 | } else { | |
520 | if (fp->ff_extents[2].blockCount == 0) | |
521 | return false; | |
522 | ||
523 | blocks = fp->ff_extents[0].blockCount + | |
524 | fp->ff_extents[1].blockCount + | |
525 | fp->ff_extents[2].blockCount; | |
526 | } | |
1c79356b | 527 | |
9bccf70c A |
528 | return (fp->ff_blocks > blocks); |
529 | } | |
1c79356b A |
530 | |
531 | ||
9bccf70c A |
532 | /* __private_extern__ */ |
533 | int | |
534 | hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p) | |
1c79356b | 535 | { |
9bccf70c A |
536 | ExtendedVCB *vcb; |
537 | struct vnode *vp = NULL; | |
538 | int numOfLockedBuffs; | |
539 | int retval = 0; | |
1c79356b | 540 | |
9bccf70c A |
541 | vcb = HFSTOVCB(hfsmp); |
542 | ||
543 | switch (fileID) { | |
544 | case kHFSExtentsFileID: | |
545 | vp = vcb->extentsRefNum; | |
546 | break; | |
547 | ||
548 | case kHFSCatalogFileID: | |
549 | vp = vcb->catalogRefNum; | |
550 | break; | |
551 | ||
552 | case kHFSAllocationFileID: | |
553 | /* bitmap is covered by Extents B-tree locking */ | |
554 | /* FALL THROUGH */ | |
555 | default: | |
556 | panic("hfs_lockmetafile: invalid fileID"); | |
557 | } | |
1c79356b | 558 | |
9bccf70c A |
559 | /* Release, if necesary any locked buffer caches */ |
560 | if ((flags & LK_TYPE_MASK) == LK_RELEASE) { | |
561 | struct timeval tv = time; | |
562 | u_int32_t lastfsync = tv.tv_sec; | |
1c79356b | 563 | |
9bccf70c A |
564 | (void) BTGetLastSync((FCB*)VTOF(vp), &lastfsync); |
565 | ||
566 | numOfLockedBuffs = count_lock_queue(); | |
567 | if ((numOfLockedBuffs > kMaxLockedMetaBuffers) || ((numOfLockedBuffs>1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) { | |
568 | hfs_btsync(vp, HFS_SYNCTRANS); | |
569 | } | |
570 | } else { | |
571 | flags |= LK_RETRY; | |
572 | } | |
573 | ||
574 | retval = lockmgr(&VTOC(vp)->c_lock, flags, &vp->v_interlock, p); | |
1c79356b | 575 | |
9bccf70c A |
576 | return (retval); |
577 | } | |
1c79356b | 578 | |
9bccf70c A |
579 | /* |
580 | * RequireFileLock | |
581 | * | |
582 | * Check to see if a vnode is locked in the current context | |
583 | * This is to be used for debugging purposes only!! | |
584 | */ | |
585 | #if HFS_DIAGNOSTIC | |
586 | void RequireFileLock(FileReference vp, int shareable) | |
1c79356b | 587 | { |
9bccf70c A |
588 | struct lock__bsd__ *lkp; |
589 | int locked = false; | |
590 | pid_t pid; | |
591 | void * self; | |
1c79356b | 592 | |
9bccf70c A |
593 | pid = current_proc()->p_pid; |
594 | self = (void *) current_thread(); | |
595 | lkp = &VTOC(vp)->c_lock; | |
1c79356b | 596 | |
9bccf70c A |
597 | simple_lock(&lkp->lk_interlock); |
598 | ||
599 | if (shareable && (lkp->lk_sharecount > 0) && (lkp->lk_lockholder == LK_NOPROC)) | |
600 | locked = true; | |
601 | else if ((lkp->lk_exclusivecount > 0) && (lkp->lk_lockholder == pid) && (lkp->lk_lockthread == self)) | |
602 | locked = true; | |
1c79356b | 603 | |
9bccf70c A |
604 | simple_unlock(&lkp->lk_interlock); |
605 | ||
606 | if (!locked) { | |
607 | switch (VTOC(vp)->c_fileid) { | |
608 | case 3: | |
609 | DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp)); | |
610 | break; | |
1c79356b | 611 | |
9bccf70c A |
612 | case 4: |
613 | DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp)); | |
614 | break; | |
1c79356b | 615 | |
9bccf70c A |
616 | default: |
617 | DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", VTOC(vp)->c_fileid, (u_int)vp)); | |
618 | break; | |
619 | } | |
620 | } | |
1c79356b | 621 | } |
9bccf70c | 622 | #endif |
1c79356b A |
623 | |
624 | ||
9bccf70c A |
625 | /* |
626 | * There are three ways to qualify for ownership rights on an object: | |
627 | * | |
628 | * 1. (a) Your UID matches the cnode's UID. | |
629 | * (b) The object in question is owned by "unknown" and | |
630 | * your UID matches the console user's UID. | |
631 | * 2. (a) Permissions on the filesystem are being ignored and | |
632 | * your UID matches the replacement UID. | |
633 | * (b) Permissions on the filesystem are being ignored and | |
634 | * the replacement UID is "unknown" and | |
635 | * your UID matches the console user UID. | |
636 | * 3. You are root. | |
637 | * | |
638 | */ | |
639 | int | |
640 | hfs_owner_rights(struct hfsmount *hfsmp, uid_t cnode_uid, struct ucred *cred, | |
641 | struct proc *p, int invokesuperuserstatus) | |
642 | { | |
643 | if ((cred->cr_uid == cnode_uid) || /* [1a] */ | |
644 | ((cnode_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */ | |
645 | ((HFSTOVFS(hfsmp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */ | |
646 | ((cred->cr_uid == hfsmp->hfs_uid) || /* [2a] */ | |
647 | ((hfsmp->hfs_uid == UNKNOWNUID) && /* [2b] */ | |
648 | (cred->cr_uid == console_user)))) || | |
649 | (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) { /* [3] */ | |
650 | return (0); | |
651 | } else { | |
652 | return (EPERM); | |
653 | } | |
1c79356b A |
654 | } |
655 | ||
656 | ||
9bccf70c A |
657 | unsigned long BestBlockSizeFit(unsigned long allocationBlockSize, |
658 | unsigned long blockSizeLimit, | |
659 | unsigned long baseMultiple) { | |
660 | /* | |
661 | Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the | |
662 | specified limit but still an even multiple of the baseMultiple. | |
663 | */ | |
664 | int baseBlockCount, blockCount; | |
665 | unsigned long trialBlockSize; | |
1c79356b | 666 | |
9bccf70c A |
667 | if (allocationBlockSize % baseMultiple != 0) { |
668 | /* | |
669 | Whoops: the allocation blocks aren't even multiples of the specified base: | |
670 | no amount of dividing them into even parts will be a multiple, either then! | |
671 | */ | |
672 | return 512; /* Hope for the best */ | |
673 | }; | |
1c79356b | 674 | |
9bccf70c A |
675 | /* Try the obvious winner first, to prevent 12K allocation blocks, for instance, |
676 | from being handled as two 6K logical blocks instead of 3 4K logical blocks. | |
677 | Even though the former (the result of the loop below) is the larger allocation | |
678 | block size, the latter is more efficient: */ | |
679 | if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE; | |
1c79356b | 680 | |
9bccf70c A |
681 | /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */ |
682 | baseBlockCount = allocationBlockSize / baseMultiple; /* Now guaranteed to be an even multiple */ | |
1c79356b | 683 | |
9bccf70c A |
684 | for (blockCount = baseBlockCount; blockCount > 0; --blockCount) { |
685 | trialBlockSize = blockCount * baseMultiple; | |
686 | if (allocationBlockSize % trialBlockSize == 0) { /* An even multiple? */ | |
687 | if ((trialBlockSize <= blockSizeLimit) && | |
688 | (trialBlockSize % baseMultiple == 0)) { | |
689 | return trialBlockSize; | |
690 | }; | |
691 | }; | |
692 | }; | |
1c79356b | 693 | |
9bccf70c A |
694 | /* Note: we should never get here, since blockCount = 1 should always work, |
695 | but this is nice and safe and makes the compiler happy, too ... */ | |
696 | return 512; | |
697 | } | |
1c79356b | 698 | |
1c79356b | 699 | |
9bccf70c A |
700 | /* |
701 | * To make the HFS Plus filesystem follow UFS unlink semantics, a remove | |
702 | * of an active vnode is translated to a move/rename so the file appears | |
703 | * deleted. The destination folder for these move/renames is setup here | |
704 | * and a reference to it is place in hfsmp->hfs_private_metadata_dir. | |
705 | */ | |
706 | u_long | |
707 | FindMetaDataDirectory(ExtendedVCB *vcb) | |
1c79356b | 708 | { |
9bccf70c A |
709 | struct hfsmount * hfsmp; |
710 | struct vnode * dvp = NULL; | |
711 | struct cnode * dcp = NULL; | |
712 | struct FndrDirInfo * fndrinfo; | |
713 | struct cat_desc out_desc = {0}; | |
714 | struct timeval tv; | |
715 | int error; | |
716 | ||
717 | if (vcb->vcbSigWord != kHFSPlusSigWord) | |
7b1edb79 | 718 | return (0); |
7b1edb79 | 719 | |
9bccf70c | 720 | hfsmp = VCBTOHFS(vcb); |
7b1edb79 | 721 | |
9bccf70c A |
722 | if (hfsmp->hfs_privdir_desc.cd_parentcnid == 0) { |
723 | hfsmp->hfs_privdir_desc.cd_parentcnid = kRootDirID; | |
724 | hfsmp->hfs_privdir_desc.cd_nameptr = hfs_privdirname; | |
725 | hfsmp->hfs_privdir_desc.cd_namelen = strlen(hfs_privdirname); | |
726 | hfsmp->hfs_privdir_desc.cd_flags = CD_ISDIR; | |
7b1edb79 A |
727 | } |
728 | ||
9bccf70c A |
729 | /* Lock catalog b-tree */ |
730 | error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, current_proc()); | |
731 | if (error) | |
732 | return (0); | |
1c79356b | 733 | |
9bccf70c A |
734 | error = cat_lookup(hfsmp, &hfsmp->hfs_privdir_desc, 0, NULL, |
735 | &hfsmp->hfs_privdir_attr, NULL); | |
736 | ||
737 | if (error == 0) { | |
738 | /* Unlock catalog b-tree */ | |
739 | (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); | |
740 | hfsmp->hfs_metadata_createdate = hfsmp->hfs_privdir_attr.ca_itime; | |
741 | return (hfsmp->hfs_privdir_attr.ca_fileid); | |
742 | } else if (hfsmp->hfs_fs_ronly) { | |
743 | /* Unlock catalog b-tree */ | |
744 | (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); | |
745 | return (0); | |
1c79356b | 746 | } |
9bccf70c A |
747 | |
748 | /* Setup the default attributes */ | |
749 | bzero(&hfsmp->hfs_privdir_attr, sizeof(struct cat_attr)); | |
750 | hfsmp->hfs_privdir_attr.ca_mode = S_IFDIR; | |
751 | hfsmp->hfs_privdir_attr.ca_flags = SF_IMMUTABLE; | |
752 | hfsmp->hfs_privdir_attr.ca_nlink = 2; | |
753 | hfsmp->hfs_privdir_attr.ca_itime = vcb->vcbCrDate; | |
754 | hfsmp->hfs_privdir_attr.ca_mtime = time.tv_sec; | |
755 | ||
756 | /* hidden and off the desktop view */ | |
757 | fndrinfo = (struct FndrDirInfo *)&hfsmp->hfs_privdir_attr.ca_finderinfo; | |
758 | fndrinfo->frLocation.v = SWAP_BE16 (22460); | |
759 | fndrinfo->frLocation.h = SWAP_BE16 (22460); | |
760 | fndrinfo->frFlags |= SWAP_BE16 (kIsInvisible + kNameLocked); | |
761 | ||
762 | error = cat_create(hfsmp, &hfsmp->hfs_privdir_desc, | |
763 | &hfsmp->hfs_privdir_attr, &out_desc); | |
764 | ||
765 | /* Unlock catalog b-tree */ | |
766 | (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); | |
767 | if (error) | |
768 | return (0); | |
1c79356b | 769 | |
9bccf70c A |
770 | hfsmp->hfs_privdir_desc.cd_hint = out_desc.cd_hint; |
771 | hfsmp->hfs_privdir_desc.cd_cnid = out_desc.cd_cnid; | |
772 | hfsmp->hfs_privdir_attr.ca_fileid = out_desc.cd_cnid; | |
773 | hfsmp->hfs_metadata_createdate = vcb->vcbCrDate; | |
774 | ||
775 | if (VFS_ROOT(HFSTOVFS(hfsmp), &dvp) == 0) { | |
776 | dcp = VTOC(dvp); | |
777 | dcp->c_childhint = out_desc.cd_hint; | |
778 | dcp->c_nlink++; | |
779 | dcp->c_entries++; | |
780 | dcp->c_flag |= C_CHANGE | C_UPDATE; | |
781 | tv = time; | |
782 | (void) VOP_UPDATE(dvp, &tv, &tv, 0); | |
783 | vput(dvp); | |
1c79356b | 784 | } |
9bccf70c A |
785 | hfs_volupdate(hfsmp, VOL_MKDIR, 1); |
786 | cat_releasedesc(&out_desc); | |
1c79356b | 787 | |
9bccf70c | 788 | return (out_desc.cd_cnid); |
1c79356b A |
789 | } |
790 | ||
9bccf70c A |
791 | |
792 | /* | |
793 | * This will return the correct logical block size for a given vnode. | |
794 | * For most files, it is the allocation block size, for meta data like | |
795 | * BTrees, this is kept as part of the BTree private nodeSize | |
796 | */ | |
797 | u_int32_t | |
798 | GetLogicalBlockSize(struct vnode *vp) | |
1c79356b | 799 | { |
9bccf70c | 800 | u_int32_t logBlockSize; |
1c79356b | 801 | |
9bccf70c | 802 | DBG_ASSERT(vp != NULL); |
1c79356b | 803 | |
9bccf70c A |
804 | /* start with default */ |
805 | logBlockSize = VTOHFS(vp)->hfs_logBlockSize; | |
1c79356b | 806 | |
0b4e3aa0 | 807 | if (vp->v_flag & VSYSTEM) { |
9bccf70c | 808 | if (VTOF(vp)->fcbBTCBPtr != NULL) { |
0b4e3aa0 A |
809 | BTreeInfoRec bTreeInfo; |
810 | ||
811 | /* | |
812 | * We do not lock the BTrees, because if we are getting block..then the tree | |
813 | * should be locked in the first place. | |
814 | * We just want the nodeSize wich will NEVER change..so even if the world | |
815 | * is changing..the nodeSize should remain the same. Which argues why lock | |
816 | * it in the first place?? | |
817 | */ | |
818 | ||
9bccf70c | 819 | (void) BTGetInformation (VTOF(vp), kBTreeInfoVersion, &bTreeInfo); |
0b4e3aa0 A |
820 | |
821 | logBlockSize = bTreeInfo.nodeSize; | |
822 | ||
9bccf70c | 823 | } else if (VTOC(vp)->c_fileid == kHFSAllocationFileID) { |
0b4e3aa0 | 824 | logBlockSize = VTOVCB(vp)->vcbVBMIOSize; |
1c79356b | 825 | } |
0b4e3aa0 A |
826 | } |
827 | ||
1c79356b A |
828 | DBG_ASSERT(logBlockSize > 0); |
829 | ||
830 | return logBlockSize; | |
831 | } | |
832 | ||
9bccf70c A |
833 | __private_extern__ |
834 | u_int32_t | |
835 | hfs_freeblks(struct hfsmount * hfsmp, int wantreserve) | |
836 | { | |
837 | struct vcb_t *vcb = HFSTOVCB(hfsmp); | |
838 | u_int32_t freeblks; | |
839 | ||
840 | freeblks = vcb->freeBlocks; | |
841 | if (wantreserve) { | |
842 | if (freeblks > vcb->reserveBlocks) | |
843 | freeblks -= vcb->reserveBlocks; | |
844 | else | |
845 | freeblks = 0; | |
846 | } | |
847 | ||
848 | freeblks -= vcb->loanedBlocks; | |
849 | return (freeblks); | |
850 | } | |
851 | ||
1c79356b A |
852 | /* |
853 | * Map HFS Common errors (negative) to BSD error codes (positive). | |
854 | * Positive errors (ie BSD errors) are passed through unchanged. | |
855 | */ | |
856 | short MacToVFSError(OSErr err) | |
857 | { | |
9bccf70c A |
858 | if (err >= 0) |
859 | return err; | |
1c79356b | 860 | |
1c79356b | 861 | switch (err) { |
9bccf70c A |
862 | case dskFulErr: /* -34 */ |
863 | case btNoSpaceAvail: /* -32733 */ | |
864 | case fxOvFlErr: /* -32750 */ | |
865 | return ENOSPC; /* +28 */ | |
866 | ||
867 | case btBadNode: /* -32731 */ | |
868 | return EIO; /* +5 */ | |
869 | ||
870 | case memFullErr: /* -108 */ | |
871 | return ENOMEM; /* +12 */ | |
872 | ||
873 | case cmExists: /* -32718 */ | |
874 | case btExists: /* -32734 */ | |
875 | return EEXIST; /* +17 */ | |
876 | ||
877 | case cmNotFound: /* -32719 */ | |
878 | case btNotFound: /* -32735 */ | |
879 | return ENOENT; /* 28 */ | |
880 | ||
881 | case cmNotEmpty: /* -32717 */ | |
882 | return ENOTEMPTY; /* 66 */ | |
883 | ||
884 | case cmFThdDirErr: /* -32714 */ | |
885 | return EISDIR; /* 21 */ | |
886 | ||
887 | case fxRangeErr: /* -32751 */ | |
888 | return EIO; /* 5 */ | |
889 | ||
890 | case bdNamErr: /* -37 */ | |
891 | return ENAMETOOLONG; /* 63 */ | |
892 | ||
893 | case paramErr: /* -50 */ | |
894 | case fileBoundsErr: /* -1309 */ | |
895 | return EINVAL; /* +22 */ | |
896 | ||
897 | case fsBTBadNodeSize: | |
d52fe63f | 898 | return ENXIO; |
9bccf70c A |
899 | |
900 | default: | |
901 | return EIO; /* +5 */ | |
1c79356b A |
902 | } |
903 | } | |
904 | ||
905 | ||
906 | /* | |
9bccf70c A |
907 | * Get the directory entry name hint for a given index. |
908 | * The directory cnode (dcp) must be locked. | |
1c79356b | 909 | */ |
9bccf70c A |
910 | __private_extern__ |
911 | char * | |
912 | hfs_getnamehint(struct cnode *dcp, int index) | |
1c79356b | 913 | { |
9bccf70c A |
914 | struct hfs_index *entry; |
915 | void *self; | |
1c79356b | 916 | |
9bccf70c A |
917 | if (index > 0) { |
918 | self = current_thread(); | |
919 | SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) { | |
920 | if ((entry->hi_index == index) | |
921 | && (entry->hi_thread == self)) | |
922 | return (entry->hi_name); | |
923 | } | |
924 | } | |
1c79356b | 925 | |
9bccf70c | 926 | return (NULL); |
1c79356b A |
927 | } |
928 | ||
9bccf70c A |
929 | /* |
930 | * Save a directory entry name hint for a given index. | |
931 | * The directory cnode (dcp) must be locked. | |
932 | */ | |
933 | __private_extern__ | |
934 | void | |
935 | hfs_savenamehint(struct cnode *dcp, int index, const char * namehint) | |
936 | { | |
937 | struct hfs_index *entry; | |
938 | int len; | |
939 | ||
940 | if (index > 0) { | |
941 | len = strlen(namehint); | |
942 | MALLOC(entry, struct hfs_index *, len + sizeof(struct hfs_index), | |
943 | M_TEMP, M_WAITOK); | |
944 | entry->hi_index = index; | |
945 | entry->hi_thread = current_thread(); | |
946 | bcopy(namehint, entry->hi_name, len + 1); | |
947 | SLIST_INSERT_HEAD(&dcp->c_indexlist, entry, hi_link); | |
948 | } | |
1c79356b A |
949 | } |
950 | ||
9bccf70c A |
951 | /* |
952 | * Release the directory entry name hint for a given index. | |
953 | * The directory cnode (dcp) must be locked. | |
954 | */ | |
955 | __private_extern__ | |
956 | void | |
957 | hfs_relnamehint(struct cnode *dcp, int index) | |
958 | { | |
959 | struct hfs_index *entry; | |
960 | void *self; | |
961 | ||
962 | if (index > 0) { | |
963 | self = current_thread(); | |
964 | SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) { | |
965 | if ((entry->hi_index == index) | |
966 | && (entry->hi_thread == self)) { | |
967 | SLIST_REMOVE(&dcp->c_indexlist, entry, hfs_index, | |
968 | hi_link); | |
969 | FREE(entry, M_TEMP); | |
970 | break; | |
971 | } | |
972 | } | |
1c79356b | 973 | } |
1c79356b A |
974 | } |
975 | ||
9bccf70c A |
976 | /* |
977 | * Release all directory entry name hints. | |
978 | */ | |
979 | __private_extern__ | |
980 | void | |
981 | hfs_relnamehints(struct cnode *dcp) | |
982 | { | |
983 | struct hfs_index *entry; | |
984 | struct hfs_index *next; | |
1c79356b | 985 | |
9bccf70c A |
986 | if (!SLIST_EMPTY(&dcp->c_indexlist)) { |
987 | for(entry = SLIST_FIRST(&dcp->c_indexlist); | |
988 | entry != NULL; | |
989 | entry = next) { | |
990 | next = SLIST_NEXT(entry, hi_link); | |
991 | SLIST_REMOVE(&dcp->c_indexlist, entry, hfs_index, hi_link); | |
992 | FREE(entry, M_TEMP); | |
1c79356b | 993 | } |
1c79356b | 994 | } |
9bccf70c | 995 | } |
1c79356b | 996 | |
1c79356b | 997 | |
1c79356b | 998 |