From b4afa66367d65eb54c52b4aeec4724af691ef11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sun, 3 May 2009 09:32:24 +0000 Subject: [PATCH] First round of cleanup: * Renamed CopyEngine to WorkerThread, since it's used for other things than just copying. * Removed the code borrowed from Tracker. * Removed the InstallerCopyLoopControl, since the CopyEngine handles notifications and cancelling by itself now. * Renamed a few message constants. * Since we only support BFS partitions as install targets, I removed the FS type from the target menu item label. However, I am going to solve this differently. I guess all partitions should be seen in the target list, just disabled if they are not a valid target, and with a reason given too. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30600 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/installer/CopyEngine.h | 49 - src/apps/installer/FSUtils.cpp | 3359 ----------------- src/apps/installer/FSUtils.h | 312 -- .../installer/InstallerCopyLoopControl.cpp | 119 - src/apps/installer/InstallerCopyLoopControl.h | 47 - src/apps/installer/InstallerWindow.cpp | 31 +- src/apps/installer/InstallerWindow.h | 12 +- src/apps/installer/Jamfile | 4 +- src/apps/installer/PackageViews.cpp | 4 +- src/apps/installer/Vector.h | 798 ---- .../{CopyEngine.cpp => WorkerThread.cpp} | 282 +- src/apps/installer/WorkerThread.h | 56 + 12 files changed, 210 insertions(+), 4863 deletions(-) delete mode 100644 src/apps/installer/CopyEngine.h delete mode 100644 src/apps/installer/FSUtils.cpp delete mode 100644 src/apps/installer/FSUtils.h delete mode 100644 src/apps/installer/InstallerCopyLoopControl.cpp delete mode 100644 src/apps/installer/InstallerCopyLoopControl.h delete mode 100644 src/apps/installer/Vector.h rename src/apps/installer/{CopyEngine.cpp => WorkerThread.cpp} (73%) create mode 100644 src/apps/installer/WorkerThread.h diff --git a/src/apps/installer/CopyEngine.h b/src/apps/installer/CopyEngine.h deleted file mode 100644 index e408c1ced0..0000000000 --- a/src/apps/installer/CopyEngine.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2005, Jérôme DUVAL. All rights reserved. - * Distributed under the terms of the MIT License. - */ - -#ifndef _CopyEngine_h -#define _CopyEngine_h - -#include "InstallerCopyLoopControl.h" - -#include -#include -#include -#include -#include -#include - -class BLocker; -class InstallerWindow; - -const uint32 ENGINE_START = 'eSRT'; - -class CopyEngine : public BLooper { - public: - CopyEngine(InstallerWindow *window); - void MessageReceived(BMessage *msg); - void ScanDisksPartitions(BMenu *srcMenu, BMenu *targetMenu); - void SetPackagesList(BList *list); - void SetSpaceRequired(off_t bytes) { fSpaceRequired = bytes; }; - bool Cancel(); - void SetLock(BLocker* lock) { fCancelLock = lock; } - void WriteBootSector(BMenu *targetMenu); - - private: - void LaunchInitScript(BPath &path); - void LaunchFinishScript(BPath &path); - void SetStatusMessage(const char *status); - void Start(BMenu *srcMenu, BMenu *targetMenu); - status_t CopyFolder(BDirectory &srcDir, BDirectory &targetDir); - - InstallerWindow *fWindow; - BDiskDeviceRoster fDDRoster; - InstallerCopyLoopControl *fControl; - BList *fPackages; - off_t fSpaceRequired; - BLocker* fCancelLock; -}; - -#endif /* _CopyEngine_h */ diff --git a/src/apps/installer/FSUtils.cpp b/src/apps/installer/FSUtils.cpp deleted file mode 100644 index b3aaabbdaa..0000000000 --- a/src/apps/installer/FSUtils.cpp +++ /dev/null @@ -1,3359 +0,0 @@ -/* -Open Tracker License - -Terms and Conditions - -Copyright (c) 1991-2000, Be Incorporated. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice applies to all licensees -and shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Be Incorporated shall not be -used in advertising or otherwise to promote the sale, use or other dealings in -this Software without prior written authorization from Be Incorporated. - -Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks -of Be Incorporated in the United States and other countries. Other brand product -names are registered trademarks or trademarks of their respective holders. -All rights reserved. -*/ - -// Tracker file system calls. - -// Note - APIs/code in FSUtils.h and FSUtils.cpp is slated for a major cleanup -// -- in other words, you will find a lot of ugly cruft in here - -// ToDo: -// Move most of preflight error checks to the Model level and only keep those -// that have to do with size, reading/writing and name collisions. -// Get rid of all the BList based APIs, use BObjectLists. -// Clean up the error handling, push most of the user interaction out of the -// low level FS calls. - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "Attributes.h" -#include "Bitmaps.h" -#include "Commands.h" -#include "FSUndoRedo.h" -#include "FSUtils.h" -#include "InfoWindow.h" -#include "MimeTypes.h" -#include "Model.h" -#include "OverrideAlert.h" -#include "StatusWindow.h" -#include "Thread.h" -#include "Tracker.h" -#include "TrackerSettings.h" -#include "Utilities.h" - - -enum { - kUserCanceled = B_ERRORS_END + 1, - kCopyCanceled = kUserCanceled, - kTrashCanceled -}; - -enum ConflictCheckResult { - kCanceled = kUserCanceled, - kPrompt, - kReplace, - kReplaceAll, - kNoConflicts -}; - -namespace BPrivate { - -static status_t FSDeleteFolder(BEntry *, CopyLoopControl *, bool updateStatus, - bool deleteTopDir = true, bool upateFileNameInStatus = false); -static status_t MoveEntryToTrash(BEntry *, BPoint *, Undo &undo); -static void LowLevelCopy(BEntry *, StatStruct *, BDirectory *, char *destName, - CopyLoopControl *, BPoint *); -status_t DuplicateTask(BObjectList *srcList); -static status_t MoveTask(BObjectList *, BEntry *, BList *, uint32); -static status_t _DeleteTask(BObjectList *, bool); -static status_t _RestoreTask(BObjectList *); -status_t CalcItemsAndSize(BObjectList *refList, int32 *totalCount, off_t *totalSize); -status_t MoveItem(BEntry *entry, BDirectory *destDir, BPoint *loc, - uint32 moveMode, const char *newName, Undo &undo); -ConflictCheckResult PreFlightNameCheck(BObjectList *srcList, const BDirectory *destDir, - int32 *collisionCount); -status_t CheckName(uint32 moveMode, const BEntry *srcEntry, const BDirectory *destDir, - bool multipleCollisions, ConflictCheckResult &); -void CopyAttributes(CopyLoopControl *control, BNode *srcNode, BNode* destNode, void *buffer, - size_t bufsize); -void CopyPoseLocation(BNode *src, BNode *dest); -bool DirectoryMatchesOrContains(const BEntry *, directory_which); -bool DirectoryMatchesOrContains(const BEntry *, const char *additionalPath, directory_which); -bool DirectoryMatches(const BEntry *, directory_which); -bool DirectoryMatches(const BEntry *, const char *additionalPath, directory_which); - -status_t empty_trash(void *); - -#ifdef __HAIKU__ - #define OS_NAME "Haiku" -#else - #define OS_NAME "BeOS" -#endif - - -const char *kDeleteConfirmationStr = "Are you sure you want to delete the selected " - "item(s)? This operation cannot be reverted."; - -const char *kReplaceStr = "You are trying to replace the item:\n" - "\t%s%s\n" - "with:\n" - "\t%s%s\n\n" - "Would you like to replace it with the one you are %s?"; - -const char *kDirectoryReplaceStr = "An item named \"%s\" already exists in this folder. " - "Would you like to replace it with the one you are %s?"; - -const char *kSymLinkReplaceStr = "An item named \"%s\" already exists in this folder. " - "Would you like to replace it with the symbolic link you are creating?"; - -const char *kNoFreeSpace = "Sorry, there is not enough free space on the destination " - "volume to copy the selection."; - -const char *kFileErrorString = "Error copying file \"%s\":\n\t%s\n\nWould you like to continue?"; -const char *kFolderErrorString = "Error copying folder \"%s\":\n\t%s\n\nWould you like to continue?"; -const char *kFileDeleteErrorString = "There was an error deleting \"%s\":\n\t%s"; -const char *kReplaceManyStr = "Some items already exist in this folder with " - "the same names as the items you are %s.\n \nWould you like to replace them " - "with the ones you are %s or be prompted for each one?"; - -const char *kFindAlternativeStr = "Would you like to find some other suitable application?"; -const char *kFindApplicationStr = "Would you like to find a suitable application to " - "open the file?"; - -// Skip these attributes when copying in Tracker -const char *kSkipAttributes[] = { - kAttrPoseInfo, - NULL -}; - - -CopyLoopControl::~CopyLoopControl() -{ -} - - -bool -TrackerCopyLoopControl::FileError(const char *message, const char *name, - status_t error, bool allowContinue) -{ - char buffer[512]; - sprintf(buffer, message, name, strerror(error)); - - if (allowContinue) - return (new BAlert("", buffer, "Cancel", "OK", 0, - B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0; - - (new BAlert("", buffer, "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(); - return false; -} - - -void -TrackerCopyLoopControl::UpdateStatus(const char *name, entry_ref, int32 count, - bool optional) -{ - if (gStatusWindow && gStatusWindow->HasStatus(fThread)) - gStatusWindow->UpdateStatus(fThread, const_cast(name), - count, optional); -} - - -bool -TrackerCopyLoopControl::CheckUserCanceled() -{ - return gStatusWindow && gStatusWindow->CheckCanceledOrPaused(fThread); -} - - -TrackerCopyLoopControl::OverwriteMode -TrackerCopyLoopControl::OverwriteOnConflict(const BEntry *, const char *, - const BDirectory *, bool, bool) -{ - return kReplace; -} - - -bool -TrackerCopyLoopControl::SkipEntry(const BEntry *, bool) -{ - // tracker makes no exceptions - return false; -} - - -bool -TrackerCopyLoopControl::SkipAttribute(const char *attributeName) -{ - for (const char **skipAttribute = kSkipAttributes; *skipAttribute; - skipAttribute++) - if (strcmp(*skipAttribute, attributeName) == 0) - return true; - - return false; -} - - -void -CopyLoopControl::ChecksumChunk(const char *, size_t) -{ -} - - -bool -CopyLoopControl::ChecksumFile(const entry_ref *) -{ - return true; -} - - -bool -CopyLoopControl::SkipAttribute(const char*) -{ - return false; -} - - -bool -CopyLoopControl::PreserveAttribute(const char*) -{ - return false; -} - - -static BNode * -GetWritableNode(BEntry *entry, StatStruct *statBuf = 0) -{ - // utility call that works around the problem with BNodes not being - // universally writeable - // BNodes created on files will fail to WriteAttr because they do not - // have the right r/w permissions - - StatStruct localStatbuf; - - if (!statBuf) { - statBuf = &localStatbuf; - if (entry->GetStat(statBuf) != B_OK) - return 0; - } - - if (S_ISREG(statBuf->st_mode)) - return new BFile(entry, O_RDWR); - - return new BNode(entry); -} - - -status_t -FSSetPoseLocation(ino_t destDirInode, BNode *destNode, BPoint point) -{ - PoseInfo poseInfo; - poseInfo.fInvisible = false; - poseInfo.fInitedDirectory = destDirInode; - poseInfo.fLocation = point; - - status_t result = destNode->WriteAttr(kAttrPoseInfo, B_RAW_TYPE, 0, - &poseInfo, sizeof(poseInfo)); - - if (result == sizeof(poseInfo)) - return B_OK; - - return result; -} - - -status_t -FSSetPoseLocation(BEntry *entry, BPoint point) -{ - BNode node(entry); - status_t result = node.InitCheck(); - if (result != B_OK) - return result; - - BDirectory parent; - result = entry->GetParent(&parent); - if (result != B_OK) - return result; - - node_ref destNodeRef; - result = parent.GetNodeRef(&destNodeRef); - if (result != B_OK) - return result; - - return FSSetPoseLocation(destNodeRef.node, &node, point); -} - - -bool -FSGetPoseLocation(const BNode *node, BPoint *point) -{ - PoseInfo poseInfo; - if (ReadAttr(node, kAttrPoseInfo, kAttrPoseInfoForeign, - B_RAW_TYPE, 0, &poseInfo, sizeof(poseInfo), &PoseInfo::EndianSwap) - == kReadAttrFailed) - return false; - - if (poseInfo.fInitedDirectory == -1LL) - return false; - - *point = poseInfo.fLocation; - - return true; -} - - -static void -SetUpPoseLocation(ino_t sourceParentIno, ino_t destParentIno, - const BNode *sourceNode, BNode *destNode, BPoint *loc) -{ - BPoint point; - if (!loc - // we don't have a position yet - && sourceParentIno != destParentIno - // we aren't copying into the same directory - && FSGetPoseLocation(sourceNode, &point)) - // the original has a valid inited location - loc = &point; - // copy the originals location - - if (loc && loc != (BPoint *)-1) { - // loc of -1 is used when copying/moving into a window in list mode - // where copying positions would not work - // TODO: - // should push all this logic to upper levels - FSSetPoseLocation(destParentIno, destNode, *loc); - } -} - - -void -FSMoveToFolder(BObjectList *srcList, BEntry *destEntry, - uint32 moveMode, BList *pointList) -{ - if (srcList->IsEmpty()) { - delete srcList; - delete pointList; - delete destEntry; - return; - } - - LaunchInNewThread("MoveTask", B_NORMAL_PRIORITY, MoveTask, srcList, destEntry, - pointList, moveMode); -} - - -void -FSDelete(entry_ref *ref, bool async, bool confirm) -{ - BObjectList *list = new BObjectList(1, true); - list->AddItem(ref); - FSDeleteRefList(list, async, confirm); -} - - -void -FSDeleteRefList(BObjectList *list, bool async, bool confirm) -{ - if (async) - LaunchInNewThread("DeleteTask", B_NORMAL_PRIORITY, _DeleteTask, list, confirm); - else - _DeleteTask(list, confirm); -} - - -void -FSRestoreRefList(BObjectList *list, bool async) -{ - if (async) - LaunchInNewThread("RestoreTask", B_NORMAL_PRIORITY, _RestoreTask, list); - else - _RestoreTask(list); -} - - -void -FSMoveToTrash(BObjectList *srcList, BList *pointList, bool async) -{ - if (srcList->IsEmpty()) { - delete srcList; - delete pointList; - return; - } - - if (async) - LaunchInNewThread("MoveTask", B_NORMAL_PRIORITY, MoveTask, srcList, - (BEntry *)0, pointList, kMoveSelectionTo); - else - MoveTask(srcList, 0, pointList, kMoveSelectionTo); -} - - -static bool -IsDisksWindowIcon(BEntry *entry) -{ - BPath path; - if (entry->InitCheck() != B_OK || entry->GetPath(&path) != B_OK) - return false; - - return strcmp(path.Path(), "/") == 0; -} - -enum { - kNotConfirmed, - kConfirmedHomeMove, - kConfirmedAll -}; - - -bool -ConfirmChangeIfWellKnownDirectory(const BEntry *entry, const char *action, - bool dontAsk, int32 *confirmedAlready) -{ - // Don't let the user casually move/change important files/folders - // - // This is a cheap replacement for having a real UID support turned - // on and not running as root all the time - - if (confirmedAlready && *confirmedAlready == kConfirmedAll) - return true; - - if (!DirectoryMatchesOrContains(entry, B_BEOS_DIRECTORY) - && !DirectoryMatchesOrContains(entry, B_USER_DIRECTORY)) - // quick way out - return true; - - const char *warning = NULL; - bool requireOverride = true; - - if (DirectoryMatches(entry, B_BEOS_DIRECTORY)) - warning = "If you %s the beos folder, you won't be able to " - "boot " OS_NAME "! Are you sure you want to do this? To %s the folder " - "anyway, hold down the Shift key and click \"Do it\"."; - else if (DirectoryMatchesOrContains(entry, B_BEOS_SYSTEM_DIRECTORY)) - warning = "If you %s the system folder or its contents, you " - "won't be able to boot " OS_NAME "! Are you sure you want to do this? " - "To %s the system folder or its contents anyway, hold down " - "the Shift key and click \"Do it\"."; - else if (DirectoryMatches(entry, B_USER_DIRECTORY)) { - warning = "If you %s the home folder, " OS_NAME " may not " - "behave properly! Are you sure you want to do this? " - "To %s the home anyway, click \"Do it\"."; - requireOverride = false; - } else if (DirectoryMatchesOrContains(entry, B_USER_CONFIG_DIRECTORY) - || DirectoryMatchesOrContains(entry, B_COMMON_SETTINGS_DIRECTORY)) { - - if (DirectoryMatchesOrContains(entry, "beos_mime", B_USER_SETTINGS_DIRECTORY) - || DirectoryMatchesOrContains(entry, "beos_mime", B_COMMON_SETTINGS_DIRECTORY)) { - warning = "If you %s the mime settings, " OS_NAME " may not " - "behave properly! Are you sure you want to do this? " - "To %s the mime settings anyway, click \"Do it\"."; - requireOverride = false; - } else if (DirectoryMatches(entry, B_USER_CONFIG_DIRECTORY)) { - warning = "If you %s the config folder, " OS_NAME " may not " - "behave properly! Are you sure you want to do this? " - "To %s the config folder anyway, click \"Do it\"."; - requireOverride = false; - } else if (DirectoryMatches(entry, B_USER_SETTINGS_DIRECTORY) - || DirectoryMatches(entry, B_COMMON_SETTINGS_DIRECTORY)) { - warning = "If you %s the settings folder, " OS_NAME " may not " - "behave properly! Are you sure you want to do this? " - "To %s the settings folder anyway, click \"Do it\"."; - requireOverride = false; - } - } - - if (!warning) - return true; - - if (dontAsk) - return false; - - if (confirmedAlready && *confirmedAlready == kConfirmedHomeMove - && !requireOverride) - // we already warned about moving home this time around - return true; - - char buffer[256]; - sprintf(buffer, warning, action, action); - - if ((new OverrideAlert("", buffer, "Do it", (requireOverride ? B_SHIFT_KEY : 0), - "Cancel", 0, NULL, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go() == 1) { - if (confirmedAlready) - *confirmedAlready = kNotConfirmed; - return false; - } - - if (confirmedAlready) { - if (!requireOverride) - *confirmedAlready = kConfirmedHomeMove; - else - *confirmedAlready = kConfirmedAll; - } - - return true; -} - - -static status_t -InitCopy(uint32 moveMode, BObjectList *srcList, thread_id thread, - BVolume *dstVol, BDirectory *destDir, entry_ref *destRef, - bool preflightNameCheck, int32 *collisionCount, ConflictCheckResult *preflightResult) -{ - if (dstVol->IsReadOnly()) { - if (gStatusWindow) - gStatusWindow->RemoveStatusItem(thread); - - (new BAlert("", "You can't move or copy items to read-only volumes.", - "Cancel", 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return B_ERROR; - } - - int32 numItems = srcList->CountItems(); - int32 askOnceOnly = kNotConfirmed; - for (int32 index = 0; index < numItems; index++) { - // we could check for this while iterating through items in each of the copy - // loops, except it takes forever to call CalcItemsAndSize - BEntry entry((entry_ref *)srcList->ItemAt(index)); - if (IsDisksWindowIcon(&entry)) { - - const char *errorStr; - if (moveMode == kCreateLink) - errorStr = "You cannot create a link to the root directory."; - else - errorStr = "You cannot copy or move the root directory."; - - (new BAlert("", errorStr, "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return B_ERROR; - } - if (moveMode == kMoveSelectionTo - && !ConfirmChangeIfWellKnownDirectory(&entry, "move", false, &askOnceOnly)) - return B_ERROR; - } - - if (preflightNameCheck) { - ASSERT(collisionCount); - ASSERT(preflightResult); - - *preflightResult = kPrompt; - *collisionCount = 0; - - *preflightResult = PreFlightNameCheck(srcList, destDir, collisionCount); - if (*preflightResult == kCanceled) // user canceled - return B_ERROR; - } - - // set up the status display - switch (moveMode) { - case kCopySelectionTo: - case kDuplicateSelection: - { - if (gStatusWindow) - gStatusWindow->CreateStatusItem(thread, kCopyState); - - int32 totalItems = 0; - off_t totalSize = 0; - if (CalcItemsAndSize(srcList, &totalItems, &totalSize) != B_OK) - return B_ERROR; - - // check for free space before starting copy - if ((totalSize + (4 * kKBSize)) >= dstVol->FreeBytes()) { - (new BAlert("", kNoFreeSpace, "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return B_ERROR; - } - - if (gStatusWindow) - gStatusWindow->InitStatusItem(thread, totalItems, totalSize, - destRef); - break; - } - - case kMoveSelectionTo: - case kCreateLink: - if (numItems > 10) { - // this will be fast, only put up status if lots of items - // moved, links created - if (gStatusWindow) { - gStatusWindow->CreateStatusItem(thread, - moveMode == kMoveSelectionTo - ? kMoveState : kCreateLinkState); - gStatusWindow->InitStatusItem(thread, numItems, numItems, - destRef); - } - } - break; - } - return B_OK; -} - - -// ToDo: -// get rid of this cruft -bool -delete_ref(void *ref) -{ - delete (entry_ref*)ref; - return false; -} - - -bool -delete_point(void *point) -{ - delete (BPoint*)point; - return false; -} - - -static status_t -MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, uint32 moveMode) -{ - ASSERT(!srcList->IsEmpty()); - - // extract information from src, dest models - // ## note that we're assuming all items come from the same volume - // ## by looking only at FirstItem here which is not a good idea - dev_t srcVolumeDevice = srcList->FirstItem()->device; - dev_t destVolumeDevice = srcVolumeDevice; - - StatStruct deststat; - BVolume volume; - entry_ref destRef; - const entry_ref *destRefToCheck = NULL; - - bool destIsTrash = false; - BDirectory destDir; - BDirectory *destDirToCheck = NULL; - bool needPreflightNameCheck = false; - - bool fromUndo = FSIsUndoMoveMode(moveMode); - moveMode = FSMoveMode(moveMode); - - // if we're not passed a destEntry then we are supposed to move to trash - if (destEntry) { - destEntry->GetRef(&destRef); - destRefToCheck = &destRef; - - destDir.SetTo(destEntry); - destDir.GetStat(&deststat); - destDirToCheck = &destDir; - - destVolumeDevice = deststat.st_dev; - destIsTrash = FSIsTrashDir(destEntry); - volume.SetTo(destVolumeDevice); - - needPreflightNameCheck = true; - } else if (moveMode == kDuplicateSelection) - volume.SetTo(srcVolumeDevice); - else { - // move is to trash - destIsTrash = true; - - FSGetTrashDir(&destDir, srcVolumeDevice); - volume.SetTo(srcVolumeDevice); - - BEntry entry; - destDir.GetEntry(&entry); - destDirToCheck = &destDir; - - entry.GetRef(&destRef); - destRefToCheck = &destRef; - } - - // change the move mode if needed - if (moveMode == kMoveSelectionTo && srcVolumeDevice != destVolumeDevice) - // move across volumes - copy instead - moveMode = kCopySelectionTo; - if (moveMode == kCopySelectionTo && destIsTrash) - // cannot copy to trash - moveMode = kMoveSelectionTo; - - // we need the undo object later on, so we create it no matter - // if we really need it or not (it's very lightweight) - MoveCopyUndo undo(srcList, destDir, pointList, moveMode); - if (fromUndo) - undo.Remove(); - - thread_id thread = find_thread(NULL); - ConflictCheckResult conflictCheckResult = kPrompt; - int32 collisionCount = 0; - status_t result = InitCopy(moveMode, srcList, thread, &volume, destDirToCheck, - &destRef, needPreflightNameCheck, &collisionCount, &conflictCheckResult); - - int32 count = srcList->CountItems(); - if (result == B_OK) { - for (int32 i = 0; i < count; i++) { - BPoint *loc = (BPoint *)-1; - // a loc of -1 forces autoplacement, rather than copying the - // position of the original node - // ToDo: - // clean this mess up - - entry_ref *srcRef = srcList->ItemAt(i); - - if (moveMode == kDuplicateSelection) { - BEntry entry(srcRef); - entry.GetParent(&destDir); - destDir.GetStat(&deststat); - volume.SetTo(srcRef->device); - } - - // handle case where item is dropped into folder it already lives in - // which could happen if dragging from a query window - if (moveMode != kCreateLink - && moveMode != kCreateRelativeLink - && moveMode != kDuplicateSelection - && !destIsTrash - && (srcRef->device == destRef.device - && srcRef->directory == deststat.st_ino)) - continue; - - if (gStatusWindow && gStatusWindow->CheckCanceledOrPaused(thread)) - break; - - BEntry sourceEntry(srcRef); - if (sourceEntry.InitCheck() != B_OK) { - BString error; - error << "Error moving \"" << srcRef->name << "\"."; - (new BAlert("", error.String(), "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - break; - } - - // are we moving item to trash? - if (destIsTrash) { - if (pointList) - loc = (BPoint *)pointList->ItemAt(i); - - result = MoveEntryToTrash(&sourceEntry, loc, undo); - if (result != B_OK) { - BString error; - error << "Error moving \"" << srcRef->name << "\" to Trash. (" - << strerror(result) << ")"; - (new BAlert("", error.String(), "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - break; - } - continue; - } - - // resolve name collisions and hierarchy problems - if (CheckName(moveMode, &sourceEntry, &destDir, collisionCount > 1, - conflictCheckResult) != B_OK) { - // we will skip the current item, because we got a conflict - // and were asked to or because there was some conflict - - // update the status because item got skipped and the status - // will not get updated by the move call - if (gStatusWindow && gStatusWindow->HasStatus(thread)) - gStatusWindow->UpdateStatus(thread, srcRef->name, 1); - - continue; - } - - // get location to place this item - if (pointList && moveMode != kCopySelectionTo) { - loc = (BPoint *)pointList->ItemAt(i); - - BNode *src_node = GetWritableNode(&sourceEntry); - if (src_node && src_node->InitCheck() == B_OK) { - PoseInfo poseInfo; - poseInfo.fInvisible = false; - poseInfo.fInitedDirectory = deststat.st_ino; - poseInfo.fLocation = *loc; - src_node->WriteAttr(kAttrPoseInfo, B_RAW_TYPE, 0, - &poseInfo, sizeof(poseInfo)); - } - delete src_node; - } - - if (pointList) - loc = (BPoint*)pointList->ItemAt(i); - - result = MoveItem(&sourceEntry, &destDir, loc, moveMode, NULL, undo); - if (result != B_OK) - break; - } - } - - // duplicates of srcList, destFolder were created - dispose them - delete srcList; - delete destEntry; - - // delete file location list and all Points within - if (pointList) { - pointList->DoForEach(delete_point); - delete pointList; - } - - if (gStatusWindow) - gStatusWindow->RemoveStatusItem(thread); - - return B_OK; -} - -class FailWithAlert { - public: - static void FailOnError(status_t error, const char *string, const char *name = NULL) - { - if (error != B_OK) - throw FailWithAlert(error, string, name); - } - - FailWithAlert(status_t error, const char *string, const char *name) - : fString(string), - fName(name), - fError(error) - { - } - - const char *fString; - const char *fName; - status_t fError; -}; - -class MoveError { - public: - static void FailOnError(status_t error) - { - if (error != B_OK) - throw MoveError(error); - } - - MoveError(status_t error) - : fError(error) - { } - - status_t fError; -}; - - -void -CopyFile(BEntry *srcFile, StatStruct *srcStat, BDirectory *destDir, - CopyLoopControl *loopControl, BPoint *loc, bool makeOriginalName, Undo &undo) -{ - if (loopControl->SkipEntry(srcFile, true)) - return; - - node_ref node; - destDir->GetNodeRef(&node); - BVolume volume(node.device); - - // check for free space first - if ((srcStat->st_size + kKBSize) >= volume.FreeBytes()) { - loopControl->FileError(kNoFreeSpace, "", B_DEVICE_FULL, false); - throw (status_t)B_DEVICE_FULL; - } - - char destName[B_FILE_NAME_LENGTH]; - srcFile->GetName(destName); - entry_ref ref; - srcFile->GetRef(&ref); - - loopControl->UpdateStatus(destName, ref, 1024, true); - - if (makeOriginalName) { - FSMakeOriginalName(destName, destDir, " copy"); - undo.UpdateEntry(srcFile, destName); - } - - BEntry conflictingEntry; - if (destDir->FindEntry(destName, &conflictingEntry) == B_OK) { - switch (loopControl->OverwriteOnConflict(srcFile, destName, destDir, - false, false)) { - case TrackerCopyLoopControl::kSkip: - // we are about to ignore this entire directory - return; - - case TrackerCopyLoopControl::kReplace: - if (conflictingEntry.IsDirectory()) - // remove existing folder recursively - ThrowOnError(FSDeleteFolder(&conflictingEntry, loopControl, false)); - else - ThrowOnError(conflictingEntry.Remove()); - break; - - case TrackerCopyLoopControl::kMerge: - // This flag implies that the attributes should be kept - // on the file. Just ignore it. - break; - } - } - - try { - LowLevelCopy(srcFile, srcStat, destDir, destName, loopControl, loc); - } catch (status_t err) { - if (err == kCopyCanceled) - throw (status_t)err; - - if (err != B_OK) { - if (!loopControl->FileError(kFileErrorString, destName, err, true)) - throw (status_t)err; - else - // user selected continue in spite of error, update status bar - loopControl->UpdateStatus(NULL, ref, (int32)srcStat->st_size); - } - } -} - - -#ifdef _SILENTLY_CORRECT_FILE_NAMES -static bool -CreateFileSystemCompatibleName(const BDirectory *destDir, char *destName) -{ - // Is it a FAT32 file system? (this is the only one we currently now about) - - BEntry target; - destDir->GetEntry(&target); - entry_ref targetRef; - fs_info info; - if (target.GetRef(&targetRef) == B_OK - && fs_stat_dev(targetRef.device, &info) == B_OK - && !strcmp(info.fsh_name, "dos")) { - bool wasInvalid = false; - - // it's a FAT32 file system, now check the name - - int32 length = strlen(destName) - 1; - while (destName[length] == '.') { - // invalid name, just cut off the dot at the end - destName[length--] = '\0'; - wasInvalid = true; - } - - char *invalid = destName; - while ((invalid = strpbrk(invalid, "?<>\\:\"|*")) != NULL) { - invalid[0] = '_'; - wasInvalid = true; - } - - return wasInvalid; - } - - return false; -} -#endif - - -static void -LowLevelCopy(BEntry *srcEntry, StatStruct *srcStat, BDirectory *destDir, - char *destName, CopyLoopControl *loopControl, BPoint *loc) -{ - entry_ref ref; - ThrowOnError(srcEntry->GetRef(&ref)); - - if (S_ISLNK(srcStat->st_mode)) { - // handle symbolic links - BSymLink srcLink; - BSymLink newLink; - char linkpath[MAXPATHLEN]; - - ThrowOnError(srcLink.SetTo(srcEntry)); - ThrowIfNotSize(srcLink.ReadLink(linkpath, MAXPATHLEN-1)); - - ThrowOnError(destDir->CreateSymLink(destName, linkpath, &newLink)); - - node_ref destNodeRef; - destDir->GetNodeRef(&destNodeRef); - // copy or write new pose location as a first thing - SetUpPoseLocation(ref.directory, destNodeRef.node, &srcLink, - &newLink, loc); - - BNodeInfo nodeInfo(&newLink); - ThrowOnError(nodeInfo.SetType(B_LINK_MIMETYPE)); - - newLink.SetPermissions(srcStat->st_mode); - newLink.SetOwner(srcStat->st_uid); - newLink.SetGroup(srcStat->st_gid); - newLink.SetModificationTime(srcStat->st_mtime); - newLink.SetCreationTime(srcStat->st_crtime); - - return; - } - - BFile srcFile(srcEntry, O_RDONLY); - ThrowOnInitCheckError(&srcFile); - - const size_t kMinBufferSize = 1024 * 128; - const size_t kMaxBufferSize = 1024 * 1024; - - size_t bufsize = kMinBufferSize; - if (bufsize < srcStat->st_size) { - // File bigger than the buffer size: determine an optimal buffer size - system_info sinfo; - get_system_info(&sinfo); - size_t freesize = static_cast((sinfo.max_pages - sinfo.used_pages) * B_PAGE_SIZE); - bufsize = freesize / 4; // take 1/4 of RAM max - bufsize -= bufsize % (16 * 1024); // Round to 16 KB boundaries - if (bufsize < kMinBufferSize) // at least kMinBufferSize - bufsize = kMinBufferSize; - else if (bufsize > kMaxBufferSize) // no more than kMaxBufferSize - bufsize = kMaxBufferSize; - } - - BFile destFile(destDir, destName, O_RDWR | O_CREAT); -#ifdef _SILENTLY_CORRECT_FILE_NAMES - if ((destFile.InitCheck() == B_BAD_VALUE || destFile.InitCheck() == B_NOT_ALLOWED) - && CreateFileSystemCompatibleName(destDir, destName)) - destFile.SetTo(destDir, destName, B_CREATE_FILE | B_READ_WRITE); -#endif - - ThrowOnInitCheckError(&destFile); - - node_ref destNodeRef; - destDir->GetNodeRef(&destNodeRef); - // copy or write new pose location as a first thing - SetUpPoseLocation(ref.directory, destNodeRef.node, &srcFile, - &destFile, loc); - - char *buffer = new char[bufsize]; - try { - // copy data portion of file - while (true) { - if (loopControl->CheckUserCanceled()) { - // if copy was canceled, remove partial destination file - destFile.Unset(); - - BEntry destEntry; - if (destDir->FindEntry(destName, &destEntry) == B_OK) - destEntry.Remove(); - - throw (status_t)kCopyCanceled; - } - - ASSERT(buffer); - ssize_t bytes = srcFile.Read(buffer, bufsize); - - if (bytes > 0) { - ssize_t updateBytes = 0; - if (bytes > 32 * 1024) { - // when copying large chunks, update after read and after write - // to get better update granularity - updateBytes = bytes / 2; - loopControl->UpdateStatus(NULL, ref, updateBytes, true); - } - - loopControl->ChecksumChunk(buffer, (size_t)bytes); - - ssize_t result = destFile.Write(buffer, (size_t)bytes); - if (result != bytes) - throw (status_t)B_ERROR; - - loopControl->UpdateStatus(NULL, ref, bytes - updateBytes, true); - } else if (bytes < 0) - // read error - throw (status_t)bytes; - else - // we are done - break; - } - - CopyAttributes(loopControl, &srcFile, &destFile, buffer, bufsize); - } catch (...) { - delete [] buffer; - throw; - } - - destFile.SetPermissions(srcStat->st_mode); - destFile.SetOwner(srcStat->st_uid); - destFile.SetGroup(srcStat->st_gid); - destFile.SetModificationTime(srcStat->st_mtime); - destFile.SetCreationTime(srcStat->st_crtime); - - delete [] buffer; - - if (!loopControl->ChecksumFile(&ref)) { - // File no good. Remove and quit. - destFile.Unset(); - - BEntry destEntry; - if (destDir->FindEntry(destName, &destEntry) == B_OK) - destEntry.Remove(); - throw (status_t)kUserCanceled; - } -} - - -void -CopyAttributes(CopyLoopControl *control, BNode *srcNode, BNode *destNode, void *buffer, - size_t bufsize) -{ - // ToDo: - // Add error checking - // prior to coyping attributes, make sure indices are installed - - // When calling CopyAttributes on files, have to make sure destNode - // is a BFile opened R/W - - srcNode->RewindAttrs(); - char name[256]; - while (srcNode->GetNextAttrName(name) == B_OK) { - // Check to see if this attribute should be skipped. - if (control->SkipAttribute(name)) - continue; - - attr_info info; - if (srcNode->GetAttrInfo(name, &info) != B_OK) - continue; - - // Check to see if this attribute should be overwritten when it - // already exists. - if (control->PreserveAttribute(name)) { - attr_info dest_info; - if (destNode->GetAttrInfo(name, &dest_info) == B_OK) - continue; - } - - // Special case for a size 0 attribute. It wouldn't be written at all - // otherwise. - if (info.size == 0) - destNode->WriteAttr(name, info.type, 0, buffer, 0); - - ssize_t bytes; - ssize_t numToRead = (ssize_t)info.size; - for (off_t offset = 0; numToRead > 0; offset += bytes) { - size_t chunkSize = (size_t)numToRead; - if (chunkSize > bufsize) - chunkSize = bufsize; - - bytes = srcNode->ReadAttr(name, info.type, offset, - buffer, chunkSize); - - if (bytes <= 0) - break; - - destNode->WriteAttr(name, info.type, offset, buffer, (size_t)bytes); - - numToRead -= bytes; - } - } -} - - -static void -CopyFolder(BEntry *srcEntry, BDirectory *destDir, CopyLoopControl *loopControl, - BPoint *loc, bool makeOriginalName, Undo &undo) -{ - BDirectory newDir; - BEntry entry; - status_t err = B_OK; - bool createDirectory = true; - BEntry existingEntry; - - if (loopControl->SkipEntry(srcEntry, false)) - return; - - entry_ref ref; - srcEntry->GetRef(&ref); - - char destName[B_FILE_NAME_LENGTH]; - strcpy(destName, ref.name); - - loopControl->UpdateStatus(ref.name, ref, 1024, true); - - if (makeOriginalName) { - FSMakeOriginalName(destName, destDir, " copy"); - undo.UpdateEntry(srcEntry, destName); - } - - if (destDir->FindEntry(destName, &existingEntry) == B_OK) { - // some entry with a conflicting name is already present in destDir - // decide what to do about it - bool isDirectory = existingEntry.IsDirectory(); - - switch (loopControl->OverwriteOnConflict(srcEntry, destName, destDir, - true, isDirectory)) { - case TrackerCopyLoopControl::kSkip: - // we are about to ignore this entire directory - return; - - case TrackerCopyLoopControl::kReplace: - if (isDirectory) - // remove existing folder recursively - ThrowOnError(FSDeleteFolder(&existingEntry, loopControl, false)); - - else - // conflicting with a file or symbolic link, remove entry - ThrowOnError(existingEntry.Remove()); - break; - - case TrackerCopyLoopControl::kMerge: - ASSERT(isDirectory); - // do not create a new directory, use the current one - newDir.SetTo(&existingEntry); - createDirectory = false; - break; - } - } - - // loop through everything in src folder and copy it to new folder - BDirectory srcDir(srcEntry); - srcDir.Rewind(); - srcEntry->Unset(); - - // create a new folder inside of destination folder - if (createDirectory) { - err = destDir->CreateDirectory(destName, &newDir); -#ifdef _SILENTLY_CORRECT_FILE_NAMES - if (err == B_BAD_VALUE) { - // check if it's an invalid name on a FAT32 file system - if (CreateFileSystemCompatibleName(destDir, destName)) - err = destDir->CreateDirectory(destName, &newDir); - } -#endif - if (err != B_OK) { - if (!loopControl->FileError(kFolderErrorString, destName, err, true)) - throw err; - - // will allow rest of copy to continue - return; - } - } - - char *buffer; - if (createDirectory && err == B_OK && (buffer = (char*)malloc(32768)) != 0) { - CopyAttributes(loopControl, &srcDir, &newDir, buffer, 32768); - // don't copy original pose location if new location passed - free(buffer); - } - - StatStruct statbuf; - srcDir.GetStat(&statbuf); - dev_t sourceDeviceID = statbuf.st_dev; - - // copy or write new pose location - node_ref destNodeRef; - destDir->GetNodeRef(&destNodeRef); - SetUpPoseLocation(ref.directory, destNodeRef.node, &srcDir, - &newDir, loc); - - while (srcDir.GetNextEntry(&entry) == B_OK) { - - if (loopControl->CheckUserCanceled()) - throw (status_t)kUserCanceled; - - entry.GetStat(&statbuf); - - if (S_ISDIR(statbuf.st_mode)) { - - // entry is a mount point, do not copy it - if (statbuf.st_dev != sourceDeviceID) { - PRINT(("Avoiding mount point %d, %d \n", statbuf.st_dev, sourceDeviceID)); - continue; - } - - CopyFolder(&entry, &newDir, loopControl, 0, false, undo); - } else - CopyFile(&entry, &statbuf, &newDir, loopControl, 0, false, undo); - } -} - - -status_t -MoveItem(BEntry *entry, BDirectory *destDir, BPoint *loc, uint32 moveMode, - const char *newName, Undo &undo) -{ - entry_ref ref; - try { - node_ref destNode; - StatStruct statbuf; - - MoveError::FailOnError(entry->GetStat(&statbuf)); - MoveError::FailOnError(entry->GetRef(&ref)); - MoveError::FailOnError(destDir->GetNodeRef(&destNode)); - - if (moveMode == kCreateLink || moveMode == kCreateRelativeLink) { - PoseInfo poseInfo; - char name[B_FILE_NAME_LENGTH]; - strcpy(name, ref.name); - - BSymLink link; - FSMakeOriginalName(name, destDir, " link"); - undo.UpdateEntry(entry, name); - - BPath path; - entry->GetPath(&path); - if (loc && loc != (BPoint *)-1) { - poseInfo.fInvisible = false; - poseInfo.fInitedDirectory = destNode.node; - poseInfo.fLocation = *loc; - } - - status_t err = B_ERROR; - - if (moveMode == kCreateRelativeLink) { - if (statbuf.st_dev == destNode.device) { - // relative link only works on the same device - char oldwd[B_PATH_NAME_LENGTH]; - getcwd(oldwd, B_PATH_NAME_LENGTH); - - BEntry destEntry; - destDir -> GetEntry(&destEntry); - BPath destPath; - destEntry.GetPath(&destPath); - - chdir(destPath.Path()); - // change working dir to target dir - - BString destString(destPath.Path()); - destString.Append("/"); - - BString srcString(path.Path()); - srcString.RemoveLast(path.Leaf()); - - // find index while paths are the same - - const char *src = srcString.String(); - const char *dest = destString.String(); - const char *lastFolderSrc = src; - const char *lastFolderDest = dest; - - while (*src && *dest && *src == *dest) { - ++src; - if (*dest++ == '/') { - lastFolderSrc = src; - lastFolderDest = dest; - } - } - src = lastFolderSrc; - dest = lastFolderDest; - - BString source; - if (*dest == '\0' && *src != '\0') { - // source is deeper in the same tree than the target - source.Append(src); - } else if (*dest != '\0') { - // target is deeper in the same tree than the source - while (*dest) { - if (*dest == '/') - source.Prepend("../"); - ++dest; - } - source.Append(src); - } - - // else source and target are in the same dir - - source.Append(path.Leaf()); - err = destDir->CreateSymLink(name, source.String(), &link); - - chdir(oldwd); - // change working dir back to original - } else - moveMode = kCreateLink; - // fall back to absolute link mode - } - - if (moveMode == kCreateLink) - err = destDir->CreateSymLink(name, path.Path(), &link); - - if (err == B_UNSUPPORTED) - throw FailWithAlert(err, "The target disk does not support creating links.", NULL); - - FailWithAlert::FailOnError(err, "Error creating link to \"%s\".", ref.name); - - if (loc && loc != (BPoint *)-1) - link.WriteAttr(kAttrPoseInfo, B_RAW_TYPE, 0, &poseInfo, sizeof(PoseInfo)); - - BNodeInfo nodeInfo(&link); - nodeInfo.SetType(B_LINK_MIMETYPE); - return B_OK; - } - - // if move is on same volume don't copy - if (statbuf.st_dev == destNode.device && moveMode != kCopySelectionTo - && moveMode != kDuplicateSelection) { - - // for "Move" the size for status is always 1 - since file - // size is irrelevant when simply moving to a new folder - - thread_id thread = find_thread(NULL); - if (gStatusWindow && gStatusWindow->HasStatus(thread)) - gStatusWindow->UpdateStatus(thread, ref.name, 1); - - MoveError::FailOnError(entry->MoveTo(destDir, newName)); - } else { - TrackerCopyLoopControl loopControl(find_thread(NULL)); - - bool makeOriginalName = (moveMode == kDuplicateSelection); - if (S_ISDIR(statbuf.st_mode)) - CopyFolder(entry, destDir, &loopControl, loc, makeOriginalName, undo); - else - CopyFile(entry, &statbuf, destDir, &loopControl, loc, makeOriginalName, undo); - } - } catch (status_t error) { - // no alert, was already taken care of before - return error; - } catch (MoveError error) { - BString errorString; - errorString << "Error moving \"" << ref.name << '"'; - (new BAlert("", errorString.String(), "OK", 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return error.fError; - } catch (FailWithAlert error) { - char buffer[256]; - if (error.fName) - sprintf(buffer, error.fString, error.fName); - else - strcpy(buffer, error.fString); - (new BAlert("", buffer, "OK", 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - - return error.fError; - } - - return B_OK; -} - - -void -FSDuplicate(BObjectList *srcList, BList *pointList) -{ - LaunchInNewThread("DupTask", B_NORMAL_PRIORITY, MoveTask, srcList, (BEntry *)NULL, - pointList, kDuplicateSelection); -} - - -status_t -FSCopyFolder(BEntry *srcEntry, BDirectory *destDir, CopyLoopControl *loopControl, - BPoint *loc, bool makeOriginalName, Undo &undo) -{ - try { - CopyFolder(srcEntry, destDir, loopControl, loc, makeOriginalName, undo); - } catch (status_t error) { - return error; - } - - return B_OK; -} - - -status_t -FSCopyAttributesAndStats(BNode *srcNode, BNode *destNode) -{ - char *buffer = new char[1024]; - - // copy the attributes - srcNode->RewindAttrs(); - char name[256]; - while (srcNode->GetNextAttrName(name) == B_OK) { - attr_info info; - if (srcNode->GetAttrInfo(name, &info) != B_OK) - continue; - - attr_info dest_info; - if (destNode->GetAttrInfo(name, &dest_info) == B_OK) - continue; - - ssize_t bytes; - ssize_t numToRead = (ssize_t)info.size; - for (off_t offset = 0; numToRead > 0; offset += bytes) { - size_t chunkSize = (size_t)numToRead; - if (chunkSize > 1024) - chunkSize = 1024; - - bytes = srcNode->ReadAttr(name, info.type, offset, buffer, chunkSize); - - if (bytes <= 0) - break; - - destNode->WriteAttr(name, info.type, offset, buffer, (size_t)bytes); - - numToRead -= bytes; - } - } - delete[] buffer; - - // copy the file stats - struct stat srcStat; - srcNode->GetStat(&srcStat); - destNode->SetPermissions(srcStat.st_mode); - destNode->SetOwner(srcStat.st_uid); - destNode->SetGroup(srcStat.st_gid); - destNode->SetModificationTime(srcStat.st_mtime); - destNode->SetCreationTime(srcStat.st_crtime); - - return B_OK; -} - - -status_t -FSCopyFile(BEntry* srcFile, StatStruct *srcStat, BDirectory* destDir, - CopyLoopControl *loopControl, BPoint *loc, bool makeOriginalName, Undo &undo) -{ - try { - CopyFile(srcFile, srcStat, destDir, loopControl, loc, makeOriginalName, undo); - } catch (status_t error) { - return error; - } - - return B_OK; -} - - -static status_t -MoveEntryToTrash(BEntry *entry, BPoint *loc, Undo &undo) -{ - BDirectory trash_dir; - entry_ref ref; - status_t result = entry->GetRef(&ref); - if (result != B_OK) - return result; - - node_ref nodeRef; - result = entry->GetNodeRef(&nodeRef); - if (result != B_OK) - return result; - - StatStruct statbuf; - result = entry->GetStat(&statbuf); - if (entry->GetStat(&statbuf) != B_OK) - return result; - - // if it's a directory close the window and any child dir windows - if (S_ISDIR(statbuf.st_mode)) { - BDirectory dir(entry); - - // if it's a volume, try to unmount - if (dir.IsRootDirectory()) { - BVolume volume(nodeRef.device); - BVolume boot; - - BVolumeRoster().GetBootVolume(&boot); - if (volume == boot) { - char name[B_FILE_NAME_LENGTH]; - volume.GetName(name); - char buffer[256]; - sprintf(buffer, "Cannot unmount the boot volume \"%s\".", name); - (new BAlert("", buffer, "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - } else { - BMessage message(kUnmountVolume); - message.AddInt32("device_id", volume.Device()); - be_app->PostMessage(&message); - } - return B_OK; - } - - // get trash directory on same volume as item being moved - result = FSGetTrashDir(&trash_dir, nodeRef.device); - if (result != B_OK) - return result; - - // check hierarchy before moving - BEntry trashEntry; - trash_dir.GetEntry(&trashEntry); - - if (dir == trash_dir || dir.Contains(&trashEntry)) { - (new BAlert("", "You cannot put the Trash, home or Desktop " - "directory into the trash.", "OK", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - - // return no error so we don't get two dialogs - return B_OK; - } - - BMessage message(kCloseWindowAndChildren); - - node_ref parentNode; - parentNode.device = statbuf.st_dev; - parentNode.node = statbuf.st_ino; - message.AddData("node_ref", B_RAW_TYPE, &parentNode, sizeof(node_ref)); - be_app->PostMessage(&message); - } else { - // get trash directory on same volume as item being moved - result = FSGetTrashDir(&trash_dir, nodeRef.device); - if (result != B_OK) - return result; - } - - // make sure name doesn't conflict with anything in trash already - char name[B_FILE_NAME_LENGTH]; - strcpy(name, ref.name); - if (trash_dir.Contains(name)) { - FSMakeOriginalName(name, &trash_dir, " copy"); - undo.UpdateEntry(entry, name); - } - - BNode *src_node = 0; - if (loc && loc != (BPoint *)-1 - && (src_node = GetWritableNode(entry, &statbuf)) != 0) { - trash_dir.GetStat(&statbuf); - PoseInfo poseInfo; - poseInfo.fInvisible = false; - poseInfo.fInitedDirectory = statbuf.st_ino; - poseInfo.fLocation = *loc; - src_node->WriteAttr(kAttrPoseInfo, B_RAW_TYPE, 0, &poseInfo, - sizeof(poseInfo)); - delete src_node; - } - - BNode node(entry); - BPath path; - // Get path of entry before it's moved to the trash - // and write it to the file as an attribute - if (node.InitCheck() == B_OK && entry->GetPath(&path) == B_OK) { - BString originalPath(path.Path()); - node.WriteAttrString(kAttrOriginalPath, &originalPath); - } - - MoveItem(entry, &trash_dir, loc, kMoveSelectionTo, name, undo); - return B_OK; -} - - -ConflictCheckResult -PreFlightNameCheck(BObjectList *srcList, const BDirectory *destDir, - int32 *collisionCount) -{ - - // count the number of name collisions in dest folder - *collisionCount = 0; - - int32 count = srcList->CountItems(); - for (int32 i = 0; i < count; i++) { - entry_ref *srcRef = srcList->ItemAt(i); - BEntry entry(srcRef); - BDirectory parent; - entry.GetParent(&parent); - - if (parent != *destDir) { - if (destDir->Contains(srcRef->name)) - (*collisionCount)++; - } - } - - // prompt user only if there is more than one collision, otherwise the - // single collision case will be handled as a "Prompt" case by CheckName - if (*collisionCount > 1) { - entry_ref *srcRef = (entry_ref*)srcList->FirstItem(); - - StatStruct statbuf; - destDir->GetStat(&statbuf); - - const char *verb = (srcRef->device == statbuf.st_dev) ? "moving" : "copying"; - char replaceMsg[256]; - sprintf(replaceMsg, kReplaceManyStr, verb, verb); - - switch ((new BAlert("", replaceMsg, "Cancel", "Prompt", "Replace All"))->Go()) { - case 0: - return kCanceled; - - case 1: - // user selected "Prompt" - return kPrompt; - - case 2: - // user selected "Replace All" - return kReplaceAll; - } - } - - return kNoConflicts; -} - - -void -FileStatToString(StatStruct *stat, char *buffer, int32 length) -{ - tm timeData; - localtime_r(&stat->st_mtime, &timeData); - - sprintf(buffer, "\n\t(%Ld bytes, ", stat->st_size); - uint32 pos = strlen(buffer); - strftime(buffer + pos, length - pos,"%b %d %Y, %I:%M:%S %p)", &timeData); -} - - -status_t -CheckName(uint32 moveMode, const BEntry *sourceEntry, const BDirectory *destDir, - bool multipleCollisions, ConflictCheckResult &replaceAll) -{ - if (moveMode == kDuplicateSelection) - // when duplicating, we will never have a conflict - return B_OK; - - // see if item already exists in destination dir - status_t err = B_OK; - char name[B_FILE_NAME_LENGTH]; - sourceEntry->GetName(name); - bool sourceIsDirectory = sourceEntry->IsDirectory(); - - BDirectory srcDirectory; - if (sourceIsDirectory) { - srcDirectory.SetTo(sourceEntry); - BEntry destEntry; - destDir->GetEntry(&destEntry); - - if (moveMode != kCreateLink - && moveMode != kCreateRelativeLink - && (srcDirectory == *destDir || srcDirectory.Contains(&destEntry))) { - (new BAlert("", "You can't move a folder into itself " - "or any of its own sub-folders.", "OK", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return B_ERROR; - } - } - - if (FSIsTrashDir(sourceEntry)) { - (new BAlert("", "You can't move or copy the trash.", - "OK", 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return B_ERROR; - } - - BEntry entry; - if (destDir->FindEntry(name, &entry) != B_OK) - // no conflict, return - return B_OK; - - if (moveMode == kCreateLink || moveMode == kCreateRelativeLink) { - // if we are creating link in the same directory, the conflict will - // be handled later by giving the link a unique name - sourceEntry->GetParent(&srcDirectory); - - if (srcDirectory == *destDir) - return B_OK; - } - - bool destIsDir = entry.IsDirectory(); - // be sure not to replace the parent directory of the item being moved - if (destIsDir) { - BDirectory test_dir(&entry); - if (test_dir.Contains(sourceEntry)) { - (new BAlert("", "You can't replace a folder " - "with one of its sub-folders.", "OK", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return B_ERROR; - } - } - - if (moveMode != kCreateLink - && moveMode != kCreateRelativeLink - && destIsDir != sourceIsDirectory) { - // ensure user isn't trying to replace a file with folder or vice versa - (new BAlert("", sourceIsDirectory - ? "You cannot replace a file with a folder or a symbolic link." - : "You cannot replace a folder or a symbolic link with a file.", - "OK", 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return B_ERROR; - } - - if (replaceAll != kReplaceAll) { - // prompt user to determine whether to replace or not - - char replaceMsg[512]; - - if (moveMode == kCreateLink || moveMode == kCreateRelativeLink) - sprintf(replaceMsg, kSymLinkReplaceStr, name); - else if (sourceEntry->IsDirectory()) - sprintf(replaceMsg, kDirectoryReplaceStr, name, - moveMode == kMoveSelectionTo ? "moving" : "copying"); - else { - char sourceBuffer[96], destBuffer[96]; - StatStruct statBuffer; - - if (!sourceEntry->IsDirectory() && sourceEntry->GetStat(&statBuffer) == B_OK) - FileStatToString(&statBuffer, sourceBuffer, 96); - else - sourceBuffer[0] = '\0'; - - if (!entry.IsDirectory() && entry.GetStat(&statBuffer) == B_OK) - FileStatToString(&statBuffer, destBuffer, 96); - else - destBuffer[0] = '\0'; - - sprintf(replaceMsg, kReplaceStr, name, destBuffer, name, sourceBuffer, - moveMode == kMoveSelectionTo ? "moving" : "copying"); - } - - // special case single collision (don't need Replace All shortcut) - BAlert *alert; - if (multipleCollisions) - alert = new BAlert("", replaceMsg, "Skip", "Replace All", - "Replace"); - else - alert = new BAlert("", replaceMsg, "Cancel", "Replace"); - - switch (alert->Go()) { - case 0: // user selected "Cancel" or "Skip" - replaceAll = kCanceled; - return B_ERROR; - - case 1: // user selected "Replace" or "Replace All" - replaceAll = kReplaceAll; - // doesn't matter which since a single - // collision "Replace" is equivalent to a - // "Replace All" - break; - } - } - - // delete destination item - if (destIsDir) { - TrackerCopyLoopControl loopControl(find_thread(NULL)); - err = FSDeleteFolder(&entry, &loopControl, false); - } else - err = entry.Remove(); - - if (err != B_OK) { - BString error; - error << "There was a problem trying to replace \"" - << name << "\". The item might be open or busy."; - (new BAlert("", error.String(), "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - } - - return err; -} - - -status_t -FSDeleteFolder(BEntry *dir_entry, CopyLoopControl *loopControl, bool update_status, - bool delete_top_dir, bool upateFileNameInStatus) -{ - entry_ref ref; - BEntry entry; - BDirectory dir; - status_t err; - - dir.SetTo(dir_entry); - dir.Rewind(); - - // loop through everything in folder and delete it, skipping trouble files - for (;;) { - if (dir.GetNextEntry(&entry) != B_OK) - break; - - entry.GetRef(&ref); - - if (loopControl->CheckUserCanceled()) - return kTrashCanceled; - - if (entry.IsDirectory()) - err = FSDeleteFolder(&entry, loopControl, update_status, true, - upateFileNameInStatus); - else { - err = entry.Remove(); - if (update_status) - loopControl->UpdateStatus(upateFileNameInStatus ? ref.name : "", ref, 1, true); - } - - if (err == kTrashCanceled) - return kTrashCanceled; - else if (err == B_OK) - dir.Rewind(); - else - loopControl->FileError(kFileDeleteErrorString, ref.name, err, false); - } - - if (loopControl->CheckUserCanceled()) - return kTrashCanceled; - - dir_entry->GetRef(&ref); - - if (update_status && delete_top_dir) - loopControl->UpdateStatus(NULL, ref, 1); - - if (delete_top_dir) - return dir_entry->Remove(); - else - return B_OK; -} - - -void -FSMakeOriginalName(BString &string, const BDirectory *destDir, const char *suffix) -{ - if (!destDir->Contains(string.String())) - return; - - FSMakeOriginalName(string.LockBuffer(B_FILE_NAME_LENGTH), - const_cast(destDir), suffix ? suffix : " copy"); - string.UnlockBuffer(); -} - - -void -FSMakeOriginalName(char *name, BDirectory *destDir, const char *suffix) -{ - char root[B_FILE_NAME_LENGTH]; - char copybase[B_FILE_NAME_LENGTH]; - char temp_name[B_FILE_NAME_LENGTH + 10]; - int32 fnum; - - // is this name already original? - if (!destDir->Contains(name)) - return; - - // Determine if we're copying a 'copy'. This algorithm isn't perfect. - // If you're copying a file whose REAL name ends with 'copy' then - // this method will return " 1", not " copy" - - // However, it will correctly handle file that contain 'copy' - // elsewhere in their name. - - bool copycopy = false; // are we copying a copy? - int32 len = (int32)strlen(name); - char *p = name + len - 1; // get pointer to end os name - - // eat up optional numbers (if were copying " copy 34") - while ((p > name) && isdigit(*p)) - p--; - - // eat up optional spaces - while ((p > name) && isspace(*p)) - p--; - - // now look for the phrase " copy" - if (p > name) { - // p points to the last char of the word. For example, 'y' in 'copy' - - if ((p - 4 > name) && (strncmp(p - 4, suffix, 5) == 0)) { - // we found 'copy' in the right place. - // so truncate after 'copy' - *(p + 1) = '\0'; - copycopy = true; - - // save the 'root' name of the file, for possible later use. - // that is copy everything but trailing " copy". Need to - // NULL terminate after copy - strncpy(root, name, (uint32)((p - name) - 4)); - root[(p - name) - 4] = '\0'; - } - } - - if (!copycopy) { - /* - The name can't be longer than B_FILE_NAME_LENGTH. - The algoritm adds " copy XX" to the name. That's 8 characters. - B_FILE_NAME_LENGTH already accounts for NULL termination so we - don't need to save an extra char at the end. - */ - if (strlen(name) > B_FILE_NAME_LENGTH - 8) { - // name is too long - truncate it! - name[B_FILE_NAME_LENGTH - 8] = '\0'; - } - - strcpy(root, name); // save root name - strcat(name, suffix); - } - - strcpy(copybase, name); - - // if name already exists then add a number - fnum = 1; - strcpy(temp_name, name); - while (destDir->Contains(temp_name)) { - sprintf(temp_name, "%s %ld", copybase, ++fnum); - - if (strlen(temp_name) > (B_FILE_NAME_LENGTH - 1)) { - /* - The name has grown too long. Maybe we just went from - " copy 9" to " copy 10" and that extra - character was too much. The solution is to further - truncate the 'root' name and continue. - ??? should we reset fnum or not ??? - */ - root[strlen(root) - 1] = '\0'; - sprintf(temp_name, "%s%s %ld", root, suffix, fnum); - } - } - - ASSERT((strlen(temp_name) <= (B_FILE_NAME_LENGTH - 1))); - strcpy(name, temp_name); -} - - -status_t -FSRecursiveCalcSize(BInfoWindow *wind, BDirectory *dir, off_t *running_size, - int32 *fileCount, int32 *dirCount) -{ - thread_id tid = find_thread(NULL); - - dir->Rewind(); - BEntry entry; - while (dir->GetNextEntry(&entry) == B_OK) { - - // be sure window hasn't closed - if (wind && wind->StopCalc()) - return B_OK; - - if (gStatusWindow && gStatusWindow->CheckCanceledOrPaused(tid)) - return kUserCanceled; - - StatStruct statbuf; - entry.GetStat(&statbuf); - - if (S_ISDIR(statbuf.st_mode)) { - BDirectory subdir(&entry); - (*dirCount)++; - (*running_size) += 1024; - status_t result; - if ((result = FSRecursiveCalcSize(wind, &subdir, running_size, - fileCount, dirCount)) != B_OK) - return result; - } else { - (*fileCount)++; - (*running_size) += statbuf.st_size + 1024; // Add to compensate - // for attributes. - } - } - return B_OK; -} - - -status_t -CalcItemsAndSize(BObjectList *refList, int32 *totalCount, off_t *totalSize) -{ - int32 fileCount = 0; - int32 dirCount = 0; - - thread_id tid = find_thread(NULL); - - int32 num_items = refList->CountItems(); - for (int32 i = 0; i < num_items; i++) { - entry_ref *ref = refList->ItemAt(i); - BEntry entry(ref); - StatStruct statbuf; - entry.GetStat(&statbuf); - - if (gStatusWindow && gStatusWindow->CheckCanceledOrPaused(tid)) - return kUserCanceled; - - if (S_ISDIR(statbuf.st_mode)) { - BDirectory dir(&entry); - dirCount++; - (*totalSize) += 1024; - status_t result; - if ((result = FSRecursiveCalcSize(NULL, &dir, totalSize, &fileCount, - &dirCount)) != B_OK) - return result; - } else { - fileCount++; - (*totalSize) += statbuf.st_size + 1024; - } - } - - *totalCount += (fileCount + dirCount); - return B_OK; -} - - -status_t -FSGetTrashDir(BDirectory *trash_dir, dev_t dev) -{ - - BVolume volume(dev); - status_t result = volume.InitCheck(); - if (result != B_OK) - return result; - - BPath path; - result = find_directory(B_TRASH_DIRECTORY, &path, true, &volume); - if (result != B_OK) - return result; - - result = trash_dir->SetTo(path.Path()); - if (result != B_OK) - return result; - - // make trash invisible - attr_info a_info; - if (trash_dir->GetAttrInfo(kAttrPoseInfo, &a_info) != B_OK) { - - StatStruct sbuf; - trash_dir->GetStat(&sbuf); - - // move trash to bottom left of main screen initially - BScreen screen(B_MAIN_SCREEN_ID); - BRect scrn_frame = screen.Frame(); - - PoseInfo poseInfo; - poseInfo.fInvisible = false; - poseInfo.fInitedDirectory = sbuf.st_ino; - poseInfo.fLocation = BPoint(scrn_frame.left + 20, scrn_frame.bottom - 60); - trash_dir->WriteAttr(kAttrPoseInfo, B_RAW_TYPE, 0, &poseInfo, - sizeof(PoseInfo)); - } - - return B_OK; -} - - -status_t -FSGetDeskDir(BDirectory *deskDir, dev_t dev) -{ - BVolume volume(dev); - status_t result = volume.InitCheck(); - if (result != B_OK) - return result; - - BPath path; - result = find_directory(B_DESKTOP_DIRECTORY, &path, true, &volume); - if (result != B_OK) - return result; - - result = deskDir->SetTo(path.Path()); - if (result != B_OK) - return result; - - // make desktop fInvisible - PoseInfo poseInfo; - poseInfo.fInvisible = true; - poseInfo.fInitedDirectory = -1LL; - deskDir->WriteAttr(kAttrPoseInfo, B_RAW_TYPE, 0, &poseInfo, sizeof(PoseInfo)); - - size_t size; - const void* data = GetTrackerResources()-> - LoadResource(B_LARGE_ICON_TYPE, kResDeskIcon, &size); - - if (data) - deskDir->WriteAttr(kAttrLargeIcon, B_COLOR_8_BIT_TYPE, 0, data, size); - - data = GetTrackerResources()-> - LoadResource(B_MINI_ICON_TYPE, kResDeskIcon, &size); - - if (data) - deskDir->WriteAttr(kAttrMiniIcon, B_COLOR_8_BIT_TYPE, 0, data, size); - - return B_OK; -} - - -status_t -FSGetBootDeskDir(BDirectory *deskDir) -{ - BVolume bootVol; - BVolumeRoster().GetBootVolume(&bootVol); - BPath path; - - status_t result = find_directory(B_DESKTOP_DIRECTORY, &path, true, &bootVol); - if (result != B_OK) - return result; - - return deskDir->SetTo(path.Path()); -} - - -static bool -FSIsDirFlavor(const BEntry *entry, directory_which directoryType) -{ - StatStruct dir_stat; - StatStruct entry_stat; - BVolume volume; - BPath path; - - if (entry->GetStat(&entry_stat) != B_OK) - return false; - - if (volume.SetTo(entry_stat.st_dev) != B_OK) - return false; - - if (find_directory(directoryType, &path, false, &volume) != B_OK) - return false; - - stat(path.Path(), &dir_stat); - - return dir_stat.st_ino == entry_stat.st_ino - && dir_stat.st_dev == entry_stat.st_dev; -} - - -bool -FSIsPrintersDir(const BEntry *entry) -{ - return FSIsDirFlavor(entry, B_USER_PRINTERS_DIRECTORY); -} - - -bool -FSIsTrashDir(const BEntry *entry) -{ - return FSIsDirFlavor(entry, B_TRASH_DIRECTORY); -} - - -bool -FSIsDeskDir(const BEntry *entry, dev_t device) -{ - BVolume volume(device); - status_t result = volume.InitCheck(); - if (result != B_OK) - return false; - - BPath path; - result = find_directory(B_DESKTOP_DIRECTORY, &path, true, &volume); - if (result != B_OK) - return false; - - BEntry entryToCompare(path.Path()); - return entryToCompare == *entry; -} - - -bool -FSIsDeskDir(const BEntry *entry) -{ - entry_ref ref; - if (entry->GetRef(&ref) != B_OK) - return false; - - return FSIsDeskDir(entry, ref.device); -} - - -bool -FSIsSystemDir(const BEntry *entry) -{ - return FSIsDirFlavor(entry, B_BEOS_SYSTEM_DIRECTORY); -} - - -bool -FSIsBeOSDir(const BEntry *entry) -{ - return FSIsDirFlavor(entry, B_BEOS_DIRECTORY); -} - - -bool -FSIsHomeDir(const BEntry *entry) -{ - return FSIsDirFlavor(entry, B_USER_DIRECTORY); -} - - -bool -DirectoryMatchesOrContains(const BEntry *entry, directory_which which) -{ - BPath path; - if (find_directory(which, &path, false, NULL) != B_OK) - return false; - - BEntry dirEntry(path.Path()); - if (dirEntry.InitCheck() != B_OK) - return false; - - if (dirEntry == *entry) - // root level match - return true; - - BDirectory dir(&dirEntry); - return dir.Contains(entry); -} - - -bool -DirectoryMatchesOrContains(const BEntry *entry, const char *additionalPath, - directory_which which) -{ - BPath path; - if (find_directory(which, &path, false, NULL) != B_OK) - return false; - - path.Append(additionalPath); - BEntry dirEntry(path.Path()); - if (dirEntry.InitCheck() != B_OK) - return false; - - if (dirEntry == *entry) - // root level match - return true; - - BDirectory dir(&dirEntry); - return dir.Contains(entry); -} - - -bool -DirectoryMatches(const BEntry *entry, directory_which which) -{ - BPath path; - if (find_directory(which, &path, false, NULL) != B_OK) - return false; - - BEntry dirEntry(path.Path()); - if (dirEntry.InitCheck() != B_OK) - return false; - - return dirEntry == *entry; -} - - -bool -DirectoryMatches(const BEntry *entry, const char *additionalPath, directory_which which) -{ - BPath path; - if (find_directory(which, &path, false, NULL) != B_OK) - return false; - - path.Append(additionalPath); - BEntry dirEntry(path.Path()); - if (dirEntry.InitCheck() != B_OK) - return false; - - return dirEntry == *entry; -} - - -extern status_t -FSFindTrackerSettingsDir(BPath *path, bool autoCreate) -{ - status_t result = find_directory (B_USER_SETTINGS_DIRECTORY, path, autoCreate); - if (result != B_OK) - return result; - - path->Append("Tracker"); - - return mkdir(path->Path(), 0777) ? B_OK : errno; -} - - -bool -FSInTrashDir(const entry_ref *ref) -{ - BEntry entry(ref); - if (entry.InitCheck() != B_OK) - return false; - - BDirectory trashDir; - if (FSGetTrashDir(&trashDir, ref->device) != B_OK) - return false; - - return trashDir.Contains(&entry); -} - - -void -FSEmptyTrash() -{ - if (find_thread("_tracker_empty_trash_") == B_NAME_NOT_FOUND) - resume_thread(spawn_thread(empty_trash, "_tracker_empty_trash_", - B_NORMAL_PRIORITY, NULL)); -} - - -status_t -empty_trash(void *) -{ - BVolumeRoster roster; - BVolume volume; - BEntry entry; - BDirectory trash_dir; - entry_ref ref; - thread_id tid; - status_t err; - int32 totalCount; - off_t totalSize; - BObjectList srcList; - - // empty trash on all mounted volumes - err = B_OK; - - tid = find_thread(NULL); - if (gStatusWindow) - gStatusWindow->CreateStatusItem(tid, kTrashState); - - // calculate the sum total of all items on all volumes in trash - totalCount = 0; - totalSize = 0; - - roster.Rewind(); - while (roster.GetNextVolume(&volume) == B_OK) { - - if (volume.IsReadOnly() || !volume.IsPersistent()) - continue; - - if (FSGetTrashDir(&trash_dir, volume.Device()) != B_OK) - continue; - - trash_dir.GetEntry(&entry); - entry.GetRef(&ref); - srcList.AddItem(&ref); - err = CalcItemsAndSize(&srcList, &totalCount, &totalSize); - if (err != B_OK) - break; - - srcList.MakeEmpty(); - - // don't count trash directory itself - totalCount--; - } - - if (err == B_OK) { - if (gStatusWindow) - gStatusWindow->InitStatusItem(tid, totalCount, totalCount); - - roster.Rewind(); - while (roster.GetNextVolume(&volume) == B_OK) { - TrackerCopyLoopControl loopControl(tid); - - if (volume.IsReadOnly() || !volume.IsPersistent()) - continue; - - if (FSGetTrashDir(&trash_dir, volume.Device()) != B_OK) - continue; - - trash_dir.GetEntry(&entry); - err = FSDeleteFolder(&entry, &loopControl, true, false); - } - } - - if (err != B_OK && err != kTrashCanceled && err != kUserCanceled) - (new BAlert("", "Error emptying Trash!", "OK", NULL, NULL, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - - if (gStatusWindow) - gStatusWindow->RemoveStatusItem(find_thread(NULL)); - - return B_OK; -} - - -status_t -_DeleteTask(BObjectList *list, bool confirm) -{ - if (confirm) { - bool dontMoveToTrash = TrackerSettings().DontMoveFilesToTrash(); - - if (!dontMoveToTrash) { - BAlert *alert = new BAlert("", kDeleteConfirmationStr, - "Cancel", "Move to Trash", "Delete", B_WIDTH_AS_USUAL, B_OFFSET_SPACING, - B_WARNING_ALERT); - - alert->SetShortcut(0, B_ESCAPE); - alert->SetShortcut(1, 'm'); - alert->SetShortcut(2, 'd'); - - switch (alert->Go()) { - case 0: - delete list; - return B_OK; - case 1: - FSMoveToTrash(list, NULL, false); - return B_OK; - } - } else { - BAlert *alert = new BAlert("", kDeleteConfirmationStr, - "Cancel", "Delete", NULL, B_WIDTH_AS_USUAL, B_OFFSET_SPACING, - B_WARNING_ALERT); - - alert->SetShortcut(0, B_ESCAPE); - alert->SetShortcut(1, 'd'); - - if (!alert->Go()) { - delete list; - return B_OK; - } - } - } - - thread_id thread = find_thread(NULL); - if (gStatusWindow) - gStatusWindow->CreateStatusItem(thread, kDeleteState); - - // calculate the sum total of all items on all volumes in trash - int32 totalItems = 0; - int64 totalSize = 0; - - status_t err = CalcItemsAndSize(list, &totalItems, &totalSize); - if (err == B_OK) { - if (gStatusWindow) - gStatusWindow->InitStatusItem(thread, totalItems, totalItems); - - int32 count = list->CountItems(); - TrackerCopyLoopControl loopControl(thread); - for (int32 index = 0; index < count; index++) { - entry_ref ref(*list->ItemAt(index)); - BEntry entry(&ref); - loopControl.UpdateStatus(ref.name, ref, 1, true); - if (entry.IsDirectory()) - err = FSDeleteFolder(&entry, &loopControl, true, true, true); - else - err = entry.Remove(); - } - - if (err != kTrashCanceled && err != kUserCanceled && err != B_OK) - (new BAlert("", "Error Deleting items", "OK", NULL, NULL, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - } - if (gStatusWindow) - gStatusWindow->RemoveStatusItem(find_thread(NULL)); - - delete list; - - return B_OK; -} - -status_t -FSRecursiveCreateFolder(BPath path) -{ - BEntry entry(path.Path()); - if (entry.InitCheck() != B_OK) { - BPath parentPath; - status_t err = path.GetParent(&parentPath); - if (err != B_OK) - return err; - - err = FSRecursiveCreateFolder(parentPath); - if (err != B_OK) - return err; - } - - entry.SetTo(path.Path()); - if (entry.Exists()) - return B_FILE_EXISTS; - else { - char name[B_FILE_NAME_LENGTH]; - BDirectory parent; - - entry.GetParent(&parent); - entry.GetName(name); - parent.CreateDirectory(name, NULL); - } - - return B_OK; -} - -status_t -_RestoreTask(BObjectList *list) -{ - thread_id thread = find_thread(NULL); - if (gStatusWindow) - gStatusWindow->CreateStatusItem(thread, kRestoreFromTrashState); - - // calculate the sum total of all items that will be restored - int32 totalItems = 0; - int64 totalSize = 0; - - status_t err = CalcItemsAndSize(list, &totalItems, &totalSize); - if (err == B_OK) { - if (gStatusWindow) - gStatusWindow->InitStatusItem(thread, totalItems, totalItems); - - int32 count = list->CountItems(); - TrackerCopyLoopControl loopControl(thread); - for (int32 index = 0; index < count; index++) { - entry_ref ref(*list->ItemAt(index)); - BEntry entry(&ref); - BPath originalPath; - - loopControl.UpdateStatus(ref.name, ref, 1, true); - - if (FSGetOriginalPath(&entry, &originalPath) != B_OK) - continue; - - BEntry originalEntry(originalPath.Path()); - BPath parentPath; - err = originalPath.GetParent(&parentPath); - if (err != B_OK) - continue; - BEntry parentEntry(parentPath.Path()); - - if (parentEntry.InitCheck() != B_OK || !parentEntry.Exists()) { - if (FSRecursiveCreateFolder(parentPath) == B_OK) { - originalEntry.SetTo(originalPath.Path()); - if (entry.InitCheck() != B_OK) - continue; - } - } - - if (!originalEntry.Exists()) { - BDirectory dir(parentPath.Path()); - if (dir.InitCheck() == B_OK) { - char leafName[B_FILE_NAME_LENGTH]; - originalEntry.GetName(leafName); - if (entry.MoveTo(&dir, leafName) == B_OK) { - BNode node(&entry); - if (node.InitCheck() == B_OK) - node.RemoveAttr(kAttrOriginalPath); - } - } - } - - err = loopControl.CheckUserCanceled(); - if (err != B_OK) - break; - } - } - if (gStatusWindow) - gStatusWindow->RemoveStatusItem(find_thread(NULL)); - - delete list; - - return err; -} - -void -FSCreateTrashDirs() -{ - BVolume volume; - BVolumeRoster roster; - - roster.Rewind(); - while (roster.GetNextVolume(&volume) == B_OK) { - - if (volume.IsReadOnly() || !volume.IsPersistent()) - continue; - - BPath path; - find_directory(B_DESKTOP_DIRECTORY, &path, true, &volume); - find_directory(B_TRASH_DIRECTORY, &path, true, &volume); - - BDirectory trashDir; - if (FSGetTrashDir(&trashDir, volume.Device()) == B_OK) { - size_t size; - const void* data = GetTrackerResources()-> - LoadResource(B_LARGE_ICON_TYPE, kResTrashIcon, &size); - if (data) { - trashDir.WriteAttr(kAttrLargeIcon, B_COLOR_8_BIT_TYPE, 0, - data, size); - } - data = GetTrackerResources()-> - LoadResource(B_MINI_ICON_TYPE, kResTrashIcon, &size); - if (data) { - trashDir.WriteAttr(kAttrMiniIcon, B_COLOR_8_BIT_TYPE, 0, - data, size); - } - } - } -} - - -status_t -FSCreateNewFolder(const entry_ref *ref) -{ - node_ref node; - node.device = ref->device; - node.node = ref->directory; - - BDirectory dir(&node); - status_t result = dir.InitCheck(); - if (result != B_OK) - return result; - - // ToDo: is that really necessary here? - BString name(ref->name); - FSMakeOriginalName(name, &dir, "-"); - - BDirectory newDir; - result = dir.CreateDirectory(name.String(), &newDir); - if (result != B_OK) - return result; - - BNodeInfo nodeInfo(&newDir); - nodeInfo.SetType(B_DIR_MIMETYPE); - - return result; -} - - -status_t -FSCreateNewFolderIn(const node_ref *dirNode, entry_ref *newRef, - node_ref *newNode) -{ - BDirectory dir(dirNode); - status_t result = dir.InitCheck(); - if (result == B_OK) { - char name[B_FILE_NAME_LENGTH]; - strcpy(name, "New Folder"); - - int32 fnum = 1; - while (dir.Contains(name)) { - // if base name already exists then add a number - // ToDo: - // move this logic ot FSMakeOriginalName - if (++fnum > 9) - sprintf(name, "New Folder%ld", fnum); - else - sprintf(name, "New Folder %ld", fnum); - } - - BDirectory newDir; - result = dir.CreateDirectory(name, &newDir); - if (result == B_OK) { - BEntry entry; - newDir.GetEntry(&entry); - entry.GetRef(newRef); - entry.GetNodeRef(newNode); - - BNodeInfo nodeInfo(&newDir); - nodeInfo.SetType(B_DIR_MIMETYPE); - - // add undo item - NewFolderUndo undo(*newRef); - return B_OK; - } - } - - (new BAlert("", "Sorry, could not create a new folder.", "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - return result; -} - - -ReadAttrResult -ReadAttr(const BNode *node, const char *hostAttrName, const char *foreignAttrName, - type_code type, off_t offset, void *buffer, size_t length, - void (*swapFunc)(void *), bool isForeign) -{ - if (!isForeign && node->ReadAttr(hostAttrName, type, offset, buffer, length) == (ssize_t)length) - return kReadAttrNativeOK; - - // PRINT(("trying %s\n", foreignAttrName)); - // try the other endianness - if (node->ReadAttr(foreignAttrName, type, offset, buffer, length) != (ssize_t)length) - return kReadAttrFailed; - - // PRINT(("got %s\n", foreignAttrName)); - if (!swapFunc) - return kReadAttrForeignOK; - - (swapFunc)(buffer); - // run the endian swapper - - return kReadAttrForeignOK; -} - - -ReadAttrResult -GetAttrInfo(const BNode *node, const char *hostAttrName, const char *foreignAttrName, - type_code *type, size_t *size) -{ - attr_info info; - - if (node->GetAttrInfo(hostAttrName, &info) == B_OK) { - if (type) - *type = info.type; - if (size) - *size = (size_t)info.size; - - return kReadAttrNativeOK; - } - - if (node->GetAttrInfo(foreignAttrName, &info) == B_OK) { - if (type) - *type = info.type; - if (size) - *size = (size_t)info.size; - - return kReadAttrForeignOK; - } - return kReadAttrFailed; -} - -// launching code - -static status_t -TrackerOpenWith(const BMessage *refs) -{ - BMessage clone(*refs); - ASSERT(dynamic_cast(be_app)); - ASSERT(clone.what); - clone.AddInt32("launchUsingSelector", 0); - // runs the Open With window - be_app->PostMessage(&clone); - - return B_OK; -} - -static void -AsynchLaunchBinder(void (*func)(const entry_ref *, const BMessage *, bool on), - const entry_ref *entry, const BMessage *message, bool on) -{ - Thread::Launch(NewFunctionObject(func, entry, message, on), - B_NORMAL_PRIORITY, "LaunchTask"); -} - -static bool -SniffIfGeneric(const entry_ref *ref) -{ - BNode node(ref); - char type[B_MIME_TYPE_LENGTH]; - BNodeInfo info(&node); - if (info.GetType(type) == B_OK && strcasecmp(type, B_FILE_MIME_TYPE) != 0) - // already has a type and it's not octet stream - return false; - - BPath path(ref); - if (path.Path()) { - // force a mimeset - node.RemoveAttr(kAttrMIMEType); - update_mime_info(path.Path(), 0, 1, 1); - } - - return true; -} - -static void -SniffIfGeneric(const BMessage *refs) -{ - entry_ref ref; - for (int32 index = 0; ; index++) { - if (refs->FindRef("refs", index, &ref) != B_OK) - break; - SniffIfGeneric(&ref); - } -} - -static void -_TrackerLaunchAppWithDocuments(const entry_ref *appRef, const BMessage *refs, bool openWithOK) -{ - team_id team; - - status_t error = B_ERROR; - BString alertString; - - for (int32 mimesetIt = 0; ; mimesetIt++) { - error = be_roster->Launch(appRef, refs, &team); - if (error == B_ALREADY_RUNNING) - // app already running, not really an error - error = B_OK; - - if (error == B_OK) - break; - - if (mimesetIt > 0) - break; - - // failed to open, try mimesetting the refs and launching again - SniffIfGeneric(refs); - } - - if (error == B_OK) { - // close possible parent window, if specified - const node_ref *nodeToClose = 0; - int32 numBytes; - refs->FindData("nodeRefsToClose", B_RAW_TYPE, (const void **)&nodeToClose, &numBytes); - if (nodeToClose) - dynamic_cast(be_app)->CloseParent(*nodeToClose); - } else { - alertString << "Could not open \"" << appRef->name << "\" (" << strerror(error) << "). "; - if (refs && openWithOK) { - alertString << kFindAlternativeStr; - if ((new BAlert("", alertString.String(), "Cancel", "Find", 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go() == 1) - error = TrackerOpenWith(refs); - } else - (new BAlert("", alertString.String(), "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - } -} - -extern "C" char** environ; -extern "C" status_t _kload_image_etc_(int argc, char **argv, char **envp, - char *buf, int bufsize); - - -static status_t -LoaderErrorDetails(const entry_ref *app, BString &details) -{ - BPath path; - BEntry appEntry(app, true); - status_t result = appEntry.GetPath(&path); - - if (result != B_OK) - return result; - - char *argv[2] = { const_cast(path.Path()), 0}; - -#ifdef __HAIKU__ - // ToDo: do this correctly! - result = load_image(1, (const char **)argv, (const char **)environ); - details.SetTo("ToDo: this is missing from Haiku"); -#else - result = _kload_image_etc_(1, argv, environ, details.LockBuffer(1024), 1024); - details.UnlockBuffer(); -#endif - return B_OK; -} - - -static void -_TrackerLaunchDocuments(const entry_ref */*doNotUse*/, const BMessage *refs, - bool openWithOK) -{ - BMessage copyOfRefs(*refs); - - entry_ref documentRef; - if (copyOfRefs.FindRef("refs", &documentRef) != B_OK) - // nothing to launch, we are done - return; - - status_t error = B_ERROR; - entry_ref app; - BMessage *refsToPass = NULL; - BString alertString; - const char *alternative = 0; - - for (int32 mimesetIt = 0; ; mimesetIt++) { - alertString = ""; - error = be_roster->FindApp(&documentRef, &app); - - if (error != B_OK && mimesetIt == 0) { - SniffIfGeneric(©OfRefs); - continue; - } - - if (error != B_OK) { - alertString << "Could not find an application to open \"" << documentRef.name - << "\" (" << strerror(error) << "). "; - if (openWithOK) - alternative = kFindApplicationStr; - - break; - } else { - BEntry appEntry(&app, true); - for (int32 index = 0;;) { - // remove the app itself from the refs received so we don't try - // to open ourselves - entry_ref ref; - if (copyOfRefs.FindRef("refs", index, &ref) != B_OK) - break; - - // deal with symlinks properly - BEntry documentEntry(&ref, true); - if (appEntry == documentEntry) { - PRINT(("stripping %s, app %s \n", ref.name, app.name)); - copyOfRefs.RemoveData("refs", index); - } else { - PRINT(("leaving %s, app %s \n", ref.name, app.name)); - index++; - } - } - - refsToPass = CountRefs(©OfRefs) > 0 ? ©OfRefs: 0; - team_id team; - error = be_roster->Launch(&app, refsToPass, &team); - if (error == B_ALREADY_RUNNING) - // app already running, not really an error - error = B_OK; - if (error == B_OK || mimesetIt != 0) - break; - - SniffIfGeneric(©OfRefs); - } - } - - if (error != B_OK && alertString.Length() == 0) { - BString loaderErrorString; - bool openedDocuments = true; - - if (!refsToPass) { - // we just double clicked the app itself, do not offer to - // find a handling app - openWithOK = false; - openedDocuments = false; - } - - if (error == B_LAUNCH_FAILED_EXECUTABLE && !refsToPass) { - alertString << "Could not open \"" << app.name - << "\". The file is mistakenly marked as executable. "; - - if (!openWithOK) { - // offer the possibility to change the permissions - - alertString << "\nShould this be fixed?"; - if ((new BAlert("", alertString.String(), "Cancel", "Proceed", 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go() == 1) { - BEntry entry(&documentRef); - mode_t permissions; - - error = entry.GetPermissions(&permissions); - if (error == B_OK) - error = entry.SetPermissions(permissions & ~(S_IXUSR | S_IXGRP | S_IXOTH)); - if (error == B_OK) { - // we updated the permissions, so let's try again - _TrackerLaunchDocuments(NULL, refs, false); - return; - } else { - alertString = "Could not update permissions of file \""; - alertString << app.name << "\". " << strerror(error); - } - } else - return; - } - - alternative = kFindApplicationStr; - } else if (error == B_LAUNCH_FAILED_APP_IN_TRASH) { - alertString << "Could not open \"" << documentRef.name - << "\" because application \"" << app.name << "\" is in the trash. "; - alternative = kFindAlternativeStr; - } else if (error == B_LAUNCH_FAILED_APP_NOT_FOUND) { - alertString << "Could not open \"" << documentRef.name << "\" " - << "(" << strerror(error) << "). "; - alternative = kFindAlternativeStr; - } else if (error == B_MISSING_SYMBOL - && LoaderErrorDetails(&app, loaderErrorString) == B_OK) { - alertString << "Could not open \"" << documentRef.name << "\" "; - if (openedDocuments) - alertString << "with application \"" << app.name << "\" "; - alertString << "(Missing symbol: " << loaderErrorString << "). \n"; - alternative = kFindAlternativeStr; - } else if (error == B_MISSING_LIBRARY - && LoaderErrorDetails(&app, loaderErrorString) == B_OK) { - alertString << "Could not open \"" << documentRef.name << "\" "; - if (openedDocuments) - alertString << "with application \"" << app.name << "\" "; - alertString << "(Missing library: " << loaderErrorString << "). \n"; - alternative = kFindAlternativeStr; - } else { - alertString << "Could not open \"" << documentRef.name - << "\" with application \"" << app.name << "\" (" << strerror(error) << "). "; - alternative = kFindAlternativeStr; - } - } - - if (error != B_OK) { - if (openWithOK) { - ASSERT(alternative); - alertString << alternative; - if ((new BAlert("", alertString.String(), "Cancel", "Find", 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go() == 1) - error = TrackerOpenWith(refs); - } else - (new BAlert("", alertString.String(), "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); - } -} - -// the following three calls don't return any reasonable error codes, -// should fix that, making them void - -status_t -TrackerLaunch(const entry_ref *appRef, const BMessage *refs, bool async, bool openWithOK) -{ - if (!async) - _TrackerLaunchAppWithDocuments(appRef, refs, openWithOK); - else - AsynchLaunchBinder(&_TrackerLaunchAppWithDocuments, appRef, refs, openWithOK); - - return B_OK; -} - -status_t -TrackerLaunch(const entry_ref *appRef, bool async) -{ - if (!async) - _TrackerLaunchAppWithDocuments(appRef, 0, false); - else - AsynchLaunchBinder(&_TrackerLaunchAppWithDocuments, appRef, 0, false); - - return B_OK; -} - -status_t -TrackerLaunch(const BMessage *refs, bool async, bool openWithOK) -{ - if (!async) - _TrackerLaunchDocuments(0, refs, openWithOK); - else - AsynchLaunchBinder(&_TrackerLaunchDocuments, 0, refs, openWithOK); - - return B_OK; -} - -status_t -LaunchBrokenLink(const char *signature, const BMessage *refs) -{ - // This call is to support a hacky workaround for double-clicking - // broken refs for cifs - be_roster->Launch(signature, const_cast(refs)); - return B_OK; -} - -// external launch calls; need to be robust, work if Tracker is not running - -status_t -FSLaunchItem(const entry_ref *application, const BMessage *refsReceived, - bool async, bool openWithOK) -{ - return TrackerLaunch(application, refsReceived, async, openWithOK); -} - - -status_t -FSOpenWith(BMessage *listOfRefs) -{ - status_t result = B_ERROR; - listOfRefs->what = B_REFS_RECEIVED; - - if (dynamic_cast(be_app)) - result = TrackerOpenWith(listOfRefs); - else - ASSERT(!"not yet implemented"); - - return result; -} - -// legacy calls, need for compatibility - -void -FSOpenWithDocuments(const entry_ref *executable, BMessage *documents) -{ - TrackerLaunch(executable, documents, true); - delete documents; -} - -status_t -FSLaunchUsing(const entry_ref *ref, BMessage *listOfRefs) -{ - BMessage temp(B_REFS_RECEIVED); - if (!listOfRefs) { - ASSERT(ref); - temp.AddRef("refs", ref); - listOfRefs = &temp; - } - FSOpenWith(listOfRefs); - return B_OK; -} - -status_t -FSLaunchItem(const entry_ref *ref, BMessage* message, int32, bool async) -{ - if (message) - message->what = B_REFS_RECEIVED; - - status_t result = TrackerLaunch(ref, message, async, true); - delete message; - return result; -} - - -void -FSLaunchItem(const entry_ref *ref, BMessage *message, int32 workspace) -{ - FSLaunchItem(ref, message, workspace, true); -} - -// Get the original path of an entry in the trash -status_t -FSGetOriginalPath(BEntry *entry, BPath *result) -{ - status_t err; - entry_ref ref; - err = entry->GetRef(&ref); - if (err != B_OK) - return err; - - // Only call the routine for entries in the trash - if (!FSInTrashDir(&ref)) - return B_ERROR; - - BNode node(entry); - BString originalPath; - if (node.ReadAttrString(kAttrOriginalPath, &originalPath) == B_OK) { - // We're in luck, the entry has the original path in an attribute - err = result->SetTo(originalPath.String()); - return err; - } - - // Iterate the parent directories to find one with - // the original path attribute - BEntry parent(*entry); - err = parent.InitCheck(); - if (err != B_OK) - return err; - - // walk up the directory structure until we find a node - // with original path attribute - do { - // move to the parent of this node - err = parent.GetParent(&parent); - if (err != B_OK) - return err; - - // return if we are at the root of the trash - if (FSIsTrashDir(&parent)) - return B_ENTRY_NOT_FOUND; - - // get the parent as a node - err = node.SetTo(&parent); - if (err != B_OK) - return err; - } while (node.ReadAttrString(kAttrOriginalPath, &originalPath) != B_OK); - - // Found the attribute, figure out there this file - // used to live, based on the successfully-read attribute - err = result->SetTo(originalPath.String()); - if (err != B_OK) - return err; - - BPath path, pathParent; - err = parent.GetPath(&pathParent); - if (err != B_OK) - return err; - err = entry->GetPath(&path); - if (err != B_OK) - return err; - result->Append(path.Path() + strlen(pathParent.Path()) + 1); - // compute the new path by appending the offset of - // the item we are locating, to the original path - // of the parent - return B_OK; -} - -directory_which -WellKnowEntryList::Match(const node_ref *node) -{ - const WellKnownEntry *result = MatchEntry(node); - if (result) - return result->which; - - return (directory_which)-1; -} - -const WellKnowEntryList::WellKnownEntry * -WellKnowEntryList::MatchEntry(const node_ref *node) -{ - if (!self) - self = new WellKnowEntryList(); - - return self->MatchEntryCommon(node); -} - -const WellKnowEntryList::WellKnownEntry * -WellKnowEntryList::MatchEntryCommon(const node_ref *node) -{ - uint32 count = entries.size(); - for (uint32 index = 0; index < count; index++) - if (*node == entries[index].node) - return &entries[index]; - - return NULL; -} - - -void -WellKnowEntryList::Quit() -{ - delete self; - self = NULL; -} - -void -WellKnowEntryList::AddOne(directory_which which, const char *name) -{ - BPath path; - if (find_directory(which, &path, true) != B_OK) - return; - - BEntry entry(path.Path()); - node_ref node; - if (entry.GetNodeRef(&node) != B_OK) - return; - - entries.push_back(WellKnownEntry(&node, which, name)); -} - -void -WellKnowEntryList::AddOne(directory_which which, directory_which base, - const char *extra, const char *name) -{ - BPath path; - if (find_directory(base, &path, true) != B_OK) - return; - - path.Append(extra); - BEntry entry(path.Path()); - node_ref node; - if (entry.GetNodeRef(&node) != B_OK) - return; - - entries.push_back(WellKnownEntry(&node, which, name)); -} - -void -WellKnowEntryList::AddOne(directory_which which, const char *path, const char *name) -{ - BEntry entry(path); - node_ref node; - if (entry.GetNodeRef(&node) != B_OK) - return; - - entries.push_back(WellKnownEntry(&node, which, name)); -} - - -WellKnowEntryList::WellKnowEntryList() -{ - AddOne(B_BEOS_DIRECTORY, "beos"); - AddOne((directory_which)B_BOOT_DISK, "/boot", "boot"); - AddOne(B_USER_DIRECTORY, "home"); - AddOne(B_BEOS_SYSTEM_DIRECTORY, "system"); - - AddOne(B_BEOS_FONTS_DIRECTORY, "fonts"); - AddOne(B_COMMON_FONTS_DIRECTORY, "fonts"); - AddOne(B_USER_FONTS_DIRECTORY, "fonts"); - - AddOne(B_BEOS_APPS_DIRECTORY, "apps"); - AddOne(B_APPS_DIRECTORY, "apps"); - AddOne((directory_which)B_USER_DESKBAR_APPS_DIRECTORY, B_USER_DESKBAR_DIRECTORY, - "Applications", "apps"); - - AddOne(B_BEOS_PREFERENCES_DIRECTORY, "preferences"); - AddOne(B_PREFERENCES_DIRECTORY, "preferences"); - AddOne((directory_which)B_USER_DESKBAR_PREFERENCES_DIRECTORY, B_USER_DESKBAR_DIRECTORY, - "Preferences", "preferences"); - - AddOne((directory_which)B_USER_MAIL_DIRECTORY, B_USER_DIRECTORY, "mail", "mail"); - - AddOne((directory_which)B_USER_QUERIES_DIRECTORY, B_USER_DIRECTORY, "queries", "queries"); - - - - AddOne(B_COMMON_DEVELOP_DIRECTORY, "develop"); - AddOne((directory_which)B_USER_DESKBAR_DEVELOP_DIRECTORY, B_USER_DESKBAR_DIRECTORY, - "Development", "develop"); - - AddOne(B_USER_CONFIG_DIRECTORY, "config"); - - AddOne((directory_which)B_USER_PEOPLE_DIRECTORY, B_USER_DIRECTORY, "people", "people"); - - AddOne((directory_which)B_USER_DOWNLOADS_DIRECTORY, B_USER_DIRECTORY, "Downloads", - "Downloads"); -} - -WellKnowEntryList *WellKnowEntryList::self = NULL; - -} diff --git a/src/apps/installer/FSUtils.h b/src/apps/installer/FSUtils.h deleted file mode 100644 index f5a88f24ea..0000000000 --- a/src/apps/installer/FSUtils.h +++ /dev/null @@ -1,312 +0,0 @@ -/* -Open Tracker License - -Terms and Conditions - -Copyright (c) 1991-2000, Be Incorporated. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice applies to all licensees -and shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Be Incorporated shall not be -used in advertising or otherwise to promote the sale, use or other dealings in -this Software without prior written authorization from Be Incorporated. - -Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks -of Be Incorporated in the United States and other countries. Other brand product -names are registered trademarks or trademarks of their respective holders. -All rights reserved. -*/ - -#ifndef FS_UTILS_H -#define FS_UTILS_H - -#include -#include -#include -#include - -#include - -#include "Model.h" -#include "ObjectList.h" - -// Note - APIs/code in FSUtils.h and FSUtils.cpp is slated for a major cleanup -// -- in other words, you will find a lot of ugly cruft in here - -class BDirectory; -class BEntry; -class BList; -class BFile; - -namespace BPrivate { - -class BInfoWindow; - -class CopyLoopControl { - // controls the copy engine; may be overriden to specify how conflicts are - // handled, etc. - // Installer has it's own subclass - public: - virtual ~CopyLoopControl(); - virtual bool FileError(const char *message, const char *name, status_t error, - bool allowContinue) = 0; - // inform that a file error occurred while copying - // returns true if user decided to continue - - virtual void UpdateStatus(const char *name, entry_ref ref, int32 count, - bool optional = false) = 0; - - virtual bool CheckUserCanceled() = 0; - // returns true if canceled - - enum OverwriteMode { - kSkip, // do not replace, go to next entry - kReplace, // remove entry before copying new one - kMerge // for folders: leave existing folder, update contents leaving - // nonconflicting items - // for files: save original attributes on file. - }; - - virtual OverwriteMode OverwriteOnConflict(const BEntry *srcEntry, - const char *destName, const BDirectory *destDir, bool srcIsDir, - bool dstIsDir) = 0; - // override to always overwrite, never overwrite, let user decide, - // compare dates, etc. - - virtual bool SkipEntry(const BEntry *, bool file) = 0; - // override to prevent copying of a given file or directory - - virtual void ChecksumChunk(const char *block, size_t size); - // during a file copy, this is called every time a chunk of data - // is copied. Users may override to keep a running checksum. - - virtual bool ChecksumFile(const entry_ref *); - // This is called when a file is finished copying. Users of this - // class may override to verify that the checksum they've been - // computing in ChecksumChunk matches. If this returns true, - // the copy will continue. If false, if will abort. - - virtual bool SkipAttribute(const char *attributeName); - virtual bool PreserveAttribute(const char *attributeName); -}; - - -class TrackerCopyLoopControl : public CopyLoopControl { - // this is the Tracker copy - specific version of CopyLoopControl - public: - TrackerCopyLoopControl(thread_id); - virtual ~TrackerCopyLoopControl() {} - - virtual bool FileError(const char *message, const char *name, status_t error, - bool allowContinue); - // inform that a file error occurred while copying - // returns true if user decided to continue - - virtual void UpdateStatus(const char *name, entry_ref ref, int32 count, - bool optional = false); - - virtual bool CheckUserCanceled(); - // returns true if canceled - - virtual OverwriteMode OverwriteOnConflict(const BEntry *srcEntry, - const char *destName, const BDirectory *destDir, bool srcIsDir, - bool dstIsDir); - - virtual bool SkipEntry(const BEntry *, bool file); - // override to prevent copying of a given file or directory - - virtual bool SkipAttribute(const char *attributeName); - - private: - thread_id fThread; -}; - - -inline -TrackerCopyLoopControl::TrackerCopyLoopControl(thread_id thread) - : fThread(thread) -{ -} - -#define B_DESKTOP_DIR_NAME "Desktop" - -status_t FSCopyAttributesAndStats(BNode *, BNode *); - -status_t FSCopyFile(BEntry* srcFile, StatStruct *srcStat, BDirectory* destDir, - CopyLoopControl *loopControl, BPoint *loc, bool makeOriginalName, Undo &undo); -status_t FSCopyFolder(BEntry *srcEntry, BDirectory *destDir, CopyLoopControl *loopControl, - BPoint *loc, bool makeOriginalName, Undo &undo); -void FSDuplicate(BObjectList *srcList, BList *pointList); -void FSMoveToFolder(BObjectList *srcList, BEntry *, uint32 moveMode, - BList *pointList = NULL); -void FSMakeOriginalName(char *name, BDirectory *destDir, const char *suffix); -bool FSIsTrashDir(const BEntry *); -bool FSIsPrintersDir(const BEntry *); -bool FSIsDeskDir(const BEntry *); -bool FSIsSystemDir(const BEntry *); -bool FSIsBeOSDir(const BEntry *); -bool FSIsHomeDir(const BEntry *); -void FSMoveToTrash(BObjectList *srcList, BList *pointList = NULL, - bool async = true); - // Deprecated - -void FSDeleteRefList(BObjectList *, bool, bool confirm = true); -void FSDelete(entry_ref *, bool, bool confirm = true); -void FSRestoreRefList(BObjectList *list, bool async); - -status_t FSLaunchItem(const entry_ref *application, const BMessage *refsReceived, - bool async, bool openWithOK); - // Preferred way of launching; only pass an actual application in , not - // a document; to open documents with the preferred app, pase 0 in and - // stuff all the document refs into - // Consider having silent mode that does not show alerts, just returns error code - -status_t FSOpenWith(BMessage *listOfRefs); - // runs the Open With window; pas a list of refs - -void FSEmptyTrash(); -status_t FSCreateNewFolderIn(const node_ref *destDir, entry_ref *newRef, - node_ref *new_node); -void FSCreateTrashDirs(); -status_t FSGetTrashDir(BDirectory *trashDir, dev_t volume); -status_t FSGetDeskDir(BDirectory *deskDir, dev_t volume); -status_t FSRecursiveCalcSize(BInfoWindow *, BDirectory *, - off_t *runningSize, int32 *fileCount, int32 *dirCount); - -bool FSInTrashDir(const entry_ref *); - -// doesn't need to be exported -bool FSGetPoseLocation(const BNode *node, BPoint *point); -status_t FSSetPoseLocation(BEntry *entry, BPoint point); -status_t FSSetPoseLocation(ino_t destDirInode, BNode *destNode, BPoint point); -status_t FSGetBootDeskDir(BDirectory *deskDir); - -status_t FSGetOriginalPath(BEntry *entry, BPath *path); - -enum ReadAttrResult { - kReadAttrFailed, - kReadAttrNativeOK, - kReadAttrForeignOK -}; - -ReadAttrResult ReadAttr(const BNode *, const char *hostAttrName, const char *foreignAttrName, - type_code , off_t , void *, size_t , void (*swapFunc)(void *) = 0, - bool isForeign = false); - // Endian swapping ReadAttr call; endianness is determined by trying first the - // native attribute name, then the foreign one; an endian swapping function can - // be passed, if null data won't be swapped; if set the foreign endianness - // will be read directly without first trying the native one - -ReadAttrResult GetAttrInfo(const BNode *, const char *hostAttrName, const char *foreignAttrName, - type_code * = NULL, size_t * = NULL); - -status_t FSCreateNewFolder(const entry_ref *); -status_t FSRecursiveCreateFolder(const char *path); -void FSMakeOriginalName(BString &name, const BDirectory *destDir, const char *suffix = 0); - -status_t TrackerLaunch(const entry_ref *app, bool async); -status_t TrackerLaunch(const BMessage *refs, bool async, bool okToRunOpenWith = true); -status_t TrackerLaunch(const entry_ref *app, const BMessage *refs, bool async, - bool okToRunOpenWith = true); -status_t LaunchBrokenLink(const char *, const BMessage *); - -status_t FSFindTrackerSettingsDir(BPath *, bool autoCreate = true); - -bool FSIsDeskDir(const BEntry *, dev_t); - -bool ConfirmChangeIfWellKnownDirectory(const BEntry *entry, const char *action, - bool dontAsk = false, int32 *confirmedAlready = NULL); - -// Deprecated calls use newer calls above instead -void FSLaunchItem(const entry_ref *, BMessage * = NULL, int32 workspace = -1); -status_t FSLaunchItem(const entry_ref *, BMessage *, - int32 workspace, bool asynch); -void FSOpenWithDocuments(const entry_ref *executableToLaunch, - BMessage *documentEntryRefs); -status_t FSLaunchUsing(const entry_ref *ref, BMessage *listOfRefs); - - -// some extra directory_which values -// move these to FindDirectory.h -const uint32 B_USER_MAIL_DIRECTORY = 3500; -const uint32 B_USER_QUERIES_DIRECTORY = 3501; -const uint32 B_USER_PEOPLE_DIRECTORY = 3502; -const uint32 B_USER_DOWNLOADS_DIRECTORY = 3503; -const uint32 B_USER_DESKBAR_APPS_DIRECTORY = 3504; -const uint32 B_USER_DESKBAR_PREFERENCES_DIRECTORY = 3505; -const uint32 B_USER_DESKBAR_DEVELOP_DIRECTORY = 3506; - -const int32 B_BOOT_DISK = 10000000; - // map /boot into the directory_which enum for convenience - -class WellKnowEntryList { - // matches up names, id's and node_refs of well known entries in the - // system hierarchy - public: - struct WellKnownEntry { - WellKnownEntry(const node_ref *node, directory_which which, const char *name) - : - node(*node), - which(which), - name(name) - { - } - - // mwcc needs these explicitly to use vector - WellKnownEntry(const WellKnownEntry &clone) - : - node(clone.node), - which(clone.which), - name(clone.name) - { - } - - WellKnownEntry() - { - } - - node_ref node; - directory_which which; - const char *name; - }; - - static directory_which Match(const node_ref *); - static const WellKnownEntry *MatchEntry(const node_ref *); - static void Quit(); - - private: - const WellKnownEntry *MatchEntryCommon(const node_ref *); - WellKnowEntryList(); - void AddOne(directory_which, const char *name); - void AddOne(directory_which, const char *path, const char *name); - void AddOne(directory_which, directory_which base, const char *extension, - const char *name); - - std::vector entries; - static WellKnowEntryList *self; -}; - -#if B_BEOS_VERSION_DANO -#undef _IMPEXP_TRACKER -#endif - -} // namespace BPrivate - -using namespace BPrivate; - -#endif /* FS_UTILS_H */ diff --git a/src/apps/installer/InstallerCopyLoopControl.cpp b/src/apps/installer/InstallerCopyLoopControl.cpp deleted file mode 100644 index da060ec013..0000000000 --- a/src/apps/installer/InstallerCopyLoopControl.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2005, Jérôme Duval. All rights reserved. - * Distributed under the terms of the MIT License. - * - */ -#include "InstallerCopyLoopControl.h" -#include "InstallerWindow.h" -#include -#include - -InstallerCopyLoopControl::InstallerCopyLoopControl(InstallerWindow *window) - : fWindow(window), - fMessenger(window), - fUserCanceled(false) -{ -} - - -bool -InstallerCopyLoopControl::FileError(const char *message, const char *name, status_t error, - bool allowContinue) -{ - char buffer[512]; - sprintf(buffer, message, name, strerror(error)); - - if (allowContinue) - return (new BAlert("", buffer, "Cancel", "OK", 0, - B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0; - - (new BAlert("", buffer, "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(); - return false; -} - - -void -InstallerCopyLoopControl::UpdateStatus(const char *name, entry_ref ref, int32 count, - bool optional) -{ - if (name) { - BMessage msg(STATUS_MESSAGE); - BString s = "Installing "; - s << name; - msg.AddString("status", s.String()); - fMessenger.SendMessage(&msg); - } -} - - -bool -InstallerCopyLoopControl::CheckUserCanceled() -{ - return fUserCanceled; -} - - -InstallerCopyLoopControl::OverwriteMode -InstallerCopyLoopControl::OverwriteOnConflict(const BEntry *srcEntry, - const char *destName, const BDirectory *destDir, bool srcIsDir, - bool dstIsDir) -{ - if (srcIsDir && dstIsDir) - return kMerge; - else - return kReplace; -} - - -bool -InstallerCopyLoopControl::SkipEntry(const BEntry *, bool file) -{ - return false; -} - - -void -InstallerCopyLoopControl::ChecksumChunk(const char *block, size_t size) -{ -} - - -bool -InstallerCopyLoopControl::ChecksumFile(const entry_ref *ref) -{ - return true; -} - - -bool -InstallerCopyLoopControl::SkipAttribute(const char *attributeName) -{ - return false; -} - - -bool -InstallerCopyLoopControl::PreserveAttribute(const char *attributeName) -{ - return false; -} - - -bool -InstallerCopyLoopControl::Cancel() -{ - fUserCanceled = (new BAlert("", - "Are you sure you want to to stop the installation?", - "Continue", "Stop", 0, - B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0; - return fUserCanceled; -} - - -void -InstallerCopyLoopControl::Reset() -{ - fUserCanceled = false; -} - diff --git a/src/apps/installer/InstallerCopyLoopControl.h b/src/apps/installer/InstallerCopyLoopControl.h deleted file mode 100644 index 67716a495c..0000000000 --- a/src/apps/installer/InstallerCopyLoopControl.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2005, Jérôme Duval. All rights reserved. - * Distributed under the terms of the MIT License. - * - */ - -#ifndef _INSTALLERCOPYLOOPCONTROL_H -#define _INSTALLERCOPYLOOPCONTROL_H - -#include "FSUndoRedo.h" -#include "FSUtils.h" -class InstallerWindow; - -class InstallerCopyLoopControl : public CopyLoopControl -{ - public: - InstallerCopyLoopControl(InstallerWindow *window); - virtual ~InstallerCopyLoopControl() {}; - - virtual bool FileError(const char *message, const char *name, status_t error, - bool allowContinue); - - virtual void UpdateStatus(const char *name, entry_ref ref, int32 count, - bool optional = false); - - virtual bool CheckUserCanceled(); - - virtual OverwriteMode OverwriteOnConflict(const BEntry *srcEntry, - const char *destName, const BDirectory *destDir, bool srcIsDir, - bool dstIsDir); - - virtual bool SkipEntry(const BEntry *, bool file); - - virtual void ChecksumChunk(const char *block, size_t size); - virtual bool ChecksumFile(const entry_ref *); - virtual bool SkipAttribute(const char *attributeName); - virtual bool PreserveAttribute(const char *attributeName); - bool Cancel(); - void Reset(); - - private: - InstallerWindow *fWindow; - BMessenger fMessenger; - bool fUserCanceled; -}; - -#endif diff --git a/src/apps/installer/InstallerWindow.cpp b/src/apps/installer/InstallerWindow.cpp index 7b528c47d4..ba8e4f1114 100644 --- a/src/apps/installer/InstallerWindow.cpp +++ b/src/apps/installer/InstallerWindow.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -35,10 +36,10 @@ #include "tracker_private.h" -#include "CopyEngine.h" #include "DialogPane.h" #include "PackageViews.h" #include "PartitionMenuItem.h" +#include "WorkerThread.h" #define DRIVESETUP_SIG "application/x-vnd.Haiku-DriveSetup" @@ -209,7 +210,7 @@ InstallerWindow::InstallerWindow() fNeedsToCenterOnScreen(true), fDriveSetupLaunched(false), fInstallStatus(kReadyForInstall), - fCopyEngine(new CopyEngine(this)), + fWorkerThread(new WorkerThread(this)), fCopyEngineLock(NULL) { LogoView* logoView = new LogoView(); @@ -265,7 +266,7 @@ InstallerWindow::InstallerWindow() "Setup partitions" B_UTF8_ELLIPSIS, new BMessage(SETUP_MESSAGE)); fMakeBootableButton = new BButton("makebootable_button", - "Write Boot Sector", new BMessage(kWriteBootSector)); + "Write Boot Sector", new BMessage(MSG_WRITE_BOOT_SECTOR)); fMakeBootableButton->SetEnabled(false); SetLayout(new BGroupLayout(B_HORIZONTAL)); @@ -357,7 +358,7 @@ void InstallerWindow::MessageReceived(BMessage *msg) { switch (msg->what) { - case RESET_INSTALL: + case MSG_RESET: delete fCopyEngineLock; fCopyEngineLock = NULL; @@ -383,11 +384,11 @@ InstallerWindow::MessageReceived(BMessage *msg) BList* list = new BList(); int32 size = 0; fPackagesView->GetPackagesToInstall(list, &size); - fCopyEngine->SetLock(fCopyEngineLock); - fCopyEngine->SetPackagesList(list); - fCopyEngine->SetSpaceRequired(size); + fWorkerThread->SetLock(fCopyEngineLock); + fWorkerThread->SetPackagesList(list); + fWorkerThread->SetSpaceRequired(size); fInstallStatus = kInstalling; - BMessenger(fCopyEngine).SendMessage(ENGINE_START); + fWorkerThread->StartInstall(); fBeginButton->SetLabel("Stop"); _DisableInterface(true); @@ -402,7 +403,7 @@ InstallerWindow::MessageReceived(BMessage *msg) case kInstalling: { _QuitCopyEngine(true); -// if (fCopyEngine->Cancel()) { +// if (fWorkerThread->Cancel()) { // fInstallStatus = kCancelled; // _SetStatusMessage("Installation cancelled."); // fProgressLayoutItem->SetVisible(false); @@ -440,7 +441,7 @@ InstallerWindow::MessageReceived(BMessage *msg) fSizeView->SetText(string); break; } - case STATUS_MESSAGE: + case MSG_STATUS_MESSAGE: { // TODO: Was this supposed to prevent status messages still arriving // after the copy engine was shut down? @@ -472,7 +473,7 @@ InstallerWindow::MessageReceived(BMessage *msg) } break; } - case INSTALL_FINISHED: + case MSG_INSTALL_FINISHED: { delete fCopyEngineLock; fCopyEngineLock = NULL; @@ -512,8 +513,8 @@ InstallerWindow::MessageReceived(BMessage *msg) } break; } - case kWriteBootSector: - fCopyEngine->WriteBootSector(fDestMenu); + case MSG_WRITE_BOOT_SECTOR: + fWorkerThread->WriteBootSector(fDestMenu); break; default: @@ -533,7 +534,7 @@ InstallerWindow::QuitRequested() return false; } _QuitCopyEngine(false); - fCopyEngine->PostMessage(B_QUIT_REQUESTED); + fWorkerThread->PostMessage(B_QUIT_REQUESTED); be_app->PostMessage(B_QUIT_REQUESTED); return true; } @@ -597,7 +598,7 @@ InstallerWindow::_ScanPartitions() while ((item = fDestMenu->RemoveItem((int32)0))) delete item; - fCopyEngine->ScanDisksPartitions(fSrcMenu, fDestMenu); + fWorkerThread->ScanDisksPartitions(fSrcMenu, fDestMenu); if (fSrcMenu->ItemAt(0)) { _PublishPackages(); diff --git a/src/apps/installer/InstallerWindow.h b/src/apps/installer/InstallerWindow.h index 95f94cbe7b..341ae2cef8 100644 --- a/src/apps/installer/InstallerWindow.h +++ b/src/apps/installer/InstallerWindow.h @@ -22,8 +22,8 @@ class BMenuField; class BStatusBar; class BStringView; class BTextView; -class CopyEngine; class PackagesView; +class WorkerThread; enum InstallStatus { kReadyForInstall, @@ -32,10 +32,10 @@ enum InstallStatus { kCancelled }; -const uint32 STATUS_MESSAGE = 'iSTM'; -const uint32 INSTALL_FINISHED = 'iIFN'; -const uint32 RESET_INSTALL = 'iRSI'; -const uint32 kWriteBootSector = 'iWBS'; +const uint32 MSG_STATUS_MESSAGE = 'iSTM'; +const uint32 MSG_INSTALL_FINISHED = 'iIFN'; +const uint32 MSG_RESET = 'iRSI'; +const uint32 MSG_WRITE_BOOT_SECTOR = 'iWBS'; const char PACKAGES_DIRECTORY[] = "_packages_"; const char VAR_DIRECTORY[] = "var"; @@ -92,7 +92,7 @@ private: bool fDriveSetupLaunched; InstallStatus fInstallStatus; - CopyEngine* fCopyEngine; + WorkerThread* fWorkerThread; BString fLastStatus; BLocker* fCopyEngineLock; }; diff --git a/src/apps/installer/Jamfile b/src/apps/installer/Jamfile index 5d663bfe61..833339fc6d 100644 --- a/src/apps/installer/Jamfile +++ b/src/apps/installer/Jamfile @@ -4,13 +4,11 @@ UsePrivateHeaders shared storage tracker ; SubDirHdrs [ FDirName $(HAIKU_TOP) src kits tracker ] ; Application Installer : - CopyEngine.cpp CopyEngine2.cpp - FSUtils.cpp InstallerApp.cpp - InstallerCopyLoopControl.cpp InstallerWindow.cpp PackageViews.cpp PartitionMenuItem.cpp + WorkerThread.cpp : be tracker translation $(TARGET_LIBSTDC++) : Installer.rdef ; diff --git a/src/apps/installer/PackageViews.cpp b/src/apps/installer/PackageViews.cpp index 12762e70c8..2b0f7385fa 100644 --- a/src/apps/installer/PackageViews.cpp +++ b/src/apps/installer/PackageViews.cpp @@ -178,11 +178,11 @@ PackageCheckBox::MouseMoved(BPoint point, uint32 transit, { printf("%s called\n", __PRETTY_FUNCTION__); if (transit == B_ENTERED_VIEW) { - BMessage msg(STATUS_MESSAGE); + BMessage msg(MSG_STATUS_MESSAGE); msg.AddString("status", fPackage->Description()); BMessenger(NULL, Window()).SendMessage(&msg); } else if (transit == B_EXITED_VIEW) { - BMessage msg(STATUS_MESSAGE); + BMessage msg(MSG_STATUS_MESSAGE); BMessenger(NULL, Window()).SendMessage(&msg); } } diff --git a/src/apps/installer/Vector.h b/src/apps/installer/Vector.h deleted file mode 100644 index bade55e452..0000000000 --- a/src/apps/installer/Vector.h +++ /dev/null @@ -1,798 +0,0 @@ -// Vector.h -// -// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// -// Except as contained in this notice, the name of a copyright holder shall -// not be used in advertising or otherwise to promote the sale, use or other -// dealings in this Software without prior written authorization of the -// copyright holder. - -#ifndef _INSTALLER_VECTOR_H -#define _INSTALLER_VECTOR_H - -#include -#include -#include - -#include - -template class VectorIterator; - -// for convenience -#define _VECTOR_TEMPLATE_LIST template -#define _VECTOR_CLASS_NAME Vector - -/*! - \class Vector - \brief A generic vector implementation. -*/ -template -class Vector { -public: - typedef VectorIterator Iterator; - typedef VectorIterator ConstIterator; - -private: - static const size_t kDefaultChunkSize = 10; - static const size_t kMaximalChunkSize = 1024 * 1024; - -public: - Vector(size_t chunkSize = kDefaultChunkSize); - ~Vector(); - - status_t PushFront(const Value &value); - status_t PushBack(const Value &value); - - void PopFront(); - void PopBack(); - - status_t Insert(const Value &value, int32 index); - status_t Insert(const Value &value, const Iterator &iterator); - - int32 Remove(const Value &value); - Iterator Erase(int32 index); - Iterator Erase(const Iterator &iterator); - - inline int32 Count() const; - inline bool IsEmpty() const; - void MakeEmpty(); - - inline Iterator Begin(); - inline ConstIterator Begin() const; - inline Iterator End(); - inline ConstIterator End() const; - inline Iterator Null(); - inline ConstIterator Null() const; - inline Iterator IteratorForIndex(int32 index); - inline ConstIterator IteratorForIndex(int32 index) const; - - inline const Value &ElementAt(int32 index) const; - inline Value &ElementAt(int32 index); - - int32 IndexOf(const Value &value, int32 start = 0) const; - Iterator Find(const Value &value); - Iterator Find(const Value &value, const Iterator &start); - ConstIterator Find(const Value &value) const; - ConstIterator Find(const Value &value, const ConstIterator &start) const; - - inline Value &operator[](int32 index); - inline const Value &operator[](int32 index) const; - - // debugging - int32 GetCapacity() const { return fCapacity; } - -private: - inline static void _MoveItems(Value *values, int32 offset, int32 count); - bool _Resize(size_t count); - inline int32 _IteratorIndex(const Iterator &iterator) const; - inline int32 _IteratorIndex(const ConstIterator &iterator) const; - -private: - size_t fCapacity; - size_t fChunkSize; - int32 fItemCount; - Value *fItems; -}; - - -// VectorIterator -template -class VectorIterator { -private: - typedef VectorIterator Iterator; - -public: - inline VectorIterator() - : fElement(NULL) - { - } - - inline VectorIterator(const Iterator &other) - : fElement(other.fElement) - { - } - - inline Iterator &operator++() - { - if (fElement) - ++fElement; - return *this; - } - - inline Iterator operator++(int) - { - Iterator it(*this); - ++*this; - return it; - } - - inline Iterator &operator--() - { - if (fElement) - --fElement; - return *this; - } - - inline Iterator operator--(int) - { - Iterator it(*this); - --*this; - return it; - } - - inline Iterator &operator=(const Iterator &other) - { - fElement = other.fElement; - return *this; - } - - - inline bool operator==(const Iterator &other) const - { - return (fElement == other.fElement); - } - - inline bool operator!=(const Iterator &other) const - { - return !(*this == other); - } - - inline Value &operator*() const - { - return *fElement; - } - - inline Value *operator->() const - { - return fElement; - } - - inline operator bool() const - { - return fElement; - } - -// private -public: - inline VectorIterator(Value *element) - : fElement(element) - { - } - - inline Value *Element() const - { - return fElement; - } - -protected: - Value *fElement; -}; - - -// Vector - -// constructor -/*! \brief Creates an empty vector. - \param chunkSize The granularity for the vector's capacity, i.e. the - minimal number of elements the capacity grows or shrinks when - necessary. -*/ -_VECTOR_TEMPLATE_LIST -_VECTOR_CLASS_NAME::Vector(size_t chunkSize) - : fCapacity(0), - fChunkSize(chunkSize), - fItemCount(0), - fItems(NULL) -{ - if (fChunkSize == 0 || fChunkSize > kMaximalChunkSize) - fChunkSize = kDefaultChunkSize; - _Resize(0); -} - -// destructor -/*! \brief Frees all resources associated with the object. - - The contained elements are destroyed. Note, that, if the element - type is a pointer type, only the pointer is destroyed, not the object - it points to. -*/ -_VECTOR_TEMPLATE_LIST -_VECTOR_CLASS_NAME::~Vector() -{ - MakeEmpty(); - free(fItems); -} - -// PushFront -/*! \brief Inserts a copy of the supplied value at the beginning of the - vector. - \param value The element to be inserted. - \return - - \c B_OK: Everything went fine. - - \c B_NO_MEMORY: Insufficient memory for this operation. -*/ -_VECTOR_TEMPLATE_LIST -status_t -_VECTOR_CLASS_NAME::PushFront(const Value &value) -{ - return Insert(value, 0); -} - -// PushBack -/*! \brief Inserts a copy of the supplied value at the end of the vector. - \param value The element to be inserted. - \return - - \c B_OK: Everything went fine. - - \c B_NO_MEMORY: Insufficient memory for this operation. -*/ -_VECTOR_TEMPLATE_LIST -status_t -_VECTOR_CLASS_NAME::PushBack(const Value &value) -{ - return Insert(value, fItemCount); -} - -// PopFront -/*! \brief Removes the first element of the vector. - - Invocation on an empty vector is harmless. -*/ -_VECTOR_TEMPLATE_LIST -void -_VECTOR_CLASS_NAME::PopFront() -{ - if (fItemCount > 0) - Erase(0); -} - -// PopBack -/*! \brief Removes the last element of the vector. - - Invocation on an empty vector is harmless. -*/ -_VECTOR_TEMPLATE_LIST -void -_VECTOR_CLASS_NAME::PopBack() -{ - if (fItemCount > 0) - Erase(fItemCount - 1); -} - -// _MoveItems -/*! \brief Moves elements within an array. - \param items The elements to be moved. - \param offset The index to which the elements shall be moved. May be - negative. - \param count The number of elements to be moved. -*/ -_VECTOR_TEMPLATE_LIST -inline -void -_VECTOR_CLASS_NAME::_MoveItems(Value* items, int32 offset, int32 count) -{ - if (count > 0 && offset != 0) - memmove(items + offset, items, count * sizeof(Value)); -} - -// Insert -/*! \brief Inserts a copy of the the supplied value at the given index. - \param value The value to be inserted. - \param index The index at which to insert the new element. It must - hold: 0 <= \a index <= Count(). - \return - - \c B_OK: Everything went fine. - - \c B_BAD_VALUE: \a index is out of range. - - \c B_NO_MEMORY: Insufficient memory for this operation. -*/ -_VECTOR_TEMPLATE_LIST -status_t -_VECTOR_CLASS_NAME::Insert(const Value &value, int32 index) -{ - if (index < 0 || index > fItemCount) - return B_BAD_VALUE; - if (!_Resize(fItemCount + 1)) - return B_NO_MEMORY; - _MoveItems(fItems + index, 1, fItemCount - index - 1); - new(fItems + index) Value(value); - return B_OK; -} - -// Insert -/*! \brief Inserts a copy of the the supplied value at the given position. - \param value The value to be inserted. - \param iterator An iterator specifying the position at which to insert - the new element. - \return - - \c B_OK: Everything went fine. - - \c B_BAD_VALUE: \a iterator is is invalid. - - \c B_NO_MEMORY: Insufficient memory for this operation. -*/ -_VECTOR_TEMPLATE_LIST -status_t -_VECTOR_CLASS_NAME::Insert(const Value &value, const Iterator &iterator) -{ - int32 index = _IteratorIndex(iterator); - if (index >= 0) - return Insert(value, index); - return B_BAD_VALUE; -} - -// Remove -/*! \brief Removes all elements of the supplied value. - \param value The value of the elements to be removed. - \return The number of removed occurrences. -*/ -_VECTOR_TEMPLATE_LIST -int32 -_VECTOR_CLASS_NAME::Remove(const Value &value) -{ - int32 count = 0; - for (int32 i = fItemCount - 1; i >= 0; i--) { - if (ElementAt(i) == value) { - Erase(i); - count++; - } - } - return count; -} - -// Erase -/*! \brief Removes the element at the given index. - \param index The position of the element to be removed. - \return An iterator referring to the element now being located at index - \a index (End(), if it was the last element that has been - removed), or Null(), if \a index was out of range. -*/ -_VECTOR_TEMPLATE_LIST -_VECTOR_CLASS_NAME::Iterator -_VECTOR_CLASS_NAME::Erase(int32 index) -{ - if (index >= 0 && index < fItemCount) { - fItems[index].~Value(); - _MoveItems(fItems + index + 1, -1, fItemCount - index - 1); - _Resize(fItemCount - 1); - return Iterator(fItems + index); - } - return Null(); -} - -// Erase -/*! \brief Removes the element at the given position. - \param iterator An iterator referring to the element to be removed. - \return An iterator referring to the element succeeding the removed - one (End(), if it was the last element that has been - removed), or Null(), if \a iterator was an invalid iterator - (in this case including End()). -*/ -_VECTOR_TEMPLATE_LIST -_VECTOR_CLASS_NAME::Iterator -_VECTOR_CLASS_NAME::Erase(const Iterator &iterator) -{ - int32 index = _IteratorIndex(iterator); - if (index >= 0 && index < fItemCount) - return Erase(index); - return Null(); -} - -// Count -/*! \brief Returns the number of elements the vector contains. - \return The number of elements the vector contains. -*/ -_VECTOR_TEMPLATE_LIST -inline -int32 -_VECTOR_CLASS_NAME::Count() const -{ - return fItemCount; -} - -// IsEmpty -/*! \brief Returns whether the vector is empty. - \return \c true, if the vector is empty, \c false otherwise. -*/ -_VECTOR_TEMPLATE_LIST -inline -bool -_VECTOR_CLASS_NAME::IsEmpty() const -{ - return (fItemCount == 0); -} - -// MakeEmpty -/*! \brief Removes all elements from the vector. -*/ -_VECTOR_TEMPLATE_LIST -void -_VECTOR_CLASS_NAME::MakeEmpty() -{ - for (int32 i = 0; i < fItemCount; i++) - fItems[i].~Value(); - _Resize(0); -} - -// Begin -/*! \brief Returns an iterator referring to the beginning of the vector. - - If the vector is not empty, Begin() refers to its first element, - otherwise it is equal to End() and must not be dereferenced! - - \return An iterator referring to the beginning of the vector. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::Iterator -_VECTOR_CLASS_NAME::Begin() -{ - return Iterator(fItems); -} - -// Begin -/*! \brief Returns an iterator referring to the beginning of the vector. - - If the vector is not empty, Begin() refers to its first element, - otherwise it is equal to End() and must not be dereferenced! - - \return An iterator referring to the beginning of the vector. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::ConstIterator -_VECTOR_CLASS_NAME::Begin() const -{ - return ConstIterator(fItems); -} - -// End -/*! \brief Returns an iterator referring to the end of the vector. - - The position identified by End() is the one succeeding the last - element, i.e. it must not be dereferenced! - - \return An iterator referring to the end of the vector. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::Iterator -_VECTOR_CLASS_NAME::End() -{ - return Iterator(fItems + fItemCount); -} - -// End -/*! \brief Returns an iterator referring to the end of the vector. - - The position identified by End() is the one succeeding the last - element, i.e. it must not be dereferenced! - - \return An iterator referring to the end of the vector. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::ConstIterator -_VECTOR_CLASS_NAME::End() const -{ - return ConstIterator(fItems + fItemCount); -} - -// Null -/*! \brief Returns an invalid iterator. - - Null() is used as a return value, if something went wrong. It must - neither be incremented or decremented nor dereferenced! - - \return An invalid iterator. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::Iterator -_VECTOR_CLASS_NAME::Null() -{ - return Iterator(NULL); -} - -// Null -/*! \brief Returns an invalid iterator. - - Null() is used as a return value, if something went wrong. It must - neither be incremented or decremented nor dereferenced! - - \return An invalid iterator. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::ConstIterator -_VECTOR_CLASS_NAME::Null() const -{ - return ConstIterator(NULL); -} - -// IteratorForIndex -/*! \brief Returns an iterator for a given index. - \return An iterator referring to the same element as \a index, or - End(), if \a index is out of range. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::Iterator -_VECTOR_CLASS_NAME::IteratorForIndex(int32 index) -{ - if (index >= 0 && index <= fItemCount) - return Iterator(fItems + index); - return End(); -} - -// IteratorForIndex -/*! \brief Returns an iterator for a given index. - \return An iterator referring to the same element as \a index, or - End(), if \a index is out of range. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::ConstIterator -_VECTOR_CLASS_NAME::IteratorForIndex(int32 index) const -{ - if (index >= 0 && index <= fItemCount) - return ConstIterator(fItems + index); - return End(); -} - -// ElementAt -/*! \brief Returns the element at a given index. - \param index The index identifying the element to be returned. - \return The element identified by the given index. -*/ -_VECTOR_TEMPLATE_LIST -inline -const Value & -_VECTOR_CLASS_NAME::ElementAt(int32 index) const -{ - if (index >= 0 && index < fItemCount) - return fItems[index]; - // Return the 0th element by default. Unless the allocation failed, there - // is always a 0th element -- uninitialized perhaps. - return fItems[0]; -} - -// ElementAt -/*! \brief Returns the element at a given index. - \param index The index identifying the element to be returned. - \return The element identified by the given index. -*/ -_VECTOR_TEMPLATE_LIST -inline -Value & -_VECTOR_CLASS_NAME::ElementAt(int32 index) -{ - if (index >= 0 && index < fItemCount) - return fItems[index]; - // Return the 0th element by default. Unless the allocation failed, there - // is always a 0th element -- uninitialized perhaps. - return fItems[0]; -} - -// IndexOf -/*! \brief Returns the index of the next element with the specified value. - \param value The value of the element to be found. - \param start The index at which to be started to search for the element. - \return The index of the found element, or \c -1, if no further element - with the given value could be found or \a index is out of range. -*/ -_VECTOR_TEMPLATE_LIST -int32 -_VECTOR_CLASS_NAME::IndexOf(const Value &value, int32 start) const -{ - if (start >= 0) { - for (int32 i = start; i < fItemCount; i++) { - if (fItems[i] == value) - return i; - } - } - return -1; -} - -// Find -/*! \brief Returns an iterator referring to the next element with the - specified value. - \param value The value of the element to be found. - \return An iterator referring to the found element, or End(), if no - further with the given value could be found. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::Iterator -_VECTOR_CLASS_NAME::Find(const Value &value) -{ - return Find(value, Begin()); -} - -// Find -/*! \brief Returns an iterator referring to the next element with the - specified value. - \param value The value of the element to be found. - \param start And iterator specifying where to start searching for the - element. - \return An iterator referring to the found element, or End(), if no - further with the given value could be found or \a start was - invalid. -*/ -_VECTOR_TEMPLATE_LIST -_VECTOR_CLASS_NAME::Iterator -_VECTOR_CLASS_NAME::Find(const Value &value, const Iterator &start) -{ - int32 index = IndexOf(value, _IteratorIndex(start)); - if (index >= 0) - return Iterator(fItems + index); - return End(); -} - -// Find -/*! \brief Returns an iterator referring to the of the next element with the - specified value. - \param value The value of the element to be found. - \return An iterator referring to the found element, or End(), if no - further with the given value could be found. -*/ -_VECTOR_TEMPLATE_LIST -inline -_VECTOR_CLASS_NAME::ConstIterator -_VECTOR_CLASS_NAME::Find(const Value &value) const -{ - return Find(value, Begin()); -} - -// Find -/*! \brief Returns an iterator referring to the of the next element with the - specified value. - \param value The value of the element to be found. - \param start And iterator specifying where to start searching for the - element. - \return An iterator referring to the found element, or End(), if no - further with the given value could be found or \a start was - invalid. -*/ -_VECTOR_TEMPLATE_LIST -_VECTOR_CLASS_NAME::ConstIterator -_VECTOR_CLASS_NAME::Find(const Value &value, const ConstIterator &start) const -{ - int32 index = IndexOf(value, _IteratorIndex(start)); - if (index >= 0) - return ConstIterator(fItems + index); - return End(); -} - -// [] -/*! \brief Semantically equivalent to ElementAt(). -*/ -_VECTOR_TEMPLATE_LIST -inline -Value & -_VECTOR_CLASS_NAME::operator[](int32 index) -{ - return ElementAt(index); -} - -// [] -/*! \brief Semantically equivalent to ElementAt(). -*/ -_VECTOR_TEMPLATE_LIST -inline -const Value & -_VECTOR_CLASS_NAME::operator[](int32 index) const -{ - return ElementAt(index); -} - -// _Resize -/*! \brief Resizes the vector. - - The internal element array will be grown or shrunk to the next multiple - of \a fChunkSize >= \a count, but no less than \a fChunkSize. - - Also adjusts \a fItemCount according to the supplied \a count, but does - not invoke a destructor or constructor on any element. - - \param count The number of element. - \return \c true, if everything went fine, \c false, if the memory - allocation failed. -*/ -_VECTOR_TEMPLATE_LIST -bool -_VECTOR_CLASS_NAME::_Resize(size_t count) -{ - bool result = true; - // calculate the new capacity - int32 newSize = count; - if (newSize <= 0) - newSize = 1; - newSize = ((newSize - 1) / fChunkSize + 1) * fChunkSize; - // resize if necessary - if ((size_t)newSize != fCapacity) { - Value* newItems = (Value*)realloc(fItems, newSize * sizeof(Value)); - if (newItems) { - fItems = newItems; - fCapacity = newSize; - } else - result = false; - } - if (result) - fItemCount = count; - return result; -} - -// _IteratorIndex -/*! \brief Returns index of the element the supplied iterator refers to. - \return The index of the element the supplied iterator refers to, or - \c -1, if the iterator is invalid (End() is considered valid - here, and Count() is returned). -*/ -_VECTOR_TEMPLATE_LIST -inline -int32 -_VECTOR_CLASS_NAME::_IteratorIndex(const Iterator &iterator) const -{ - if (iterator.Element()) { - int32 index = iterator.Element() - fItems; - if (index >= 0 && index <= fItemCount) - return index; - } - return -1; -} - -// _IteratorIndex -/*! \brief Returns index of the element the supplied iterator refers to. - \return The index of the element the supplied iterator refers to, or - \c -1, if the iterator is invalid (End() is considered valid - here, and Count() is returned). -*/ -_VECTOR_TEMPLATE_LIST -inline -int32 -_VECTOR_CLASS_NAME::_IteratorIndex(const ConstIterator &iterator) const -{ - if (iterator.Element()) { - int32 index = iterator.Element() - fItems; - if (index >= 0 && index <= fItemCount) - return index; - } - return -1; -} - -#endif // _INSTALLER_VECTOR_H diff --git a/src/apps/installer/CopyEngine.cpp b/src/apps/installer/WorkerThread.cpp similarity index 73% rename from src/apps/installer/CopyEngine.cpp rename to src/apps/installer/WorkerThread.cpp index bea20295bc..e71cb0587e 100644 --- a/src/apps/installer/CopyEngine.cpp +++ b/src/apps/installer/WorkerThread.cpp @@ -1,26 +1,30 @@ /* - * Copyright 2005-2008, Jérôme DUVAL. All rights reserved. - * Distributed under the terms of the MIT License. + * Copyright 2009, Stephan Aßmus . + * Copyright 2005-2008, Jérôme DUVAL. + * All rights reserved. Distributed under the terms of the MIT License. */ -#include "CopyEngine.h" +#include "WorkerThread.h" #include #include +#include +#include #include #include #include +#include +#include #include #include #include #include #include +#include "AutoLocker.h" #include "CopyEngine2.h" #include "InstallerWindow.h" -#include "FSUndoRedo.h" -#include "FSUtils.h" #include "PackageViews.h" #include "PartitionMenuItem.h" @@ -28,8 +32,8 @@ //#define COPY_TRACE #ifdef COPY_TRACE #define CALLED() printf("CALLED %s\n",__PRETTY_FUNCTION__) -#define ERR2(x, y...) fprintf(stderr, "CopyEngine: "x" %s\n", y, strerror(err)) -#define ERR(x) fprintf(stderr, "CopyEngine: "x" %s\n", strerror(err)) +#define ERR2(x, y...) fprintf(stderr, "WorkerThread: "x" %s\n", y, strerror(err)) +#define ERR(x) fprintf(stderr, "WorkerThread: "x" %s\n", strerror(err)) #else #define CALLED() #define ERR(x) @@ -40,6 +44,10 @@ const char BOOT_PATH[] = "/boot"; extern void SizeAsString(off_t size, char *string); + +const uint32 MSG_START_INSTALLING = 'eSRT'; + + class SourceVisitor : public BDiskDeviceVisitor { public: @@ -63,37 +71,39 @@ class TargetVisitor : public BDiskDeviceVisitor }; -CopyEngine::CopyEngine(InstallerWindow *window) +// #pragma mark - WorkerThread + + +WorkerThread::WorkerThread(InstallerWindow *window) : BLooper("copy_engine"), fWindow(window), fPackages(NULL), fSpaceRequired(0) { - fControl = new InstallerCopyLoopControl(window); Run(); } void -CopyEngine::MessageReceived(BMessage* message) +WorkerThread::MessageReceived(BMessage* message) { CALLED(); switch (message->what) { - case ENGINE_START: - Start(fWindow->GetSourceMenu(), fWindow->GetTargetMenu()); + case MSG_START_INSTALLING: + _PerformInstall(fWindow->GetSourceMenu(), fWindow->GetTargetMenu()); break; - case kWriteBootSector: + case MSG_WRITE_BOOT_SECTOR: { int32 id; if (message->FindInt32("id", &id) != B_OK) { - SetStatusMessage("Boot sector not written because of an " + _SetStatusMessage("Boot sector not written because of an " " internal error."); break; } - // TODO: Refactor with Start() + // TODO: Refactor with _PerformInstall() BPath targetDirectory; BDiskDevice device; BPartition* partition; @@ -101,32 +111,32 @@ CopyEngine::MessageReceived(BMessage* message) if (fDDRoster.GetPartitionWithID(id, &device, &partition) == B_OK) { if (!partition->IsMounted()) { if (partition->Mount() < B_OK) { - SetStatusMessage("The partition can't be mounted. " + _SetStatusMessage("The partition can't be mounted. " "Please choose a different partition."); break; } } if (partition->GetMountPoint(&targetDirectory) != B_OK) { - SetStatusMessage("The mount point could not be retrieve."); + _SetStatusMessage("The mount point could not be retrieve."); break; } } else if (fDDRoster.GetDeviceWithID(id, &device) == B_OK) { if (!device.IsMounted()) { if (device.Mount() < B_OK) { - SetStatusMessage("The disk can't be mounted. Please " + _SetStatusMessage("The disk can't be mounted. Please " "choose a different disk."); break; } } if (device.GetMountPoint(&targetDirectory) != B_OK) { - SetStatusMessage("The mount point could not be retrieve."); + _SetStatusMessage("The mount point could not be retrieve."); break; } } - LaunchFinishScript(targetDirectory); + _LaunchFinishScript(targetDirectory); // TODO: Get error from executing script! - SetStatusMessage("Boot sector successfully written."); + _SetStatusMessage("Boot sector successfully written."); } default: BLooper::MessageReceived(message); @@ -134,17 +144,67 @@ CopyEngine::MessageReceived(BMessage* message) } + + void -CopyEngine::SetStatusMessage(const char *status) +WorkerThread::ScanDisksPartitions(BMenu *srcMenu, BMenu *targetMenu) { - BMessage msg(STATUS_MESSAGE); - msg.AddString("status", status); - BMessenger(fWindow).SendMessage(&msg); + // NOTE: This is actually executed in the window thread. + BDiskDevice device; + BPartition *partition = NULL; + + printf("\nScanDisksPartitions source partitions begin\n"); + SourceVisitor srcVisitor(srcMenu); + fDDRoster.VisitEachMountedPartition(&srcVisitor, &device, &partition); + + printf("\nScanDisksPartitions target partitions begin\n"); + TargetVisitor targetVisitor(targetMenu); + fDDRoster.VisitEachPartition(&targetVisitor, &device, &partition); } void -CopyEngine::LaunchInitScript(BPath &path) +WorkerThread::SetPackagesList(BList *list) +{ + // Executed in window thread. + BAutolock _(this); + + delete fPackages; + fPackages = list; +} + + +void +WorkerThread::StartInstall() +{ + // Executed in window thread. + PostMessage(MSG_START_INSTALLING, this); +} + + +void +WorkerThread::WriteBootSector(BMenu* targetMenu) +{ + // Executed in window thread. + CALLED(); + + PartitionMenuItem* item = (PartitionMenuItem*)targetMenu->FindMarked(); + if (item == NULL) { + ERR("bad menu items\n"); + return; + } + + BMessage message(MSG_WRITE_BOOT_SECTOR); + message.AddInt32("id", item->ID()); + PostMessage(&message, this); +} + + +// #pragma mark - + + +void +WorkerThread::_LaunchInitScript(BPath &path) { BPath bootPath; find_directory(B_BEOS_BOOT_DIRECTORY, &bootPath); @@ -152,13 +212,13 @@ CopyEngine::LaunchInitScript(BPath &path) command += bootPath.Path(); command += "/InstallerInitScript "; command += path.Path(); - SetStatusMessage("Starting Installation."); + _SetStatusMessage("Starting Installation."); system(command.String()); } void -CopyEngine::LaunchFinishScript(BPath &path) +WorkerThread::_LaunchFinishScript(BPath &path) { BPath bootPath; find_directory(B_BEOS_BOOT_DIRECTORY, &bootPath); @@ -166,27 +226,27 @@ CopyEngine::LaunchFinishScript(BPath &path) command += bootPath.Path(); command += "/InstallerFinishScript "; command += path.Path(); - SetStatusMessage("Finishing Installation."); + _SetStatusMessage("Finishing Installation."); system(command.String()); } void -CopyEngine::Start(BMenu *srcMenu, BMenu *targetMenu) +WorkerThread::_PerformInstall(BMenu *srcMenu, BMenu *targetMenu) { CALLED(); BPath targetDirectory, srcDirectory; - BDirectory targetDir, srcDir; + BDirectory targetDir; BDiskDevice device; BPartition *partition; BVolume targetVolume; status_t err = B_OK; int32 entries = 0; entry_ref testRef; -bigtime_t now; - fControl->Reset(); + BMessenger messenger(fWindow); + CopyEngine2 engine(messenger, new BMessage(MSG_STATUS_MESSAGE)); PartitionMenuItem *targetItem = (PartitionMenuItem *)targetMenu->FindMarked(); PartitionMenuItem *srcItem = (PartitionMenuItem *)srcMenu->FindMarked(); @@ -201,7 +261,7 @@ bigtime_t now; if (fDDRoster.GetPartitionWithID(targetItem->ID(), &device, &partition) == B_OK) { if (!partition->IsMounted()) { if ((err = partition->Mount()) < B_OK) { - SetStatusMessage("The disk can't be mounted. Please choose a " + _SetStatusMessage("The disk can't be mounted. Please choose a " "different disk."); ERR("BPartition::Mount"); goto error; @@ -218,7 +278,7 @@ bigtime_t now; } else if (fDDRoster.GetDeviceWithID(targetItem->ID(), &device) == B_OK) { if (!device.IsMounted()) { if ((err = device.Mount()) < B_OK) { - SetStatusMessage("The disk can't be mounted. Please choose a " + _SetStatusMessage("The disk can't be mounted. Please choose a " "different disk."); ERR("BDiskDevice::Mount"); goto error; @@ -259,7 +319,7 @@ bigtime_t now; // check not installing on itself if (strcmp(srcDirectory.Path(), targetDirectory.Path()) == 0) { - SetStatusMessage("You can't install the contents of a disk onto " + _SetStatusMessage("You can't install the contents of a disk onto " "itself. Please choose a different disk."); goto error; } @@ -270,7 +330,7 @@ bigtime_t now; "current boot disk? The Installer will have to reboot your " "machine if you proceed.", "OK", "Cancel", 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { - SetStatusMessage("Installation stopped."); + _SetStatusMessage("Installation stopped."); goto error; } @@ -326,143 +386,54 @@ bigtime_t now; } - LaunchInitScript(targetDirectory); + _LaunchInitScript(targetDirectory); // copy source volume - targetDir.Rewind(); - srcDir.SetTo(srcDirectory.Path()); -now = system_time(); -#if 0 - err = CopyFolder(srcDir, targetDir); -#else - { - BMessenger messenger(fWindow); - CopyEngine2 engine(messenger, new BMessage(STATUS_MESSAGE)); - err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(), - fCancelLock); -if (err != B_OK) -printf("error: %s\n", strerror(err)); - } -#endif -printf("copy time: %.3fs\n", (system_time() - now) / 1000000.0); - - if (err != B_OK || fControl->CheckUserCanceled()) + err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(), + fCancelLock); + if (err != B_OK) goto error; // copy selected packages if (fPackages) { srcDirectory.Append(PACKAGES_DIRECTORY); - srcDir.SetTo(srcDirectory.Path()); - BDirectory packageDir; int32 count = fPackages->CountItems(); for (int32 i = 0; i < count; i++) { Package *p = static_cast(fPackages->ItemAt(i)); - packageDir.SetTo(&srcDir, p->Folder()); - err = CopyFolder(packageDir, targetDir); - if (err != B_OK || fControl->CheckUserCanceled()) + BPath packageDir(srcDirectory.Path(), p->Folder()); + err = engine.CopyFolder(packageDir.Path(), targetDirectory.Path(), + fCancelLock); + if (err != B_OK) goto error; } } - LaunchFinishScript(targetDirectory); + _LaunchFinishScript(targetDirectory); - BMessenger(fWindow).SendMessage(INSTALL_FINISHED); + BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED); return; error: - if (err == B_CANCELED || fControl->CheckUserCanceled()) - SetStatusMessage("Installation canceled."); - ERR("Start failed"); - BMessenger(fWindow).SendMessage(RESET_INSTALL); -} - - -status_t -CopyEngine::CopyFolder(BDirectory &srcDir, BDirectory &targetDir) -{ - BEntry entry; - status_t err; - while (srcDir.GetNextEntry(&entry) == B_OK - && !fControl->CheckUserCanceled()) { - StatStruct statbuf; - entry.GetStat(&statbuf); - - Undo undo; - if (S_ISDIR(statbuf.st_mode)) { - char name[B_FILE_NAME_LENGTH]; - if (entry.GetName(name) == B_OK - && (strcmp(name, PACKAGES_DIRECTORY) == 0 - || strcmp(name, VAR_DIRECTORY) == 0)) { - continue; - } - err = FSCopyFolder(&entry, &targetDir, fControl, NULL, false, undo); - } else { - err = FSCopyFile(&entry, &statbuf, &targetDir, fControl, NULL, - false, undo); - } - if (err != B_OK) { - BPath path; - entry.GetPath(&path); - ERR2("error while copying %s", path.Path()); - return err; - } - } - - return B_OK; + BMessage statusMessage(MSG_RESET); + if (err == B_CANCELED) + _SetStatusMessage("Installation canceled."); + else + statusMessage.AddInt32("error", err); + ERR("_PerformInstall failed"); + BMessenger(fWindow).SendMessage(&statusMessage); } void -CopyEngine::ScanDisksPartitions(BMenu *srcMenu, BMenu *targetMenu) +WorkerThread::_SetStatusMessage(const char *status) { - // NOTE: This is actually executed in the window thread. - BDiskDevice device; - BPartition *partition = NULL; - - printf("\nScanDisksPartitions source partitions begin\n"); - SourceVisitor srcVisitor(srcMenu); - fDDRoster.VisitEachMountedPartition(&srcVisitor, &device, &partition); - - printf("\nScanDisksPartitions target partitions begin\n"); - TargetVisitor targetVisitor(targetMenu); - fDDRoster.VisitEachPartition(&targetVisitor, &device, &partition); + BMessage msg(MSG_STATUS_MESSAGE); + msg.AddString("status", status); + BMessenger(fWindow).SendMessage(&msg); } -void -CopyEngine::SetPackagesList(BList *list) -{ - delete fPackages; - fPackages = list; -} - - -bool -CopyEngine::Cancel() -{ - return fControl->Cancel(); -} - - -void -CopyEngine::WriteBootSector(BMenu* targetMenu) -{ - // Executed in window thread. - CALLED(); - - PartitionMenuItem* item = (PartitionMenuItem*)targetMenu->FindMarked(); - if (item == NULL) { - ERR("bad menu items\n"); - return; - } - - BMessage message(kWriteBootSector); - message.AddInt32("id", item->ID()); - PostMessage(&message, this); -} - - -// #pragma mark - +// #pragma mark - SourceVisitor SourceVisitor::SourceVisitor(BMenu *menu) @@ -516,7 +487,7 @@ SourceVisitor::Visit(BPartition *partition, int32 level) } -// #pragma mark - +// #pragma mark - TargetVisitor TargetVisitor::TargetVisitor(BMenu *menu) @@ -582,10 +553,15 @@ TargetVisitor::_MakeLabel(BPartition *partition, char *label, char *menuLabel) BPath path; partition->GetPath(&path); - sprintf(label, "%s - %s [%s] [%s]", partition->ContentName(), - size, partition->ContentType(), path.Path()); - sprintf(menuLabel, "%s - %s [%s]", partition->ContentName(), size, - partition->ContentType()); + // TODO: Reenable the printing of the content type once Haiku supports + // installing to other file systems than BFS. +// sprintf(label, "%s - %s [%s] [%s]", partition->ContentName(), +// size, partition->ContentType(), path.Path()); +// sprintf(menuLabel, "%s - %s [%s]", partition->ContentName(), size, +// partition->ContentType()); + sprintf(label, "%s - %s - %s", partition->ContentName(), size, + path.Path()); + sprintf(menuLabel, "%s - %s", partition->ContentName(), size); } diff --git a/src/apps/installer/WorkerThread.h b/src/apps/installer/WorkerThread.h new file mode 100644 index 0000000000..b5b2b7547d --- /dev/null +++ b/src/apps/installer/WorkerThread.h @@ -0,0 +1,56 @@ +/* + * Copyright 2009, Stephan Aßmus . + * Copyright 2005, Jérôme DUVAL. + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef WORKER_THREAD_H +#define WORKER_THREAD_H + +#include +#include +#include +#include +#include +#include + +class BList; +class BLocker; +class BMenu; +class InstallerWindow; + +class WorkerThread : public BLooper { +public: + WorkerThread(InstallerWindow* window); + + virtual void MessageReceived(BMessage* message); + + void ScanDisksPartitions(BMenu* srcMenu, + BMenu* dstMenu); + + void SetPackagesList(BList* list); + void SetSpaceRequired(off_t bytes) + { fSpaceRequired = bytes; }; + + bool Cancel(); + void SetLock(BLocker* lock) + { fCancelLock = lock; } + + void StartInstall(); + void WriteBootSector(BMenu* dstMenu); + +private: + void _LaunchInitScript(BPath& path); + void _LaunchFinishScript(BPath& path); + + void _PerformInstall(BMenu* srcMenu, BMenu* dstMenu); + + void _SetStatusMessage(const char* status); + + InstallerWindow* fWindow; + BDiskDeviceRoster fDDRoster; + BList* fPackages; + off_t fSpaceRequired; + BLocker* fCancelLock; +}; + +#endif // WORKER_THREAD_H