2 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>.
3 * Copyright 2005-2008, Jérôme DUVAL.
4 * All rights reserved. Distributed under the terms of the MIT License.
7 #include "WorkerThread.h"
19 #include <Directory.h>
20 #include <DiskDeviceVisitor.h>
21 #include <DiskDeviceTypes.h>
22 #include <FindDirectory.h>
28 #include <Messenger.h>
31 #include <VolumeRoster.h>
33 #include "AutoLocker.h"
34 #include "CopyEngine.h"
35 #include "InstallerDefs.h"
36 #include "PackageViews.h"
37 #include "PartitionMenuItem.h"
38 #include "ProgressReporter.h"
39 #include "StringForSize.h"
40 #include "UnzipEngine.h"
43 #define B_TRANSLATION_CONTEXT "InstallProgress"
48 #define CALLED() printf("CALLED %s\n",__PRETTY_FUNCTION__)
49 #define ERR2(x, y...) fprintf(stderr, "WorkerThread: "x" %s\n", y, strerror(err))
50 #define ERR(x) fprintf(stderr, "WorkerThread: "x" %s\n", strerror(err))
57 const char BOOT_PATH
[] = "/boot";
59 const uint32 MSG_START_INSTALLING
= 'eSRT';
62 class SourceVisitor
: public BDiskDeviceVisitor
{
64 SourceVisitor(BMenu
* menu
);
65 virtual bool Visit(BDiskDevice
* device
);
66 virtual bool Visit(BPartition
* partition
, int32 level
);
73 class TargetVisitor
: public BDiskDeviceVisitor
{
75 TargetVisitor(BMenu
* menu
);
76 virtual bool Visit(BDiskDevice
* device
);
77 virtual bool Visit(BPartition
* partition
, int32 level
);
84 // #pragma mark - WorkerThread
87 class WorkerThread::EntryFilter
: public CopyEngine::EntryFilter
{
89 EntryFilter(const char* sourceDirectory
)
95 fIgnorePaths
.insert(kPackagesDirectoryPath
);
96 fIgnorePaths
.insert(kSourcesDirectoryPath
);
97 fIgnorePaths
.insert("rr_moved");
98 fIgnorePaths
.insert("boot.catalog");
99 fIgnorePaths
.insert("haiku-boot-floppy.image");
100 fIgnorePaths
.insert("system/var/swap");
101 fIgnorePaths
.insert("system/var/shared_memory");
103 fPackageFSRootPaths
.insert("system");
104 fPackageFSRootPaths
.insert("home/config");
105 } catch (std::bad_alloc
&) {
109 if (stat(sourceDirectory
, &st
) == 0)
110 fSourceDevice
= st
.st_dev
;
113 virtual bool ShouldCopyEntry(const BEntry
& entry
, const char* path
,
114 const struct stat
& statInfo
, int32 level
) const
116 if (fIgnorePaths
.find(path
) != fIgnorePaths
.end()) {
117 printf("ignoring '%s'.\n", path
);
121 if (statInfo
.st_dev
!= fSourceDevice
) {
122 // Allow that only for the root of the packagefs mounts, since
123 // those contain directories that shine through from the
124 // underlying volume.
125 if (fPackageFSRootPaths
.find(path
) == fPackageFSRootPaths
.end())
132 virtual bool ShouldClobberFolder(const BEntry
& entry
, const char* path
,
133 const struct stat
& statInfo
, int32 level
) const
135 if (level
== 2 && S_ISDIR(statInfo
.st_mode
)
136 && strncmp("system/", path
, 7) == 0
137 && strcmp("system/settings", path
) != 0) {
138 // Replace everything in "system" besides "settings"
139 printf("clobbering '%s'.\n", path
);
146 typedef std::set
<std::string
> StringSet
;
148 StringSet fIgnorePaths
;
149 StringSet fPackageFSRootPaths
;
154 // #pragma mark - WorkerThread
157 WorkerThread::WorkerThread(const BMessenger
& owner
)
159 BLooper("copy_engine"),
170 WorkerThread::MessageReceived(BMessage
* message
)
174 switch (message
->what
) {
175 case MSG_START_INSTALLING
:
176 _PerformInstall(message
->GetInt32("source", -1),
177 message
->GetInt32("target", -1));
180 case MSG_WRITE_BOOT_SECTOR
:
183 if (message
->FindInt32("id", &id
) != B_OK
) {
184 _SetStatusMessage(B_TRANSLATE("Boot sector not written "
185 "because of an internal error."));
189 // TODO: Refactor with _PerformInstall()
190 BPath targetDirectory
;
192 BPartition
* partition
;
194 if (fDDRoster
.GetPartitionWithID(id
, &device
, &partition
) == B_OK
) {
195 if (!partition
->IsMounted()) {
196 if (partition
->Mount() < B_OK
) {
197 _SetStatusMessage(B_TRANSLATE("The partition can't be "
198 "mounted. Please choose a different partition."));
202 if (partition
->GetMountPoint(&targetDirectory
) != B_OK
) {
203 _SetStatusMessage(B_TRANSLATE("The mount point could not "
207 } else if (fDDRoster
.GetDeviceWithID(id
, &device
) == B_OK
) {
208 if (!device
.IsMounted()) {
209 if (device
.Mount() < B_OK
) {
210 _SetStatusMessage(B_TRANSLATE("The disk can't be "
211 "mounted. Please choose a different disk."));
215 if (device
.GetMountPoint(&targetDirectory
) != B_OK
) {
216 _SetStatusMessage(B_TRANSLATE("The mount point could not "
222 _LaunchFinishScript(targetDirectory
);
223 // TODO: Get error from executing script!
225 B_TRANSLATE("Boot sector successfully written."));
228 BLooper::MessageReceived(message
);
236 WorkerThread::ScanDisksPartitions(BMenu
*srcMenu
, BMenu
*targetMenu
)
238 // NOTE: This is actually executed in the window thread.
240 BPartition
*partition
= NULL
;
242 printf("\nScanDisksPartitions source partitions begin\n");
243 SourceVisitor
srcVisitor(srcMenu
);
244 fDDRoster
.VisitEachMountedPartition(&srcVisitor
, &device
, &partition
);
246 printf("\nScanDisksPartitions target partitions begin\n");
247 TargetVisitor
targetVisitor(targetMenu
);
248 fDDRoster
.VisitEachPartition(&targetVisitor
, &device
, &partition
);
253 WorkerThread::SetPackagesList(BList
*list
)
255 // Executed in window thread.
264 WorkerThread::StartInstall(partition_id sourcePartitionID
,
265 partition_id targetPartitionID
)
267 // Executed in window thread.
268 BMessage
message(MSG_START_INSTALLING
);
269 message
.AddInt32("source", sourcePartitionID
);
270 message
.AddInt32("target", targetPartitionID
);
272 PostMessage(&message
, this);
277 WorkerThread::WriteBootSector(BMenu
* targetMenu
)
279 // Executed in window thread.
282 PartitionMenuItem
* item
= (PartitionMenuItem
*)targetMenu
->FindMarked();
284 ERR("bad menu items\n");
288 BMessage
message(MSG_WRITE_BOOT_SECTOR
);
289 message
.AddInt32("id", item
->ID());
290 PostMessage(&message
, this);
298 WorkerThread::_LaunchInitScript(BPath
&path
)
301 find_directory(B_BEOS_BOOT_DIRECTORY
, &bootPath
);
302 BString
command("/bin/sh ");
303 command
+= bootPath
.Path();
304 command
+= "/InstallerInitScript ";
306 command
+= path
.Path();
308 _SetStatusMessage(B_TRANSLATE("Starting Installation."));
309 system(command
.String());
314 WorkerThread::_LaunchFinishScript(BPath
&path
)
317 find_directory(B_BEOS_BOOT_DIRECTORY
, &bootPath
);
318 BString
command("/bin/sh ");
319 command
+= bootPath
.Path();
320 command
+= "/InstallerFinishScript ";
322 command
+= path
.Path();
324 _SetStatusMessage(B_TRANSLATE("Finishing Installation."));
325 system(command
.String());
330 WorkerThread::_PerformInstall(partition_id sourcePartitionID
,
331 partition_id targetPartitionID
)
335 BPath targetDirectory
;
339 BDirectory targetDir
;
341 BPartition
* partition
;
342 BVolume targetVolume
;
346 const char* mountError
= B_TRANSLATE("The disk can't be mounted. Please "
347 "choose a different disk.");
349 if (sourcePartitionID
< 0 || targetPartitionID
< 0) {
350 ERR("bad source or target partition ID\n");
351 return _InstallationError(err
);
354 // check if target is initialized
355 // ask if init or mount as is
356 if (fDDRoster
.GetPartitionWithID(targetPartitionID
, &device
,
357 &partition
) == B_OK
) {
358 if (!partition
->IsMounted()) {
359 if ((err
= partition
->Mount()) < B_OK
) {
360 _SetStatusMessage(mountError
);
361 ERR("BPartition::Mount");
362 return _InstallationError(err
);
365 if ((err
= partition
->GetVolume(&targetVolume
)) != B_OK
) {
366 ERR("BPartition::GetVolume");
367 return _InstallationError(err
);
369 if ((err
= partition
->GetMountPoint(&targetDirectory
)) != B_OK
) {
370 ERR("BPartition::GetMountPoint");
371 return _InstallationError(err
);
373 } else if (fDDRoster
.GetDeviceWithID(targetPartitionID
, &device
) == B_OK
) {
374 if (!device
.IsMounted()) {
375 if ((err
= device
.Mount()) < B_OK
) {
376 _SetStatusMessage(mountError
);
377 ERR("BDiskDevice::Mount");
378 return _InstallationError(err
);
381 if ((err
= device
.GetVolume(&targetVolume
)) != B_OK
) {
382 ERR("BDiskDevice::GetVolume");
383 return _InstallationError(err
);
385 if ((err
= device
.GetMountPoint(&targetDirectory
)) != B_OK
) {
386 ERR("BDiskDevice::GetMountPoint");
387 return _InstallationError(err
);
390 return _InstallationError(err
); // shouldn't happen
392 // check if target has enough space
393 if (fSpaceRequired
> 0 && targetVolume
.FreeBytes() < fSpaceRequired
) {
394 BAlert
* alert
= new BAlert("", B_TRANSLATE("The destination disk may "
395 "not have enough space. Try choosing a different disk or choose "
396 "to not install optional items."),
397 B_TRANSLATE("Try installing anyway"), B_TRANSLATE("Cancel"), 0,
398 B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
399 alert
->SetShortcut(1, B_ESCAPE
);
400 if (alert
->Go() != 0)
401 return _InstallationError(err
);
404 if (fDDRoster
.GetPartitionWithID(sourcePartitionID
, &device
, &partition
)
406 if ((err
= partition
->GetMountPoint(&srcDirectory
)) != B_OK
) {
407 ERR("BPartition::GetMountPoint");
408 return _InstallationError(err
);
410 } else if (fDDRoster
.GetDeviceWithID(sourcePartitionID
, &device
) == B_OK
) {
411 if ((err
= device
.GetMountPoint(&srcDirectory
)) != B_OK
) {
412 ERR("BDiskDevice::GetMountPoint");
413 return _InstallationError(err
);
416 return _InstallationError(err
); // shouldn't happen
418 // check not installing on itself
419 if (strcmp(srcDirectory
.Path(), targetDirectory
.Path()) == 0) {
420 _SetStatusMessage(B_TRANSLATE("You can't install the contents of a "
421 "disk onto itself. Please choose a different disk."));
422 return _InstallationError(err
);
425 // check not installing on boot volume
426 if (strncmp(BOOT_PATH
, targetDirectory
.Path(), strlen(BOOT_PATH
)) == 0) {
427 BAlert
* alert
= new BAlert("", B_TRANSLATE("Are you sure you want to "
428 "install onto the current boot disk? The Installer will have to "
429 "reboot your machine if you proceed."), B_TRANSLATE("OK"),
430 B_TRANSLATE("Cancel"), 0, B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
431 alert
->SetShortcut(1, B_ESCAPE
);
432 if (alert
->Go() != 0) {
433 _SetStatusMessage("Installation stopped.");
434 return _InstallationError(err
);
438 // check if target volume's trash dir has anything in it
439 // (target volume w/ only an empty trash dir is considered
441 if (find_directory(B_TRASH_DIRECTORY
, &trashPath
, false,
442 &targetVolume
) == B_OK
&& targetDir
.SetTo(trashPath
.Path()) == B_OK
) {
443 while (targetDir
.GetNextRef(&testRef
) == B_OK
) {
444 // Something in the Trash
450 targetDir
.SetTo(targetDirectory
.Path());
452 // check if target volume otherwise has any entries
453 while (entries
== 0 && targetDir
.GetNextRef(&testRef
) == B_OK
) {
454 if (testPath
.SetTo(&testRef
) == B_OK
&& testPath
!= trashPath
)
459 BAlert
* alert
= new BAlert("", B_TRANSLATE("The target volume is not "
460 "empty. Are you sure you want to install anyway?\n\nNote: The "
461 "'system' folder will be a clean copy from the source volume but "
462 "will retain its settings folder, all other folders will be "
463 "merged, whereas files and links that exist on both the source "
464 "and target volume will be overwritten with the source volume "
466 B_TRANSLATE("Install anyway"), B_TRANSLATE("Cancel"), 0,
467 B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
468 alert
->SetShortcut(1, B_ESCAPE
);
469 if (alert
->Go() != 0) {
470 // TODO: Would be cool to offer the option here to clean additional
471 // folders at the user's choice.
472 return _InstallationError(B_CANCELED
);
476 // Begin actual installation
478 ProgressReporter
reporter(fOwner
, new BMessage(MSG_STATUS_MESSAGE
));
479 EntryFilter
entryFilter(srcDirectory
.Path());
480 CopyEngine
engine(&reporter
, &entryFilter
);
483 _LaunchInitScript(targetDirectory
);
485 // Create the default indices which should always be present on a proper
486 // boot volume. We don't care if the source volume does not have them.
487 // After all, the user might be re-installing to another drive and may
488 // want problems fixed along the way...
489 err
= _CreateDefaultIndices(targetDirectory
);
491 return _InstallationError(err
);
492 // Mirror all the indices which are present on the source volume onto
493 // the target volume.
494 err
= _MirrorIndices(srcDirectory
, targetDirectory
);
496 return _InstallationError(err
);
498 // Let the engine collect information for the progress bar later on
499 engine
.ResetTargets(srcDirectory
.Path());
500 err
= engine
.CollectTargets(srcDirectory
.Path(), fCancelSemaphore
);
502 return _InstallationError(err
);
504 // Collect selected packages also
506 BPath
pkgRootDir(srcDirectory
.Path(), kPackagesDirectoryPath
);
507 int32 count
= fPackages
->CountItems();
508 for (int32 i
= 0; i
< count
; i
++) {
509 Package
*p
= static_cast<Package
*>(fPackages
->ItemAt(i
));
510 BPath
packageDir(pkgRootDir
.Path(), p
->Folder());
511 err
= engine
.CollectTargets(packageDir
.Path(), fCancelSemaphore
);
513 return _InstallationError(err
);
517 // collect information about all zip packages
518 err
= _ProcessZipPackages(srcDirectory
.Path(), targetDirectory
.Path(),
519 &reporter
, unzipEngines
);
521 return _InstallationError(err
);
523 reporter
.StartTimer();
525 // copy source volume
526 err
= engine
.CopyFolder(srcDirectory
.Path(), targetDirectory
.Path(),
529 return _InstallationError(err
);
531 // copy selected packages
533 BPath
pkgRootDir(srcDirectory
.Path(), kPackagesDirectoryPath
);
534 int32 count
= fPackages
->CountItems();
535 for (int32 i
= 0; i
< count
; i
++) {
536 Package
*p
= static_cast<Package
*>(fPackages
->ItemAt(i
));
537 BPath
packageDir(pkgRootDir
.Path(), p
->Folder());
538 err
= engine
.CopyFolder(packageDir
.Path(), targetDirectory
.Path(),
541 return _InstallationError(err
);
545 // Extract all zip packages. If an error occured, delete the rest of
546 // the engines, but stop extracting.
547 for (int32 i
= 0; i
< unzipEngines
.CountItems(); i
++) {
548 UnzipEngine
* engine
= reinterpret_cast<UnzipEngine
*>(
549 unzipEngines
.ItemAtFast(i
));
551 err
= engine
->UnzipPackage();
555 return _InstallationError(err
);
557 _LaunchFinishScript(targetDirectory
);
559 fOwner
.SendMessage(MSG_INSTALL_FINISHED
);
565 WorkerThread::_InstallationError(status_t error
)
567 BMessage
statusMessage(MSG_RESET
);
568 if (error
== B_CANCELED
)
569 _SetStatusMessage(B_TRANSLATE("Installation canceled."));
571 statusMessage
.AddInt32("error", error
);
572 ERR("_PerformInstall failed");
573 fOwner
.SendMessage(&statusMessage
);
579 WorkerThread::_MirrorIndices(const BPath
& sourceDirectory
,
580 const BPath
& targetDirectory
) const
582 dev_t sourceDevice
= dev_for_path(sourceDirectory
.Path());
583 if (sourceDevice
< 0)
584 return (status_t
)sourceDevice
;
585 dev_t targetDevice
= dev_for_path(targetDirectory
.Path());
586 if (targetDevice
< 0)
587 return (status_t
)targetDevice
;
588 DIR* indices
= fs_open_index_dir(sourceDevice
);
589 if (indices
== NULL
) {
590 printf("%s: fs_open_index_dir(): (%d) %s\n", sourceDirectory
.Path(),
591 errno
, strerror(errno
));
592 // Opening the index directory will fail for example on ISO-Live
593 // CDs. The default indices have already been created earlier, so
597 while (dirent
* index
= fs_read_index_dir(indices
)) {
598 if (strcmp(index
->d_name
, "name") == 0
599 || strcmp(index
->d_name
, "size") == 0
600 || strcmp(index
->d_name
, "last_modified") == 0) {
605 if (fs_stat_index(sourceDevice
, index
->d_name
, &info
) != B_OK
) {
606 printf("Failed to mirror index %s: fs_stat_index(): (%d) %s\n",
607 index
->d_name
, errno
, strerror(errno
));
612 // Flags are always 0 for the moment.
613 if (fs_create_index(targetDevice
, index
->d_name
, info
.type
, flags
)
615 if (errno
== B_FILE_EXISTS
)
617 printf("Failed to mirror index %s: fs_create_index(): (%d) %s\n",
618 index
->d_name
, errno
, strerror(errno
));
622 fs_close_index_dir(indices
);
628 WorkerThread::_CreateDefaultIndices(const BPath
& targetDirectory
) const
630 dev_t targetDevice
= dev_for_path(targetDirectory
.Path());
631 if (targetDevice
< 0)
632 return (status_t
)targetDevice
;
639 const IndexInfo defaultIndices
[] = {
640 { "BEOS:APP_SIG", B_STRING_TYPE
},
641 { "BEOS:LOCALE_LANGUAGE", B_STRING_TYPE
},
642 { "BEOS:LOCALE_SIGNATURE", B_STRING_TYPE
},
643 { "_trk/qrylastchange", B_INT32_TYPE
},
644 { "_trk/recentQuery", B_INT32_TYPE
},
645 { "be:deskbar_item_status", B_STRING_TYPE
}
649 // Flags are always 0 for the moment.
651 for (uint32 i
= 0; i
< sizeof(defaultIndices
) / sizeof(IndexInfo
); i
++) {
652 const IndexInfo
& info
= defaultIndices
[i
];
653 if (fs_create_index(targetDevice
, info
.name
, info
.type
, flags
)
655 if (errno
== B_FILE_EXISTS
)
657 printf("Failed to create index %s: fs_create_index(): (%d) %s\n",
658 info
.name
, errno
, strerror(errno
));
668 WorkerThread::_ProcessZipPackages(const char* sourcePath
,
669 const char* targetPath
, ProgressReporter
* reporter
, BList
& unzipEngines
)
671 // TODO: Put those in the optional packages list view
672 // TODO: Implement mechanism to handle dependencies between these
673 // packages. (Selecting one will auto-select others.)
674 BPath
pkgRootDir(sourcePath
, kPackagesDirectoryPath
);
675 BDirectory
directory(pkgRootDir
.Path());
677 while (directory
.GetNextEntry(&entry
) == B_OK
) {
678 char name
[B_FILE_NAME_LENGTH
];
679 if (entry
.GetName(name
) != B_OK
)
681 int nameLength
= strlen(name
);
684 char* nameExtension
= name
+ nameLength
- 4;
685 if (strcasecmp(nameExtension
, ".zip") != 0)
687 printf("found .zip package: %s\n", name
);
689 UnzipEngine
* unzipEngine
= new(std::nothrow
) UnzipEngine(reporter
,
691 if (unzipEngine
== NULL
|| !unzipEngines
.AddItem(unzipEngine
)) {
696 entry
.GetPath(&path
);
697 status_t ret
= unzipEngine
->SetTo(path
.Path(), targetPath
);
701 reporter
->AddItems(unzipEngine
->ItemsToUncompress(),
702 unzipEngine
->BytesToUncompress());
710 WorkerThread::_SetStatusMessage(const char *status
)
712 BMessage
msg(MSG_STATUS_MESSAGE
);
713 msg
.AddString("status", status
);
714 fOwner
.SendMessage(&msg
);
719 make_partition_label(BPartition
* partition
, char* label
, char* menuLabel
,
720 bool showContentType
)
723 string_for_size(partition
->Size(), size
, sizeof(size
));
726 partition
->GetPath(&path
);
728 if (showContentType
) {
729 const char* type
= partition
->ContentType();
731 type
= B_TRANSLATE_COMMENT("Unknown Type", "Partition content type");
733 sprintf(label
, "%s - %s [%s] (%s)", partition
->ContentName(), size
,
736 sprintf(label
, "%s - %s [%s]", partition
->ContentName(), size
,
740 sprintf(menuLabel
, "%s - %s", partition
->ContentName(), size
);
744 // #pragma mark - SourceVisitor
747 SourceVisitor::SourceVisitor(BMenu
*menu
)
753 SourceVisitor::Visit(BDiskDevice
*device
)
755 return Visit(device
, 0);
760 SourceVisitor::Visit(BPartition
*partition
, int32 level
)
763 if (partition
->GetPath(&path
) == B_OK
)
764 printf("SourceVisitor::Visit(BPartition *) : %s\n", path
.Path());
765 printf("SourceVisitor::Visit(BPartition *) : %s\n",
766 partition
->ContentName());
768 if (partition
->ContentType() == NULL
)
771 bool isBootPartition
= false;
772 if (partition
->IsMounted()) {
774 partition
->GetMountPoint(&mountPoint
);
775 isBootPartition
= strcmp(BOOT_PATH
, mountPoint
.Path()) == 0;
779 && strcmp(partition
->ContentType(), kPartitionTypeBFS
) != 0) {
780 // Except only BFS partitions, except this is the boot partition
781 // (ISO9660 with write overlay for example).
785 // TODO: We could probably check if this volume contains
786 // the Haiku kernel or something. Does it make sense to "install"
787 // from your BFS volume containing the music collection?
788 // TODO: Then the check for BFS could also be removed above.
792 make_partition_label(partition
, label
, menuLabel
, false);
793 PartitionMenuItem
* item
= new PartitionMenuItem(partition
->ContentName(),
794 label
, menuLabel
, new BMessage(SOURCE_PARTITION
), partition
->ID());
795 item
->SetMarked(isBootPartition
);
796 fMenu
->AddItem(item
);
801 // #pragma mark - TargetVisitor
804 TargetVisitor::TargetVisitor(BMenu
*menu
)
811 TargetVisitor::Visit(BDiskDevice
*device
)
813 if (device
->IsReadOnlyMedia())
815 return Visit(device
, 0);
820 TargetVisitor::Visit(BPartition
*partition
, int32 level
)
823 if (partition
->GetPath(&path
) == B_OK
)
824 printf("TargetVisitor::Visit(BPartition *) : %s\n", path
.Path());
825 printf("TargetVisitor::Visit(BPartition *) : %s\n",
826 partition
->ContentName());
828 if (partition
->ContentSize() < 20 * 1024 * 1024) {
829 // reject partitions which are too small anyway
830 // TODO: Could depend on the source size
831 printf(" too small\n");
835 if (partition
->CountChildren() > 0) {
836 // Looks like an extended partition, or the device itself.
837 // Do not accept this as target...
838 printf(" no leaf partition\n");
842 // TODO: After running DriveSetup and doing another scan, it would
843 // be great to pick the partition which just appeared!
845 bool isBootPartition
= false;
846 if (partition
->IsMounted()) {
848 partition
->GetMountPoint(&mountPoint
);
849 isBootPartition
= strcmp(BOOT_PATH
, mountPoint
.Path()) == 0;
852 // Only non-boot BFS partitions are valid targets, but we want to display the
853 // other partitions as well, in order not to irritate the user.
854 bool isValidTarget
= isBootPartition
== false
855 && partition
->ContentType() != NULL
856 && strcmp(partition
->ContentType(), kPartitionTypeBFS
) == 0;
860 make_partition_label(partition
, label
, menuLabel
, !isValidTarget
);
861 PartitionMenuItem
* item
= new PartitionMenuItem(partition
->ContentName(),
862 label
, menuLabel
, new BMessage(TARGET_PARTITION
), partition
->ID());
864 item
->SetIsValidTarget(isValidTarget
);
867 fMenu
->AddItem(item
);