Exemplo n.º 1
0
PackageWriter::Entry*
PackageWriter::_RegisterEntry(Entry* parent, const char* name,
	size_t nameLength, bool isImplicit)
{
	// check the component name -- don't allow "." or ".."
	if (*name == '.'
		&& (nameLength == 1 || (nameLength == 2 && name[2] == '.'))) {
		fprintf(stderr, "Error: Invalid file name: \".\" and \"..\" "
			"are not allowed as path components\n");
		throw status_t(B_BAD_VALUE);
	}

	// the entry might already exist
	Entry* entry = parent->GetChild(name, nameLength);
	if (entry != NULL) {
		// If the entry was implicit and is no longer, we mark it non-implicit
		// and delete all of it's children.
		if (entry->IsImplicit() && !isImplicit) {
			entry->DeleteChildren();
			entry->SetImplicit(false);
		}
	} else {
		// nope -- create it
		entry = Entry::Create(name, nameLength, isImplicit);
		parent->AddChild(entry);
	}

	return entry;
}
	virtual status_t HandleEntry(BPackageEntry* entry)
	{
		// create a token
		Token* token = new(std::nothrow) Token;
		if (token == NULL)
			return B_NO_MEMORY;
		ObjectDeleter<Token> tokenDeleter(token);

		// check whether this entry shall be ignored or is implicit
		Entry* parentFilterEntry;
		bool implicit;
		if (entry->Parent() != NULL) {
			Token* parentToken = (Token*)entry->Parent()->UserToken();
			if (parentToken == NULL) {
				// parent is ignored, so ignore this entry, too
				return B_OK;
			}

			parentFilterEntry = parentToken->filterEntry;
			implicit = parentToken->implicit;
		} else {
			parentFilterEntry = &fRootFilterEntry;
			implicit = fRootFilterEntry.IsImplicit();
		}

		Entry* filterEntry = parentFilterEntry != NULL
			? parentFilterEntry->FindChild(entry->Name()) : NULL;

		if (implicit && filterEntry == NULL) {
			// parent is implicit and the filter doesn't include this entry
			// -- ignore it
			return B_OK;
		}

		// If the entry is in the filter, get its implicit flag.
		if (filterEntry != NULL) {
			implicit = filterEntry->IsImplicit();
			filterEntry->SetSeen();
		}

		token->filterEntry = filterEntry;
		token->implicit = implicit;

		// get parent FD and the entry name
		int parentFD;
		const char* entryName;
		_GetParentFDAndEntryName(entry, parentFD, entryName);

		// check whether something is in the way
		struct stat st;
		bool entryExists = fstatat(parentFD, entryName, &st,
			AT_SYMLINK_NOFOLLOW) == 0;
		if (entryExists) {
			if (S_ISREG(entry->Mode()) || S_ISLNK(entry->Mode())) {
				// If the entry in the way is a regular file or a symlink,
				// remove it, otherwise fail.
				if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
					fprintf(stderr, "Error: Can't create entry \"%s\", since "
						"something is in the way\n",
						_EntryPath(entry).String());
					return B_FILE_EXISTS;
				}

				if (unlinkat(parentFD, entryName, 0) != 0) {
					fprintf(stderr, "Error: Failed to unlink entry \"%s\": %s\n",
						_EntryPath(entry).String(), strerror(errno));
					return errno;
				}

				entryExists = false;
			} else if (S_ISDIR(entry->Mode())) {
				// If the entry in the way is a directory, merge, otherwise
				// fail.
				if (!S_ISDIR(st.st_mode)) {
					fprintf(stderr, "Error: Can't create directory \"%s\", "
						"since something is in the way\n",
						_EntryPath(entry).String());
					return B_FILE_EXISTS;
				}
			}
		}

		// create the entry
		int fd = -1;
		if (S_ISREG(entry->Mode())) {
			if (implicit) {
				fprintf(stderr, "Error: File \"%s\" was specified as a "
					"path directory component.\n", _EntryPath(entry).String());
				return B_BAD_VALUE;
			}

			// create the file
			fd = openat(parentFD, entryName, O_RDWR | O_CREAT | O_EXCL,
				S_IRUSR | S_IWUSR);
				// Note: We use read+write user permissions now -- so write
				// operations (e.g. attributes) won't fail, but set them to the
				// desired ones in HandleEntryDone().
			if (fd < 0) {
				fprintf(stderr, "Error: Failed to create file \"%s\": %s\n",
					_EntryPath(entry).String(), strerror(errno));
				return errno;
			}

			// write data
			status_t error;
			const BPackageData& data = entry->Data();
			if (data.IsEncodedInline()) {
				BBufferDataReader dataReader(data.InlineData(),
					data.CompressedSize());
				error = _ExtractFileData(&dataReader, data, fd);
			} else
				error = _ExtractFileData(&fPackageFileReader, data, fd);

			if (error != B_OK)
				return error;
		} else if (S_ISLNK(entry->Mode())) {
			if (implicit) {
				fprintf(stderr, "Error: Symlink \"%s\" was specified as a "
					"path directory component.\n", _EntryPath(entry).String());
				return B_BAD_VALUE;
			}

			// create the symlink
			const char* symlinkPath = entry->SymlinkPath();
			if (symlinkat(symlinkPath != NULL ? symlinkPath : "", parentFD,
					entryName) != 0) {
				fprintf(stderr, "Error: Failed to create symlink \"%s\": %s\n",
					_EntryPath(entry).String(), strerror(errno));
				return errno;
			}
// TODO: Set symlink permissions?
 		} else if (S_ISDIR(entry->Mode())) {
			// create the directory, if necessary
			if (!entryExists
				&& mkdirat(parentFD, entryName, S_IRWXU) != 0) {
				// Note: We use read+write+exec user permissions now -- so write
				// operations (e.g. attributes) won't fail, but set them to the
				// desired ones in HandleEntryDone().
				fprintf(stderr, "Error: Failed to create directory \"%s\": "
					"%s\n", _EntryPath(entry).String(), strerror(errno));
				return errno;
			}
		} else {
			fprintf(stderr, "Error: Invalid file type for entry \"%s\"\n",
				_EntryPath(entry).String());
			return B_BAD_DATA;
		}

		// If not done yet (symlink, dir), open the node -- we need the FD.
		if (fd < 0 && (!implicit || S_ISDIR(entry->Mode()))) {
			fd = openat(parentFD, entryName, O_RDONLY | O_NOTRAVERSE);
			if (fd < 0) {
				fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n",
					_EntryPath(entry).String(), strerror(errno));
				return errno;
			}
		}
		token->fd = fd;

		// set the file times
		if (!entryExists && !implicit) {
			timespec times[2] = {entry->AccessTime(), entry->ModifiedTime()};
			futimens(fd, times);

			// set user/group
			// TODO:...
		}

		entry->SetUserToken(tokenDeleter.Detach());
		return B_OK;
	}