1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | #include "Inode.h" |
9 | #include "BPlusTree.h" |
10 | |
11 | #include <Directory.h> |
12 | #include <SymLink.h> |
13 | #include <Entry.h> |
14 | #include <Path.h> |
15 | #include <String.h> |
16 | |
17 | #include <new> |
18 | #include <stdlib.h> |
19 | #include <stdio.h> |
20 | #include <string.h> |
21 | |
22 | |
23 | class NodeGetter { |
24 | public: |
25 | NodeGetter(Inode* inode) |
26 | : |
27 | fInode(inode) |
28 | { |
29 | fInode->AcquireBuffer(); |
30 | } |
31 | |
32 | ~NodeGetter() |
33 | { |
34 | fInode->ReleaseBuffer(); |
35 | } |
36 | |
37 | private: |
38 | Inode* fInode; |
39 | }; |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | Inode::Inode(Disk* disk, bfs_inode* inode, bool ownBuffer) |
46 | : |
47 | fDisk(disk), |
48 | fInode(inode), |
49 | fOwnBuffer(ownBuffer), |
50 | fPath(NULL__null), |
51 | fRefCount(1), |
52 | fCurrentSmallData(NULL__null), |
53 | fAttributes(NULL__null), |
54 | fAttributeBuffer(NULL__null) |
55 | { |
56 | if (inode != NULL__null) |
57 | fBlockRun = inode->inode_num; |
58 | } |
59 | |
60 | |
61 | Inode::Inode(const Inode& inode) |
62 | : |
63 | fDisk(inode.fDisk), |
64 | fInode(inode.fInode), |
65 | fOwnBuffer(false), |
66 | fPath(NULL__null), |
67 | fBlockRun(inode.fBlockRun), |
68 | fRefCount(1), |
69 | fCurrentSmallData(NULL__null), |
70 | fAttributes(NULL__null), |
71 | fAttributeBuffer(NULL__null) |
72 | { |
73 | } |
74 | |
75 | |
76 | Inode::~Inode() |
77 | { |
78 | _Unset(); |
79 | } |
80 | |
81 | |
82 | void |
83 | Inode::_Unset() |
84 | { |
85 | if (fOwnBuffer) |
86 | free(fInode); |
87 | |
88 | fInode = NULL__null; |
89 | fBlockRun.SetTo(0, 0, 0); |
90 | |
91 | free(fPath); |
92 | fPath = NULL__null; |
93 | |
94 | delete fAttributes; |
95 | fAttributes = NULL__null; |
96 | } |
97 | |
98 | |
99 | status_t |
100 | Inode::SetTo(bfs_inode *inode) |
101 | { |
102 | _Unset(); |
103 | |
104 | fInode = inode; |
105 | fBlockRun = inode->inode_num; |
106 | return B_OK((int)0); |
107 | } |
108 | |
109 | |
110 | status_t |
111 | Inode::InitCheck() |
112 | { |
113 | if (!fInode) |
114 | return B_ERROR(-1); |
115 | |
116 | |
117 | if (fInode->magic1 != INODE_MAGIC10x3bbe0ad9 |
118 | || !(fInode->flags & INODE_IN_USE) |
119 | || fInode->inode_num.length != 1) |
120 | return B_ERROR(-1); |
121 | |
122 | if (fDisk->BlockSize()) { |
123 | |
124 | if (fInode->inode_size != fDisk->SuperBlock()->inode_size |
125 | |
126 | || fInode->parent.allocation_group > fDisk->SuperBlock()->num_ags |
127 | || fInode->parent.allocation_group < 0 |
128 | || fInode->parent.start > (1L << fDisk->SuperBlock()->ag_shift) |
129 | || fInode->parent.length != 1 |
130 | |
131 | || fInode->attributes.allocation_group > fDisk->SuperBlock()->num_ags |
132 | || fInode->attributes.allocation_group < 0 |
133 | || fInode->attributes.start > (1L << fDisk->SuperBlock()->ag_shift)) |
134 | return B_ERROR(-1); |
135 | } else { |
136 | |
137 | switch (fInode->inode_size) { |
138 | case 1024: |
139 | case 2048: |
140 | case 4096: |
141 | case 8192: |
142 | break; |
143 | default: |
144 | return B_ERROR(-1); |
145 | } |
146 | } |
147 | return B_OK((int)0); |
148 | |
149 | |
150 | } |
151 | |
152 | |
153 | status_t |
154 | Inode::CopyBuffer() |
155 | { |
156 | if (!fInode) |
157 | return B_ERROR(-1); |
158 | |
159 | bfs_inode *buffer = (bfs_inode *)malloc(fInode->inode_size); |
160 | if (!buffer) |
161 | return B_NO_MEMORY((-2147483647 - 1) + 0); |
162 | |
163 | memcpy(buffer, fInode, fInode->inode_size); |
164 | fInode = buffer; |
165 | fOwnBuffer = true; |
166 | BufferClobbered(); |
167 | |
168 | |
169 | return B_OK((int)0); |
170 | } |
171 | |
172 | |
173 | bool |
174 | Inode::_LowMemory() |
175 | { |
176 | static bigtime_t lastChecked; |
177 | static int32 percentUsed; |
178 | |
179 | if (system_time() > lastChecked + 1000000LL) { |
180 | system_info info; |
181 | get_system_info(&info)_get_system_info((&info), sizeof(*(&info))); |
182 | percentUsed = 100 * info.used_pages / info.max_pages; |
183 | } |
184 | |
185 | return percentUsed > 75; |
186 | } |
187 | |
188 | |
189 | void |
190 | Inode::ReleaseBuffer() |
191 | { |
192 | if (atomic_add(&fRefCount, -1)__sync_fetch_and_add(&fRefCount, -1) != 1) |
193 | return; |
194 | |
195 | if (fOwnBuffer) { |
196 | if (!_LowMemory()) |
197 | return; |
198 | |
199 | free(fInode); |
200 | fInode = NULL__null; |
201 | } |
202 | } |
203 | |
204 | |
205 | status_t |
206 | Inode::AcquireBuffer() |
207 | { |
208 | if (atomic_add(&fRefCount, 1)__sync_fetch_and_add(&fRefCount, 1) != 0) |
209 | return B_OK((int)0); |
210 | |
211 | if (!fOwnBuffer || fInode != NULL__null) |
212 | return B_OK((int)0); |
213 | |
214 | fInode = (bfs_inode*)malloc(fDisk->BlockSize()); |
215 | if (fInode == NULL__null) |
216 | return B_NO_MEMORY((-2147483647 - 1) + 0); |
217 | |
218 | ssize_t bytesRead = fDisk->ReadAt(Offset(), fInode, fDisk->BlockSize()); |
219 | if (bytesRead < B_OK((int)0)) |
220 | return bytesRead; |
221 | |
222 | return B_OK((int)0); |
223 | } |
224 | |
225 | |
226 | void |
227 | Inode::BufferClobbered() |
228 | { |
229 | AcquireBuffer(); |
230 | } |
231 | |
232 | |
233 | void |
234 | Inode::SetParent(const block_run& run) |
235 | { |
236 | fInode->parent = run; |
237 | BufferClobbered(); |
238 | } |
239 | |
240 | |
241 | void |
242 | Inode::SetBlockRun(const block_run& run) |
243 | { |
244 | fInode->inode_num = run; |
245 | fBlockRun = run; |
246 | BufferClobbered(); |
247 | } |
248 | |
249 | |
250 | void |
251 | Inode::SetMode(uint32 mode) |
252 | { |
253 | fInode->mode = mode; |
254 | BufferClobbered(); |
255 | } |
256 | |
257 | |
258 | status_t |
259 | Inode::SetName(const char *name) |
260 | { |
261 | if (name == NULL__null || *name == '\0') |
262 | return B_BAD_VALUE((-2147483647 - 1) + 5); |
263 | |
264 | small_data *data = fInode->small_data_start, *nameData = NULL__null; |
265 | BufferClobbered(); |
266 | |
267 | while (!data->IsLast(fInode)) { |
268 | if (data->type == FILE_NAME_TYPE'CSTR' |
269 | && data->name_size == FILE_NAME_NAME_LENGTH1 |
270 | && *data->Name() == FILE_NAME_NAME0x13) |
271 | nameData = data; |
272 | |
273 | data = data->Next(); |
274 | } |
275 | |
276 | int32 oldLength = nameData == NULL__null ? 0 : nameData->data_size; |
277 | int32 newLength = strlen(name) + (nameData == NULL__null ? sizeof(small_data) + 5 : 0); |
278 | |
279 | if ((addr_t)data + newLength - oldLength >= (addr_t)(fInode |
280 | + fDisk->BlockSize())) |
281 | return B_NO_MEMORY((-2147483647 - 1) + 0); |
282 | |
283 | if (nameData == NULL__null) { |
284 | memmove(newLength + (uint8 *)fInode->small_data_start, |
285 | fInode->small_data_start, |
286 | (addr_t)data - (addr_t)fInode->small_data_start); |
287 | nameData = fInode->small_data_start; |
288 | } else { |
289 | memmove(newLength + (uint8 *)nameData, nameData, |
290 | (addr_t)data - (addr_t)fInode->small_data_start); |
291 | } |
292 | |
293 | memset(nameData, 0, sizeof(small_data) + 5 + strlen(name)); |
294 | nameData->type = FILE_NAME_TYPE'CSTR'; |
295 | nameData->name_size = FILE_NAME_NAME_LENGTH1; |
296 | nameData->data_size = strlen(name); |
297 | *nameData->Name() = FILE_NAME_NAME0x13; |
298 | strcpy((char *)nameData->Data(),name); |
299 | |
300 | return B_OK((int)0); |
301 | } |
302 | |
303 | |
304 | const char * |
305 | Inode::Name() const |
306 | { |
307 | small_data *data = fInode->small_data_start; |
308 | while (!data->IsLast(fInode)) { |
309 | if (data->type == FILE_NAME_TYPE'CSTR' |
310 | && data->name_size == FILE_NAME_NAME_LENGTH1 |
311 | && *data->Name() == FILE_NAME_NAME0x13) |
312 | return (const char *)data->Data(); |
313 | |
314 | data = data->Next(); |
315 | } |
316 | return NULL__null; |
317 | } |
318 | |
319 | |
320 | status_t |
321 | Inode::GetNextSmallData(small_data **smallData) |
322 | { |
323 | if (!fInode) |
324 | return B_ERROR(-1); |
325 | |
326 | small_data *data = *smallData; |
327 | |
328 | |
329 | if (data == NULL__null) |
330 | data = fInode->small_data_start; |
331 | else |
332 | data = data->Next(); |
333 | |
334 | |
335 | if (data->IsLast(fInode)) |
336 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); |
337 | |
338 | *smallData = data; |
339 | return B_OK((int)0); |
340 | } |
341 | |
342 | |
343 | status_t |
344 | Inode::RewindAttributes() |
345 | { |
346 | fCurrentSmallData = NULL__null; |
347 | |
348 | if (fAttributes != NULL__null) |
349 | fAttributes->Rewind(); |
350 | |
351 | return B_OK((int)0); |
352 | } |
353 | |
354 | |
355 | status_t |
356 | Inode::GetNextAttribute(char *name, uint32 *type, void **data, size_t *length) |
357 | { |
358 | |
359 | |
360 | if (fCurrentSmallData == NULL__null || !fCurrentSmallData->IsLast(fInode)) { |
361 | if (fCurrentSmallData == NULL__null) |
362 | fCurrentSmallData = fInode->small_data_start; |
363 | else |
364 | fCurrentSmallData = fCurrentSmallData->Next(); |
365 | |
366 | |
367 | if (!fCurrentSmallData->IsLast(fInode) |
368 | && fCurrentSmallData->name_size == FILE_NAME_NAME_LENGTH1 |
369 | && *fCurrentSmallData->Name() == FILE_NAME_NAME0x13) |
370 | fCurrentSmallData = fCurrentSmallData->Next(); |
371 | |
372 | if (!fCurrentSmallData->IsLast(fInode)) { |
373 | strncpy(name,fCurrentSmallData->Name(), B_FILE_NAME_LENGTH(256)); |
374 | *type = fCurrentSmallData->type; |
375 | *data = fCurrentSmallData->Data(); |
376 | *length = fCurrentSmallData->data_size; |
377 | |
378 | return B_OK((int)0); |
379 | } |
380 | } |
381 | |
382 | |
383 | |
384 | if (Attributes().IsZero()) |
385 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); |
386 | |
387 | if (fAttributes == NULL__null) |
388 | fAttributes = (Directory *)Inode::Factory(fDisk, Attributes()); |
389 | |
390 | status_t status = fAttributes ? fAttributes->InitCheck() : B_ERROR(-1); |
391 | if (status < B_OK((int)0)) |
392 | return status; |
393 | |
394 | block_run run; |
395 | status = fAttributes->GetNextEntry(name, &run); |
396 | if (status < B_OK((int)0)) { |
397 | free(fAttributeBuffer); |
398 | fAttributeBuffer = NULL__null; |
399 | return status; |
400 | } |
401 | |
402 | Attribute *attribute = (Attribute *)Inode::Factory(fDisk, run); |
403 | if (attribute == NULL__null || attribute->InitCheck() < B_OK((int)0)) |
404 | return B_IO_ERROR((-2147483647 - 1) + 1); |
405 | |
406 | *type = attribute->Type(); |
407 | |
408 | void *buffer = realloc(fAttributeBuffer, attribute->Size()); |
409 | if (buffer == NULL__null) { |
410 | free(fAttributeBuffer); |
411 | fAttributeBuffer = NULL__null; |
412 | delete attribute; |
413 | return B_NO_MEMORY((-2147483647 - 1) + 0); |
414 | } |
415 | fAttributeBuffer = buffer; |
416 | |
417 | ssize_t size = attribute->Read(fAttributeBuffer, attribute->Size()); |
418 | delete attribute; |
419 | |
420 | *length = size; |
421 | *data = fAttributeBuffer; |
422 | |
423 | return size < B_OK((int)0) ? size : B_OK((int)0); |
424 | } |
425 | |
426 | |
427 | status_t |
428 | Inode::_FindPath(Inode::Source *source) |
429 | { |
430 | BString path; |
431 | |
432 | block_run parent = Parent(); |
433 | while (!parent.IsZero() && parent != fDisk->Root()) { |
434 | Inode *inode; |
435 | if (source) |
436 | inode = source->InodeAt(parent); |
437 | else |
438 | inode = Inode::Factory(fDisk, parent); |
439 | |
440 | if (inode == NULL__null |
441 | || inode->InitCheck() < B_OK((int)0) |
442 | || inode->Name() == NULL__null |
443 | || !*inode->Name()) { |
444 | BString sub; |
445 | sub << "__recovered " << parent.allocation_group << ":" |
446 | << (int32)parent.start << "/"; |
447 | path.Prepend(sub); |
448 | |
449 | delete inode; |
450 | break; |
451 | } |
452 | parent = inode->Parent(); |
453 | path.Prepend("/"); |
454 | path.Prepend(inode->Name()); |
455 | |
456 | delete inode; |
457 | } |
458 | fPath = strdup(path.String()); |
459 | |
460 | return B_OK((int)0); |
461 | } |
462 | |
463 | |
464 | const char * |
465 | Inode::Path(Inode::Source *source) |
466 | { |
467 | if (fPath == NULL__null) |
468 | _FindPath(source); |
469 | |
470 | return fPath; |
471 | } |
472 | |
473 | |
474 | status_t |
475 | Inode::CopyTo(const char *root, bool fullPath, Inode::Source *source) |
476 | { |
477 | if (root == NULL__null) |
478 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); |
479 | |
480 | BString path; |
481 | |
482 | if (fullPath) |
483 | path.Append(Path(source)); |
484 | |
485 | if (*(root + strlen(root) - 1) != '/') |
486 | path.Prepend("/"); |
487 | path.Prepend(root); |
488 | |
489 | return create_directory(path.String(), 0777); |
490 | } |
491 | |
492 | |
493 | status_t |
494 | Inode::CopyAttributesTo(BNode *node) |
495 | { |
496 | |
497 | |
498 | RewindAttributes(); |
499 | |
500 | char name[B_FILE_NAME_LENGTH(256)]; |
501 | const uint32 kMaxBrokenAttributes = 64; |
502 | |
503 | uint32 count = 0; |
504 | uint32 type; |
505 | void *data; |
506 | size_t size; |
507 | |
508 | status_t status; |
509 | while ((status = GetNextAttribute(name, &type, &data, &size)) |
510 | != B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3)) { |
511 | if (status != B_OK((int)0)) { |
512 | printf("could not open attribute (possibly: %s): %s!\n", |
513 | name, strerror(status)); |
514 | if (count++ > kMaxBrokenAttributes) |
515 | break; |
516 | |
517 | continue; |
518 | } |
519 | |
520 | ssize_t written = node->WriteAttr(name, type, 0, data, size); |
521 | if (written < B_OK((int)0)) { |
522 | printf("could not write attribute \"%s\": %s\n", name, |
523 | strerror(written)); |
524 | } else if ((size_t)written < size) { |
525 | printf("could only write %ld bytes (from %ld) at attribute \"%s\"\n", |
526 | written, size, name); |
527 | } |
528 | } |
529 | |
530 | |
531 | |
532 | node->SetPermissions(fInode->mode); |
533 | node->SetOwner(fInode->uid); |
534 | node->SetGroup(fInode->gid); |
535 | node->SetModificationTime(fInode->last_modified_time >> 16); |
536 | node->SetCreationTime(fInode->create_time >> 16); |
537 | |
538 | return B_OK((int)0); |
539 | } |
540 | |
541 | |
542 | Inode * |
543 | Inode::Factory(Disk *disk, bfs_inode *inode, bool ownBuffer) |
544 | { |
545 | |
546 | if ((inode->mode & (S_ATTR02000000000 | S_ATTR_DIR01000000000)) == S_ATTR02000000000) |
547 | return new Attribute(disk, inode, ownBuffer); |
548 | |
549 | |
550 | if (S_ISDIR(inode->mode)(((inode->mode) & 00000170000) == 00000040000) || inode->mode & S_ATTR_DIR01000000000) |
551 | return new Directory(disk, inode, ownBuffer); |
552 | |
553 | |
554 | if (S_ISREG(inode->mode)(((inode->mode) & 00000170000) == 00000100000)) |
555 | return new File(disk, inode, ownBuffer); |
556 | |
557 | |
558 | if (S_ISLNK(inode->mode)(((inode->mode) & 00000170000) == 00000120000)) |
559 | return new Symlink(disk, inode, ownBuffer); |
560 | |
561 | return NULL__null; |
562 | } |
563 | |
564 | |
565 | Inode * |
566 | Inode::Factory(Disk *disk, block_run run) |
567 | { |
568 | bfs_inode *inode = (bfs_inode *)malloc(disk->BlockSize()); |
569 | if (!inode) |
570 | return NULL__null; |
571 | |
572 | if (disk->ReadAt(disk->ToOffset(run), inode, disk->BlockSize()) <= 0) |
573 | return NULL__null; |
574 | |
575 | Inode *object = Factory(disk, inode); |
576 | if (object == NULL__null) |
577 | free(inode); |
578 | |
579 | return object; |
580 | } |
581 | |
582 | |
583 | Inode * |
584 | Inode::Factory(Disk *disk, Inode *inode, bool copyBuffer) |
585 | { |
586 | bfs_inode *inodeBuffer = inode->fInode; |
587 | |
588 | if (copyBuffer) { |
589 | bfs_inode *inodeCopy = (bfs_inode *)malloc(inodeBuffer->inode_size); |
590 | if (!inodeCopy) |
591 | return NULL__null; |
592 | |
593 | memcpy(inodeCopy, inodeBuffer, inodeBuffer->inode_size); |
594 | inodeBuffer = inodeCopy; |
595 | } |
596 | return Factory(disk, inodeBuffer, copyBuffer); |
597 | } |
598 | |
599 | |
600 | Inode * |
601 | Inode::EmptyInode(Disk *disk, const char *name, int32 mode) |
602 | { |
603 | bfs_inode *inode = (bfs_inode *)malloc(disk->BlockSize()); |
604 | if (!inode) |
| 1 | Assuming 'inode' is non-null | |
|
| |
605 | return NULL__null; |
606 | |
607 | memset(inode, 0, sizeof(bfs_inode)); |
608 | |
609 | inode->magic1 = INODE_MAGIC10x3bbe0ad9; |
610 | inode->inode_size = disk->BlockSize(); |
611 | inode->mode = mode; |
612 | inode->flags = INODE_IN_USE | (mode & S_IFDIR00000040000 ? INODE_LOGGED : 0); |
| |
613 | |
614 | if (name) { |
| |
| |
615 | small_data *data = inode->small_data_start; |
616 | data->type = FILE_NAME_TYPE'CSTR'; |
617 | data->name_size = FILE_NAME_NAME_LENGTH1; |
618 | *data->Name() = FILE_NAME_NAME0x13; |
619 | data->data_size = strlen(name); |
620 | strcpy((char *)data->Data(), name); |
621 | } |
622 | |
623 | Inode *object = new (std::nothrow) Inode(disk, inode); |
| 6 | | 'object' initialized here | |
|
624 | if (object == NULL__null) |
| 7 | | Assuming pointer value is null | |
|
| |
625 | free(inode); |
626 | |
627 | object->AcquireBuffer(); |
| 9 | | Called C++ object pointer is null |
|
628 | |
629 | return object; |
630 | } |
631 | |
632 | |
633 | |
634 | |
635 | |
636 | DataStream::DataStream(Disk *disk, bfs_inode *inode, bool ownBuffer) |
637 | : Inode(disk,inode,ownBuffer), |
638 | fCurrent(-1), |
639 | fPosition(0LL) |
640 | { |
641 | } |
642 | |
643 | |
644 | DataStream::DataStream(const Inode &inode) |
645 | : Inode(inode), |
646 | fCurrent(-1), |
647 | fPosition(0LL) |
648 | { |
649 | } |
650 | |
651 | |
652 | DataStream::~DataStream() |
653 | { |
654 | } |
655 | |
656 | |
657 | status_t |
658 | DataStream::FindBlockRun(off_t pos) |
659 | { |
660 | NodeGetter _(this); |
661 | |
662 | if (pos > fInode->data.size) |
663 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); |
664 | |
665 | if (fCurrent < 0) |
666 | fLevel = 0; |
667 | |
668 | fRunBlockEnd = fCurrent >= 0 |
669 | ? fRunFileOffset + (fRun.length << fDisk->BlockShift()) : 0LL; |
670 | |
671 | |
672 | |
673 | if (fCurrent >= 0 && pos >= fRunFileOffset && pos < fRunBlockEnd) |
674 | return B_OK((int)0); |
675 | |
676 | |
677 | |
678 | if (fInode->data.max_direct_range > 0 |
679 | && pos >= fInode->data.max_direct_range) { |
680 | if (fInode->data.max_double_indirect_range > 0 |
681 | && pos >= fInode->data.max_indirect_range) { |
682 | |
683 | |
684 | |
685 | block_run *indirect = (block_run *)fDisk->ReadBlockRun(fInode->data.double_indirect); |
686 | if (indirect == NULL__null) |
687 | return B_ERROR(-1); |
688 | |
689 | off_t start = pos - fInode->data.max_indirect_range; |
690 | int32 indirectSize = fDisk->BlockSize() * 16 * (fDisk->BlockSize() / sizeof(block_run)); |
691 | int32 directSize = fDisk->BlockSize() * 4; |
692 | int32 index = start / indirectSize; |
693 | |
694 | |
695 | |
696 | indirect = (block_run *)fDisk->ReadBlockRun(indirect[index]); |
697 | if (indirect == NULL__null) |
698 | return B_ERROR(-1); |
699 | |
700 | fCurrent = (start % indirectSize) / directSize; |
701 | fRunFileOffset = fInode->data.max_indirect_range + (index * indirectSize) + (fCurrent * directSize); |
702 | fRunBlockEnd = fRunFileOffset + directSize; |
703 | fRun = indirect[fCurrent]; |
704 | |
705 | } else { |
706 | |
707 | |
708 | block_run *indirect = (block_run *)fDisk->ReadBlockRun(fInode->data.indirect); |
709 | if (!indirect) |
710 | return B_ERROR(-1); |
711 | |
712 | int32 indirectRuns = (fInode->data.indirect.length << fDisk->BlockShift()) / sizeof(block_run); |
713 | |
714 | if (fLevel != 1 || pos < fRunFileOffset) { |
715 | fRunBlockEnd = fInode->data.max_direct_range; |
716 | fCurrent = -1; |
717 | fLevel = 1; |
718 | } |
719 | |
720 | while (++fCurrent < indirectRuns) { |
721 | if (indirect[fCurrent].IsZero()) |
722 | break; |
723 | |
724 | fRunFileOffset = fRunBlockEnd; |
725 | fRunBlockEnd += indirect[fCurrent].length << fDisk->BlockShift(); |
726 | if (fRunBlockEnd > pos) |
727 | break; |
728 | } |
729 | if (fCurrent == indirectRuns || indirect[fCurrent].IsZero()) |
730 | return B_ERROR(-1); |
731 | |
732 | fRun = indirect[fCurrent]; |
733 | |
734 | |
735 | } |
736 | } else { |
737 | |
738 | if (fRunFileOffset > pos) { |
739 | fRunBlockEnd = 0LL; |
740 | fCurrent = -1; |
741 | } |
742 | fLevel = 0; |
743 | |
744 | while (++fCurrent < NUM_DIRECT_BLOCKS12) { |
745 | if (fInode->data.direct[fCurrent].IsZero()) |
746 | break; |
747 | |
748 | fRunFileOffset = fRunBlockEnd; |
749 | fRunBlockEnd += fInode->data.direct[fCurrent].length << fDisk->BlockShift(); |
750 | if (fRunBlockEnd > pos) |
751 | break; |
752 | } |
753 | if (fCurrent == NUM_DIRECT_BLOCKS12 || fInode->data.direct[fCurrent].IsZero()) |
754 | return B_ERROR(-1); |
755 | |
756 | fRun = fInode->data.direct[fCurrent]; |
757 | |
758 | } |
759 | return B_OK((int)0); |
760 | } |
761 | |
762 | |
763 | ssize_t |
764 | DataStream::ReadAt(off_t pos, void *buffer, size_t size) |
765 | { |
766 | NodeGetter _(this); |
767 | |
768 | |
769 | |
770 | if (pos + (off_t)size > fInode->data.size) { |
771 | if (pos > fInode->data.size) |
772 | return B_ERROR(-1); |
773 | |
774 | size = fInode->data.size - pos; |
775 | if (!size) |
776 | return 0; |
777 | } |
778 | ssize_t read = 0; |
779 | |
780 | |
781 | while (size > 0) { |
782 | status_t status = FindBlockRun(pos); |
783 | if (status < B_OK((int)0)) |
784 | return status; |
785 | |
786 | ssize_t bytes = min_c((off_t)size, fRunBlockEnd - pos)(((off_t)size)>(fRunBlockEnd - pos)?(fRunBlockEnd - pos):( (off_t)size)); |
787 | |
788 | |
789 | bytes = fDisk->ReadAt(fDisk->ToOffset(fRun) + pos - fRunFileOffset, |
790 | buffer, bytes); |
791 | if (bytes <= 0) { |
792 | if (bytes == 0) { |
793 | printf("could not read bytes at: %" B_PRId32"l" "d" ",%d\n", |
794 | fRun.allocation_group, fRun.start); |
795 | } |
796 | return bytes < 0 ? bytes : B_BAD_DATA((-2147483647 - 1) + 16); |
797 | } |
798 | |
799 | buffer = (void *)((uint8 *)buffer + bytes); |
800 | size -= bytes; |
801 | pos += bytes; |
802 | read += bytes; |
803 | } |
804 | if (read >= 0) |
805 | return read; |
806 | |
807 | return B_IO_ERROR((-2147483647 - 1) + 1); |
808 | } |
809 | |
810 | |
811 | ssize_t |
812 | DataStream::WriteAt(off_t pos, const void *buffer, size_t size) |
813 | { |
814 | NodeGetter _(this); |
815 | |
816 | |
817 | if (pos + (off_t)size > fInode->data.size) { |
818 | if (pos > fInode->data.size) |
819 | return B_ERROR(-1); |
820 | |
821 | size = fInode->data.size - pos; |
822 | if (!size) |
823 | return 0; |
824 | } |
825 | ssize_t written = 0; |
826 | |
827 | |
828 | while (size > 0) { |
829 | status_t status = FindBlockRun(pos); |
830 | if (status < B_OK((int)0)) |
831 | return status; |
832 | |
833 | ssize_t bytes = min_c((off_t)size, fRunBlockEnd - pos)(((off_t)size)>(fRunBlockEnd - pos)?(fRunBlockEnd - pos):( (off_t)size)); |
834 | |
835 | |
836 | bytes = fDisk->WriteAt(fDisk->ToOffset(fRun) + pos - fRunFileOffset,buffer,bytes); |
837 | if (bytes < 0) |
838 | return bytes; |
839 | |
840 | buffer = (void *)((uint8 *)buffer + bytes); |
841 | size -= bytes; |
842 | pos += bytes; |
843 | written += bytes; |
844 | } |
845 | if (written >= 0) |
846 | return written; |
847 | |
848 | return B_IO_ERROR((-2147483647 - 1) + 1); |
849 | } |
850 | |
851 | |
852 | off_t |
853 | DataStream::Seek(off_t position, uint32 seekMode) |
854 | { |
855 | NodeGetter _(this); |
856 | |
857 | if (seekMode == SEEK_SET0) |
858 | fPosition = position; |
859 | else if (seekMode == SEEK_END2) |
860 | fPosition = fInode->data.size + position; |
861 | else |
862 | fPosition += position; |
863 | |
864 | return fPosition; |
865 | } |
866 | |
867 | |
868 | off_t |
869 | DataStream::Position() const |
870 | { |
871 | return fPosition; |
872 | } |
873 | |
874 | |
875 | status_t |
876 | DataStream::SetSize(off_t size) |
877 | { |
878 | NodeGetter _(this); |
879 | |
880 | |
881 | if (size > fInode->data.size || size > fInode->data.max_direct_range) |
882 | return B_ERROR(-1); |
883 | |
884 | if (size == fInode->data.size) |
885 | return B_OK((int)0); |
886 | |
887 | BufferClobbered(); |
888 | |
889 | fInode->data.size = size; |
890 | fInode->data.max_direct_range = size; |
891 | fInode->data.max_indirect_range = 0; |
892 | fInode->data.max_double_indirect_range = 0; |
893 | |
894 | for (int32 i = 0;i < NUM_DIRECT_BLOCKS12;i++) { |
895 | if (size <= 0) |
896 | fInode->data.direct[i].SetTo(0, 0, 0); |
897 | else if ((fInode->data.direct[i].length << fDisk->BlockShift()) >= size) { |
898 | off_t blocks = (size + fDisk->BlockSize() - 1) / fDisk->BlockSize(); |
899 | fInode->data.direct[i].length = blocks; |
900 | size = 0; |
901 | } else |
902 | size -= fInode->data.direct[i].length << fDisk->BlockShift(); |
903 | } |
904 | |
905 | return B_OK((int)0); |
906 | } |
907 | |
908 | |
909 | |
910 | |
911 | |
912 | File::File(Disk *disk, bfs_inode *inode,bool ownBuffer) |
913 | : DataStream(disk,inode,ownBuffer) |
914 | { |
915 | } |
916 | |
917 | |
918 | File::File(const Inode &inode) |
919 | : DataStream(inode) |
920 | { |
921 | } |
922 | |
923 | |
924 | File::~File() |
925 | { |
926 | } |
927 | |
928 | |
929 | status_t |
930 | File::InitCheck() |
931 | { |
932 | status_t status = DataStream::InitCheck(); |
933 | if (status == B_OK((int)0)) |
934 | return IsFile() ? B_OK((int)0) : B_ERROR(-1); |
935 | |
936 | return status; |
937 | } |
938 | |
939 | |
940 | status_t |
941 | File::CopyTo(const char *root, bool fullPath, Inode::Source *source) |
942 | { |
943 | status_t status = Inode::CopyTo(root, fullPath, source); |
944 | if (status < B_OK((int)0)) |
945 | return status; |
946 | |
947 | BPath path(root); |
948 | if (fullPath && Path(source)) |
949 | path.Append(Path(source)); |
950 | |
951 | char *name = (char *)Name(); |
952 | if (name != NULL__null) { |
953 | |
954 | if (!*name) |
955 | *name = '_'; |
956 | path.Append(name); |
957 | } else { |
958 | BString sub; |
959 | sub << "__untitled " << BlockRun().allocation_group << ":" |
960 | << (int32)BlockRun().start; |
961 | path.Append(sub.String()); |
962 | } |
963 | printf("%" B_PRId32"l" "d" ",%d -> %s\n", BlockRun().allocation_group, |
964 | BlockRun().start, path.Path()); |
965 | |
966 | BFile file; |
967 | status = file.SetTo(path.Path(), |
968 | B_WRITE_ONLY0x0001 | B_CREATE_FILE0x0200 | B_FAIL_IF_EXISTS0x0100); |
969 | if (status < B_OK((int)0)) |
970 | return status; |
971 | |
972 | char buffer[fDisk->BlockSize()]; |
973 | ssize_t size; |
974 | Seek(0, SEEK_SET0); |
975 | |
976 | while ((size = Read(buffer, sizeof(buffer))) > B_OK((int)0)) { |
977 | ssize_t written = file.Write(buffer, size); |
978 | if (written < B_OK((int)0)) |
979 | return written; |
980 | } |
981 | |
982 | return CopyAttributesTo(&file); |
983 | } |
984 | |
985 | |
986 | |
987 | |
988 | |
989 | Attribute::Attribute(Disk *disk, bfs_inode *inode, bool ownBuffer) |
990 | : File(disk, inode, ownBuffer) |
991 | { |
992 | } |
993 | |
994 | |
995 | Attribute::Attribute(const Inode &inode) |
996 | : File(inode) |
997 | { |
998 | } |
999 | |
1000 | |
1001 | Attribute::~Attribute() |
1002 | { |
1003 | } |
1004 | |
1005 | |
1006 | status_t |
1007 | Attribute::InitCheck() |
1008 | { |
1009 | status_t status = DataStream::InitCheck(); |
1010 | if (status == B_OK((int)0)) |
1011 | return IsAttribute() ? B_OK((int)0) : B_ERROR(-1); |
1012 | |
1013 | return status; |
1014 | } |
1015 | |
1016 | |
1017 | status_t |
1018 | Attribute::CopyTo(const char *, bool , |
1019 | Inode::Source *) |
1020 | { |
1021 | |
1022 | |
1023 | |
1024 | |
1025 | |
1026 | return B_OK((int)0); |
1027 | } |
1028 | |
1029 | |
1030 | |
1031 | |
1032 | |
1033 | Directory::Directory(Disk *disk, bfs_inode *inode, bool ownBuffer) |
1034 | : DataStream(disk, inode, ownBuffer), |
1035 | fTree(NULL__null) |
1036 | { |
1037 | } |
1038 | |
1039 | |
1040 | Directory::Directory(const Inode &inode) |
1041 | : DataStream(inode), |
1042 | fTree(NULL__null) |
1043 | { |
1044 | } |
1045 | |
1046 | |
1047 | Directory::~Directory() |
1048 | { |
1049 | delete fTree; |
1050 | } |
1051 | |
1052 | |
1053 | status_t |
1054 | Directory::InitCheck() |
1055 | { |
1056 | status_t status = DataStream::InitCheck(); |
1057 | if (status == B_OK((int)0)) |
1058 | return (IsDirectory() || IsAttributeDirectory()) ? B_OK((int)0) : B_ERROR(-1); |
1059 | |
1060 | return status; |
1061 | } |
1062 | |
1063 | |
1064 | status_t |
1065 | Directory::CopyTo(const char *root, bool fullPath, Inode::Source *source) |
1066 | { |
1067 | |
1068 | |
1069 | if (IsAttributeDirectory() || IsIndex()) |
1070 | return B_OK((int)0); |
1071 | |
1072 | status_t status = Inode::CopyTo(root, fullPath, source); |
1073 | if (status < B_OK((int)0)) |
1074 | return status; |
1075 | |
1076 | BPath path(root); |
1077 | if (fullPath && Path(source)) |
1078 | path.Append(Path(source)); |
1079 | |
1080 | char *name = (char *)Name(); |
1081 | if (name != NULL__null) { |
1082 | |
1083 | if (!*name) |
1084 | *name = '_'; |
1085 | path.Append(name); |
1086 | } else { |
1087 | |
1088 | BString sub; |
1089 | sub << "__untitled " << BlockRun().allocation_group << ":" |
1090 | << (int32)BlockRun().start; |
1091 | path.Append(sub.String()); |
1092 | } |
1093 | |
1094 | BEntry entry(path.Path()); |
1095 | BDirectory directory; |
1096 | if ((status = entry.GetParent(&directory)) < B_OK((int)0)) |
1097 | return status; |
1098 | |
1099 | status = directory.CreateDirectory(path.Leaf(), NULL__null); |
1100 | if (status < B_OK((int)0) && status != B_FILE_EXISTS(((-2147483647 - 1) + 0x6000) + 2)) |
1101 | return status; |
1102 | |
1103 | if ((status = directory.SetTo(&entry)) < B_OK((int)0)) |
1104 | return status; |
1105 | |
1106 | return CopyAttributesTo(&directory); |
1107 | } |
1108 | |
1109 | |
1110 | status_t |
1111 | Directory::Rewind() |
1112 | { |
1113 | if (!fTree) { |
1114 | status_t status = CreateTree(); |
1115 | if (status < B_OK((int)0)) |
1116 | return status; |
1117 | } |
1118 | return fTree->Rewind(); |
1119 | } |
1120 | |
1121 | |
1122 | status_t |
1123 | Directory::GetNextEntry(char *name, block_run *run) |
1124 | { |
1125 | status_t status; |
1126 | |
1127 | if (!fTree) { |
1128 | if ((status = Rewind()) < B_OK((int)0)) |
1129 | return status; |
1130 | } |
1131 | uint16 length; |
1132 | off_t offset; |
1133 | |
1134 | if ((status = fTree->GetNextEntry(name, &length, B_FILE_NAME_LENGTH(256) - 1, |
1135 | &offset)) < B_OK((int)0)) |
1136 | return status; |
1137 | |
1138 | *run = fDisk->ToBlockRun(offset); |
1139 | |
1140 | return B_OK((int)0); |
1141 | } |
1142 | |
1143 | |
1144 | status_t |
1145 | Directory::GetNextEntry(block_run *run) |
1146 | { |
1147 | char name[B_FILE_NAME_LENGTH(256)]; |
1148 | |
1149 | return GetNextEntry(name, run); |
1150 | } |
1151 | |
1152 | |
1153 | status_t |
1154 | Directory::Contains(const block_run *run) |
1155 | { |
1156 | status_t status; |
1157 | |
1158 | if (!fTree) { |
1159 | if ((status = Rewind()) < B_OK((int)0)) |
1160 | return status; |
1161 | } |
1162 | |
1163 | block_run searchRun; |
1164 | while (GetNextEntry(&searchRun) == B_OK((int)0)) { |
1165 | if (searchRun == *run) |
1166 | return B_OK((int)0); |
1167 | } |
1168 | |
1169 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); |
1170 | } |
1171 | |
1172 | |
1173 | status_t |
1174 | Directory::Contains(const Inode *inode) |
1175 | { |
1176 | status_t status; |
1177 | |
1178 | if (!fTree) { |
1179 | if ((status = CreateTree()) < B_OK((int)0)) |
1180 | return status; |
1181 | } |
1182 | |
1183 | off_t value; |
1184 | const char *name = inode->Name(); |
1185 | status = B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); |
1186 | |
1187 | if (name && (status = fTree->Find((uint8 *)name, (uint16)strlen(name), |
1188 | &value)) == B_OK((int)0)) { |
1189 | if (fDisk->ToBlockRun(value) == inode->InodeBuffer()->inode_num) |
1190 | return B_OK((int)0); |
1191 | |
1192 | printf("inode address do not match (%s)!\n", inode->Name()); |
1193 | } |
1194 | |
1195 | if (status != B_OK((int)0) && status != B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3)) |
1196 | return status; |
1197 | |
1198 | return Contains(&inode->InodeBuffer()->inode_num); |
1199 | } |
1200 | |
1201 | |
1202 | status_t |
1203 | Directory::FindEntry(const char *name, block_run *run) |
1204 | { |
1205 | status_t status; |
1206 | |
1207 | if (!name) |
1208 | return B_BAD_VALUE((-2147483647 - 1) + 5); |
1209 | |
1210 | if (!fTree) { |
1211 | if ((status = CreateTree()) < B_OK((int)0)) |
1212 | return status; |
1213 | } |
1214 | |
1215 | off_t value; |
1216 | |
1217 | if ((status = fTree->Find((uint8 *)name, (uint16)strlen(name), |
1218 | &value)) >= B_OK((int)0)) { |
1219 | if (run) |
1220 | *run = fDisk->ToBlockRun(value); |
1221 | return B_OK((int)0); |
1222 | } |
1223 | return status; |
1224 | } |
1225 | |
1226 | |
1227 | status_t |
1228 | Directory::AddEntry(Inode *inode) |
1229 | { |
1230 | status_t status; |
1231 | bool created = false; |
1232 | |
1233 | if (!fTree) { |
1234 | status = CreateTree(); |
1235 | if (status == B_OK((int)0)) |
1236 | status = fTree->Validate(); |
1237 | |
1238 | if (status == B_BAD_DATA((-2147483647 - 1) + 16)) { |
1239 | |
1240 | fTree = new BPlusTree(BPLUSTREE_STRING_TYPE, BPLUSTREE_NODE_SIZE1024, |
1241 | false); |
1242 | if ((status = fTree->InitCheck()) < B_OK((int)0)) { |
1243 | delete fTree; |
1244 | fTree = NULL__null; |
1245 | } else |
1246 | created = true; |
1247 | } |
1248 | |
1249 | if (status < B_OK((int)0)) |
1250 | return status; |
1251 | } |
1252 | |
1253 | fTree->SetHoldChanges(true); |
1254 | |
1255 | if (created) { |
1256 | |
1257 | fTree->Insert(".", Block()); |
1258 | fTree->Insert("..", fDisk->ToBlock(Parent())); |
1259 | } |
1260 | |
1261 | if (inode->Flags() & INODE_DELETED) |
1262 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); |
1263 | |
1264 | BString name = inode->Name(); |
1265 | if (name == "") { |
1266 | name << "__file " << inode->BlockRun().allocation_group << ":" |
1267 | << (int32)inode->BlockRun().start; |
1268 | } |
1269 | |
1270 | return fTree->Insert(name.String(), inode->Block()); |
1271 | } |
1272 | |
1273 | |
1274 | status_t |
1275 | Directory::CreateTree() |
1276 | { |
1277 | fTree = new BPlusTree(this); |
1278 | |
1279 | status_t status = fTree->InitCheck(); |
1280 | if (status < B_OK((int)0)) { |
1281 | delete fTree; |
1282 | fTree = NULL__null; |
1283 | return status; |
1284 | } |
1285 | return B_OK((int)0); |
1286 | } |
1287 | |
1288 | |
1289 | status_t |
1290 | Directory::GetTree(BPlusTree **tree) |
1291 | { |
1292 | if (!fTree) { |
1293 | status_t status = CreateTree(); |
1294 | if (status < B_OK((int)0)) |
1295 | return status; |
1296 | } |
1297 | *tree = fTree; |
1298 | return B_OK((int)0); |
1299 | } |
1300 | |
1301 | |
1302 | |
1303 | |
1304 | |
1305 | Symlink::Symlink(Disk *disk, bfs_inode *inode,bool ownBuffer) |
1306 | : Inode(disk,inode,ownBuffer) |
1307 | { |
1308 | } |
1309 | |
1310 | |
1311 | Symlink::Symlink(const Inode &inode) |
1312 | : Inode(inode) |
1313 | { |
1314 | } |
1315 | |
1316 | |
1317 | Symlink::~Symlink() |
1318 | { |
1319 | } |
1320 | |
1321 | |
1322 | status_t |
1323 | Symlink::InitCheck() |
1324 | { |
1325 | status_t status = Inode::InitCheck(); |
1326 | if (status == B_OK((int)0)) |
1327 | return IsSymlink() ? B_OK((int)0) : B_ERROR(-1); |
1328 | |
1329 | return status; |
1330 | } |
1331 | |
1332 | |
1333 | status_t |
1334 | Symlink::CopyTo(const char *root, bool fullPath,Inode::Source *source) |
1335 | { |
1336 | status_t status = Inode::CopyTo(root,fullPath,source); |
1337 | if (status < B_OK((int)0)) |
1338 | return status; |
1339 | |
1340 | BPath path(root); |
1341 | if (fullPath && Path(source)) |
1342 | path.Append(Path(source)); |
1343 | |
1344 | char *name = (char *)Name(); |
1345 | if (name != NULL__null) { |
1346 | |
1347 | if (!*name) |
1348 | *name = '_'; |
1349 | path.Append(name); |
1350 | } else { |
1351 | |
1352 | BString sub; |
1353 | sub << "__symlink " << BlockRun().allocation_group << ":" |
1354 | << (int32)BlockRun().start; |
1355 | path.Append(sub.String()); |
1356 | } |
1357 | |
1358 | BEntry entry(path.Path()); |
1359 | BDirectory directory; |
1360 | if ((status = entry.GetParent(&directory)) < B_OK((int)0)) |
1361 | return status; |
1362 | |
1363 | char to[2048]; |
1364 | if (LinksTo(to,sizeof(to)) < B_OK((int)0)) |
1365 | return B_ERROR(-1); |
1366 | |
1367 | BSymLink link; |
1368 | status = directory.CreateSymLink(path.Leaf(),to,&link); |
1369 | if (status < B_OK((int)0) && status != B_FILE_EXISTS(((-2147483647 - 1) + 0x6000) + 2)) |
1370 | return status; |
1371 | |
1372 | if ((status = link.SetTo(&entry)) < B_OK((int)0)) |
1373 | return status; |
1374 | |
1375 | return CopyAttributesTo(&link); |
1376 | } |
1377 | |
1378 | |
1379 | status_t |
1380 | Symlink::LinksTo(char *to,size_t maxLength) |
1381 | { |
1382 | if ((fInode->flags & INODE_LONG_SYMLINK) == 0) { |
1383 | strcpy(to,fInode->short_symlink); |
1384 | return B_OK((int)0); |
1385 | } |
1386 | |
1387 | DataStream stream(*this); |
1388 | status_t status = stream.InitCheck(); |
1389 | if (status < B_OK((int)0)) |
1390 | return status; |
1391 | |
1392 | status = stream.Read(to,maxLength); |
1393 | |
1394 | return status < B_OK((int)0) ? status : B_OK((int)0); |
1395 | } |
1396 | |