Пример #1
0
int restoreObject(const char* aside, const char* target, const char* path, const char* object)
{
	char source[PATH_MAX];		/* Flawfinder: ignore */
	char dest[PATH_MAX];		/* Flawfinder: ignore */
	snprintf(source, sizeof(source), "%s/%s/%s", aside, path, object);		
	snprintf(dest, sizeof(dest), "%s/%s", target, path);		
	FSRef sourceRef;
	FSRef destRef;
	OSStatus err;
	err = FSPathMakeRef((UInt8 *)source, &sourceRef, NULL);
	if(err != noErr) return false;
	err = FSPathMakeRef((UInt8 *)dest, &destRef, NULL);
	if(err != noErr) return false;

	llinfos << "Copying " << source << " to " << dest << llendl;

	err = FSCopyObject(	
			&sourceRef,
			&destRef,
			0,
			kFSCatInfoNone,
			kDupeActionReplace,
			NULL,
			false,
			false,
			NULL,
			NULL,
			NULL,
			NULL);

	if(err != noErr) return false;
	return true;
}
Пример #2
0
static void TestFSCopyObject( DupeAction dupeAction)
{
    FSRef			sourceRef,
                    destRef,
                    newRef;
    FSSpec			newSpec;
    OSErr			osErr;

    /* Get the source and destination objects via Nav Services... */
    osErr = ChooseSourceAndDest( &sourceRef, &destRef );
    if( osErr == noErr )
        osErr = FSCopyObject( &sourceRef, &destRef, 0, kFSCatInfoNone,
                              dupeAction, NULL, true, false, MyFilterProc, NULL, &newRef, &newSpec);

    printf( "%s returned: %d", __FUNCTION__, osErr );
    if( osErr == noErr )
    {
        newSpec.name[newSpec.name[0]+1] = '\0';
        printf(", '%s'\n",  newSpec.name+1 );
    }
}
Пример #3
0
void *updatethreadproc(void*)
{
	char tempDir[PATH_MAX] = "";		/* Flawfinder: ignore */
	FSRef tempDirRef;
	char temp[PATH_MAX];	/* Flawfinder: ignore */
	// *NOTE: This buffer length is used in a scanf() below.
	char deviceNode[1024] = "";	/* Flawfinder: ignore */
	FILE *downloadFile = NULL;
	OSStatus err;
	ProcessSerialNumber psn;
	char target[PATH_MAX];		/* Flawfinder: ignore */
	FSRef targetRef;
	FSRef targetParentRef;
	FSVolumeRefNum targetVol;
	FSRef trashFolderRef, tempFolderRef;
	Boolean replacingTarget = false;

	memset(&tempDirRef, 0, sizeof(tempDirRef));
	memset(&targetRef, 0, sizeof(targetRef));
	memset(&targetParentRef, 0, sizeof(targetParentRef));
	
	try
	{
		// Attempt to get a reference to the Second Life application bundle containing this updater.
		// Any failures during this process will cause us to default to updating /Applications/Second Life.app
		{
			FSRef myBundle;

			err = GetCurrentProcess(&psn);
			if(err == noErr)
			{
				err = GetProcessBundleLocation(&psn, &myBundle);
			}

			if(err == noErr)
			{
				// Sanity check:  Make sure the name of the item referenced by targetRef is "Second Life.app".
				FSRefMakePath(&myBundle, (UInt8*)target, sizeof(target));
				
				llinfos << "Updater bundle location: " << target << llendl;
			}
			
			// Our bundle should be in Second Life.app/Contents/Resources/AutoUpdater.app
			// so we need to go up 3 levels to get the path to the main application bundle.
			if(err == noErr)
			{
				err = FSGetParentRef(&myBundle, &targetRef);
			}
			if(err == noErr)
			{
				err = FSGetParentRef(&targetRef, &targetRef);
			}
			if(err == noErr)
			{
				err = FSGetParentRef(&targetRef, &targetRef);
			}
			
			// And once more to get the parent of the target
			if(err == noErr)
			{
				err = FSGetParentRef(&targetRef, &targetParentRef);
			}
			
			if(err == noErr)
			{
				FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
				llinfos << "Path to target: " << target << llendl;
			}
			
			// Sanity check: make sure the target is a bundle with the right identifier
			if(err == noErr)
			{
				// Assume the worst...
				err = -1;

				if(isFSRefViewerBundle(&targetRef))
				{
					// This is the bundle we're looking for.
					err = noErr;
					replacingTarget = true;
				}
			}
			
			// Make sure the target's parent directory is writable.
			if(err == noErr)
			{
				if(!isDirWritable(targetParentRef))
				{
					// Parent directory isn't writable.
					llinfos << "Target parent directory not writable." << llendl;
					err = -1;
					replacingTarget = false;
				}
			}

			if(err != noErr)
			{
				Boolean isDirectory;
				llinfos << "Target search failed, defaulting to /Applications/" << gProductName << ".app." << llendl;
				
				// Set up the parent directory
				err = FSPathMakeRef((UInt8*)"/Applications", &targetParentRef, &isDirectory);
				if((err != noErr) || (!isDirectory))
				{
					// We're so hosed.
					llinfos << "Applications directory not found, giving up." << llendl;
					throw 0;
				}
				
				snprintf(target, sizeof(target), "/Applications/%s.app", gProductName);		

				memset(&targetRef, 0, sizeof(targetRef));
				err = FSPathMakeRef((UInt8*)target, &targetRef, NULL);
				if(err == fnfErr)
				{
					// This is fine, just means we're not replacing anything.
					err = noErr;
					replacingTarget = false;
				}
				else
				{
					replacingTarget = true;
				}

				// Make sure the target's parent directory is writable.
				if(err == noErr)
				{
					if(!isDirWritable(targetParentRef))
					{
						// Parent directory isn't writable.
						llinfos << "Target parent directory not writable." << llendl;
						err = -1;
						replacingTarget = false;
					}
				}

			}
			
			// If we haven't fixed all problems by this point, just bail.
			if(err != noErr)
			{
				llinfos << "Unable to pick a target, giving up." << llendl;
				throw 0;
			}
		}
		
		// Find the volID of the volume the target resides on
		{
			FSCatalogInfo info;
			err = FSGetCatalogInfo(
				&targetParentRef,
				kFSCatInfoVolume,
				&info,
				NULL, 
				NULL,  
				NULL);
				
			if(err != noErr)
				throw 0;
			
			targetVol = info.volume;
		}

		// Find the temporary items and trash folders on that volume.
		err = FSFindFolder(
			targetVol,
			kTrashFolderType,
			true,
			&trashFolderRef);

		if(err != noErr)
			throw 0;

		err = FSFindFolder(
			targetVol,
			kTemporaryFolderType,
			true,
			&tempFolderRef);
		
		if(err != noErr)
			throw 0;
		
		err = FSRefMakePath(&tempFolderRef, (UInt8*)temp, sizeof(temp));

		if(err != noErr)
			throw 0;
		
		temp[0] = '\0';
		strncat(temp, "/SecondLifeUpdate_XXXXXX", sizeof(temp) - 1);
		if(mkdtemp(temp) == NULL)
		{
			throw 0;
		}
		
		strcpy(tempDir, temp);		/* Flawfinder: ignore */
		
		llinfos << "tempDir is " << tempDir << llendl;

		err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);

		if(err != noErr)
			throw 0;
				
		chdir(tempDir);
		
		snprintf(temp, sizeof(temp), "SecondLife.dmg");		
		
		downloadFile = fopen(temp, "wb");		/* Flawfinder: ignore */
		if(downloadFile == NULL)
		{
			throw 0;
		}

		{
			CURL *curl = curl_easy_init();

			curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	//		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback);
			curl_easy_setopt(curl, CURLOPT_FILE, downloadFile);
			curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
			curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func);
			curl_easy_setopt(curl, CURLOPT_URL,	gUpdateURL);
			curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
			
			sendProgress(0, 1, CFSTR("Downloading..."));
			
			CURLcode result = curl_easy_perform(curl);
			
			curl_easy_cleanup(curl);
			
			if(gCancelled)
			{
				llinfos << "User cancel, bailing out."<< llendl;
				throw 0;
			}
			
			if(result != CURLE_OK)
			{
				llinfos << "Error " << result << " while downloading disk image."<< llendl;
				throw 0;
			}
			
			fclose(downloadFile);
			downloadFile = NULL;
		}
		
		sendProgress(0, 0, CFSTR("Mounting image..."));
		LLFile::mkdir("mnt", 0700);
		
		// NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder,
		//		but if our cleanup fails, this makes it much harder for the user to unmount the image.
		LLString mountOutput;
		FILE* mounter = popen("hdiutil attach SecondLife.dmg -mountpoint mnt", "r");		/* Flawfinder: ignore */
		
		if(mounter == NULL)
		{
			llinfos << "Failed to mount disk image, exiting."<< llendl;
			throw 0;
		}
		
		// We need to scan the output from hdiutil to find the device node it uses to attach the disk image.
		// If we don't have this information, we can't detach it later.
		while(mounter != NULL)
		{
			size_t len = fread(temp, 1, sizeof(temp)-1, mounter);
			temp[len] = 0;
			mountOutput.append(temp);
			if(len < sizeof(temp)-1)
			{
				// End of file or error.
				if(pclose(mounter) != 0)
				{
					llinfos << "Failed to mount disk image, exiting."<< llendl;
					throw 0;
				}
				mounter = NULL;
			}
		}
		
		if(!mountOutput.empty())
		{
			const char *s = mountOutput.c_str();
			char *prefix = "/dev/";
			char *sub = strstr(s, prefix);
			
			if(sub != NULL)
			{
				sub += strlen(prefix);	/* Flawfinder: ignore */
				sscanf(sub, "%1023s", deviceNode);	/* Flawfinder: ignore */
			}
		}
		
		if(deviceNode[0] != 0)
		{
			llinfos << "Disk image attached on /dev/" << deviceNode << llendl;
		}
		else
		{
			llinfos << "Disk image device node not found!" << llendl;
		}
		
		// Get an FSRef to the new application on the disk image
		FSRef sourceRef;
		FSRef mountRef;
		snprintf(temp, sizeof(temp), "%s/mnt", tempDir);		

		llinfos << "Disk image mount point is: " << temp << llendl;

		err = FSPathMakeRef((UInt8 *)temp, &mountRef, NULL);
		if(err != noErr)
		{
			llinfos << "Couldn't make FSRef to disk image mount point." << llendl;
			throw 0;
		}

		err = findAppBundleOnDiskImage(&mountRef, &sourceRef);
		if(err != noErr)
		{
			llinfos << "Couldn't find application bundle on mounted disk image." << llendl;
			throw 0;
		}
		
		FSRef asideRef;
		char aside[MAX_PATH];		/* Flawfinder: ignore */
		
		// this will hold the name of the destination target
		HFSUniStr255 appNameUniStr;

		if(replacingTarget)
		{
			// Get the name of the target we're replacing
			err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL);
			if(err != noErr)
				throw 0;
			
			// Move aside old version (into work directory)
			err = FSMoveObject(&targetRef, &tempDirRef, &asideRef);
			if(err != noErr)
				throw 0;

			// Grab the path for later use.
			err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside));
		}
		else
		{
			// Construct the name of the target based on the product name
			char appName[MAX_PATH];		/* Flawfinder: ignore */
			snprintf(appName, sizeof(appName), "%s.app", gProductName);		
			utf8str_to_HFSUniStr255( &appNameUniStr, appName );
		}
		
		sendProgress(0, 0, CFSTR("Copying files..."));
		
		llinfos << "Starting copy..." << llendl;

		// Copy the new version from the disk image to the target location.
		err = FSCopyObject(	
				&sourceRef,
				&targetParentRef,
				0,
				kFSCatInfoNone,
				kDupeActionStandard,
				&appNameUniStr,
				false,
				false,
				NULL,
				NULL,
				&targetRef,
				NULL);
		
		// Grab the path for later use.
		err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
		if(err != noErr)
			throw 0;

		llinfos << "Copy complete. Target = " << target << llendl;

		if(err != noErr)
		{
			// Something went wrong during the copy.  Attempt to put the old version back and bail.
			(void)FSDeleteObjects(&targetRef);
			if(replacingTarget)
			{
				(void)FSMoveObject(&asideRef, &targetParentRef, NULL);
			}
			throw 0;
		}
		else
		{
			// The update has succeeded.  Clear the cache directory.

			sendProgress(0, 0, CFSTR("Clearing cache..."));
	
			llinfos << "Clearing cache..." << llendl;
			
			char mask[LL_MAX_PATH];		/* Flawfinder: ignore */
			snprintf(mask, LL_MAX_PATH, "%s*.*", gDirUtilp->getDirDelimiter().c_str());		
			gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
			
			llinfos << "Clear complete." << llendl;

		}
	}
	catch(...)
	{
		if(!gCancelled)
			if(gFailure == noErr)
				gFailure = -1;
	}

	// Failures from here on out are all non-fatal and not reported.
	sendProgress(0, 3, CFSTR("Cleaning up..."));

	// Close disk image file if necessary
	if(downloadFile != NULL)
	{
		llinfos << "Closing download file." << llendl;

		fclose(downloadFile);
		downloadFile = NULL;
	}

	sendProgress(1, 3);
	// Unmount image
	if(deviceNode[0] != 0)
	{
		llinfos << "Detaching disk image." << llendl;

		snprintf(temp, sizeof(temp), "hdiutil detach '%s'", deviceNode);		
		system(temp);		/* Flawfinder: ignore */
	}

	sendProgress(2, 3);

	// Move work directory to the trash
	if(tempDir[0] != 0)
	{
//		chdir("/");
//		FSDeleteObjects(tempDirRef);

		llinfos << "Moving work directory to the trash." << llendl;

		err = FSMoveObject(&tempDirRef, &trashFolderRef, NULL);

//		snprintf(temp, sizeof(temp), "rm -rf '%s'", tempDir);
//		printf("%s\n", temp);
//		system(temp);
	}
	
	if(!gCancelled  && !gFailure && (target[0] != 0))
	{
		llinfos << "Touching application bundle." << llendl;

		snprintf(temp, sizeof(temp), "touch '%s'", target);		
		system(temp);		/* Flawfinder: ignore */

		llinfos << "Launching updated application." << llendl;

		snprintf(temp, sizeof(temp), "open '%s'", target);		
		system(temp);		/* Flawfinder: ignore */
	}

	sendDone();
	
	return(NULL);
}