Example #1
0
	def create(self, size_bytes):
		# Check to make sure the file doesn't already exist.
		if (self.exists()):
			raise PackageAlreadyExistsException()

		# Create a temporary folder for working in.
		tempfolder = tempfile.mkdtemp("", self.appname_prefix + "_build_area.", "/tmp/")
		log.showInfoW("Total size for Ext2 partition will be: " + str(float(size_bytes) / (1024 * 1024)) + " MB")

		# Create a zero'd file so that we can partition it.
		log.showInfoW("Creating zero'd file at " + os.path.join(tempfolder, "app.ext2") + "...")
		with open(os.path.join(tempfolder, "app.ext2"), "w") as f:
			f.write("".ljust(int(size_bytes), "\0"))

		# Now format the zero'd file.
		log.showInfoW("Formatting Ext2 partition at " + os.path.join(tempfolder, "app.ext2") + "...")
		if (environment.runSilent(["mkfs.ext2", "-F", "-t", "ext2", os.path.join(tempfolder, "app.ext2")]) != 0):
			log.showErrorW("An error occurred while formatting the Ext2 partition.")
			raise PackageCreationFailureException()

		# Attach the blank partition to the AppFS bootstrapping binary.
		log.showInfoW("Attaching Ext2 partition to AppFS file at " + os.path.join(tempfolder, "app.afs") + "...")
		if (subprocess.call(["appattach", os.path.join(tempfolder, "app.ext2"), os.path.join(tempfolder, "app.afs")]) != 0):
			log.showErrorW("An error occurred while attaching the Ext2 partition to")
			log.showErrorO("the AppFS binary.  Check above for error messages.")
			raise PackageCreationFailureException()

		# Move the newly created package to the new location.
		log.showInfoW("Moving package to " + self.filename + "...")
		try:
			os.rename(os.path.join(tempfolder, "app.afs"), self.filename)
		except:
			log.showErrorW("Failed to move AppFS package to target.")
			raise PackageCreationFailureException()
		log.showSuccessW("Package successfully created.")
		
		# Remove our temporary files
		try:
			self.forceFileRemoval(os.path.join(tempfolder, "app.afs"))
			self.forceFileRemoval(os.path.join(tempfolder, "app.ext2"))
			os.rmdir(tempfolder)
			log.showSuccessW("Cleaned up temporary working directory.")
		except:
			log.showErrorW("Unable to clean up working directory at: " + tempfolder)
			log.showErrorO("Please remove directory manually.")
		
		return True
Example #2
0
	def unlink(self):
		"""Unlink an application from the base filesystem."""
		adiff = ApplicationDifferencer()

		# Determine the differences between what's in the
		# application's directory and what's currently
		# available from the root filesystem (in relation
		# to this application).
		results = adiff.scan(
				os.path.join(
					AppFolders.get(self.type),
					self.name + "/" + self.version
					),
				True
				);
		
		safe_app_dir = os.path.join(
                                        AppFolders.get(self.type),
                                        self.name # We exclude the version here because we could be
                                                  # checking against a link that's under Current or
                                                  # a specific version.
                                        )
		
		# Preemptively go through the list of directories, removing those
		# that are symlinks to the application folder.  This is from the legacy
		# link system and unfortunatly if you let the block below this run
		# through a system with said symlinks, you'll end up annihilating the
		# the application files (because it'll walk through the symlink into
		# the application directory and start rm'ing stuff we don't want to)
		# The solution here is to go through and remove directory symlinks before
		# hand, with a reversed result list (in effect reversing the walk process
		# in adiff.scan) so that we elimate the top level symlinks first, preventing
		# it from annihilating symlinked directories inside the application folder.
		# Very annoying stuff.
		#
		# XXX: I almost hosed the entire Elementary system with this.  Apparently it
		#      that removing symlinked directories included some of the base ones
		#      such as /lib and /bin (because the Python install contains those dirs
		#      too :P).  The only_sub variable defines that only paths that resolve
		#      to a *subdirectory* of those specified can be removed if it's a symlinked
		#      directory.  This prevents removal of /bin, /lib, etc.. symlinks.
		#
		only_sub = [
				"/System/Utilities/Applications",
				"/System/Utilities/Libraries",
				"/Applications",
				"/Users"
			]
		results.reverse()
		trip_safety = False
		for i in results:
			# Legacy removal is a special case because directories will be detected
			# as file entries (because they are symlinks).  Therefore, we need to use
			# os.path.realpath and os.path.isdir to find out whether it's really a directory
			# or not.
			is_directory = os.path.isdir(os.path.realpath(i[2]))

			# Get file information.
			try:
				pstat = os.lstat(i[2])[stat.ST_MODE]
			except:
				# Likely broken when we removed a directory symlink.
				continue
			
			# Determine whether we should proceed with this entry.
			if (not is_directory):
				continue
			if (not stat.S_ISLNK(pstat)):
				continue

			# Determine whether it's safe to remove this symlinked dir.
			if (not self.isApplicationOwned(i[2], safe_app_dir)):
				continue
			
			# Double-check before we go unlinking (in case of a logic oversight).
			if (is_directory and stat.S_ISLNK(pstat)):
				trip_safety = True
				try:
					self.oper_unlink(i[2])
					log.showWarningW("Removed symlinked directory at: " + i[2])
					log.showWarningW("The full path was: " + rpath)
				except:
					pass
		results.reverse()		

		if (trip_safety):
			log.showErrorW("Legacy system safety switch was tripped.  This indicates you have")
			log.showErrorO("symlinked directories on your system (from legacy linkage systems).")
			log.showErrorO("The unlinking process has removed at least one of those symlinked")
			log.showErrorO("directories.  In order to make sure application files don't get")
			log.showErrorO("removed, you need to run the unlink process again to ensure the system")
			log.showErrorO("is scanned without symlinked directories.  If the process shows this")
			log.showErrorO("message twice, then STOP and REMOVE THE SYMLINKS MANUALLY.  You risk")
			log.showErrorO("destroying application installations if you continue.")
			sys.exit(1)
		

		# Now go through the results, removing directories (if they're
		# empty) and un-symlinking files (but making sure that we only
		# remove symlinks and not normal files).
		attempt_successes = list()
		attempt_failures = list()
		attempt_notexists = list()
		total_files = 0
		for i in results:
			total_files += 1
			try:
				pstat = os.lstat(i[2])[stat.ST_MODE]
			except:
				# File doesn't exist.  Likely got removed while we unlinked
				# a `symlinked' directory (from old linkage system).
				continue

			# Check to make sure that the file we're going to remove is located
			# within a safe directory.
			if (not self.isApplicationOwned(i[2], safe_app_dir)):
				# This check only applies to symlinks, not real directories.
				if ((i[0] == "file" or i[0] == "directory") and stat.S_ISLNK(pstat)):
					log.showInfoW("Ignoring " + i[2] + " because it's not owned by the application.")
					continue

			if (i[0] == "directory" and not stat.S_ISLNK(pstat)):
				try:
					self.oper_rmdir(i[2])
					attempt_successes.append(i[2])
				except:
					log.showInfoW("Still in use: " + i[2])
					# Failure to remove a directory should not be counted
					# as a failure since quite often directories will not be
					# removed because they are still in use by other applications.
					#attempt_failures.append(i[2])
			elif ((i[0] == "file" or i[0] == "directory") and stat.S_ISLNK(pstat)):
				try:
					self.oper_unlink(i[2])
					attempt_successes.append(i[2])
				except:
					log.showErrorW("Unable to symlink file " + i[2])
					attempt_failures.append(i[2])
			elif (i[0] == "notexists"):
				log.showInfoW("  N " + i[2])
				attempt_notexists.append(i[2])
			elif (i[0] != "notexists" and i[0] != "file" and i[0] != "directory"):
				log.showWarningW("Unknown operation for " + i[1])

		return attempt_successes, attempt_failures, total_files