[Haiku-commits] r24849 - haiku/trunk/src/bin

bonefish at BerliOS bonefish at mail.berlios.de
Mon Apr 7 01:40:13 CEST 2008


Author: bonefish
Date: 2008-04-07 01:40:12 +0200 (Mon, 07 Apr 2008)
New Revision: 24849
ViewCVS: http://svn.berlios.de/viewcvs/haiku?rev=24849&view=rev

Added:
   haiku/trunk/src/bin/diff_zip.cpp
Modified:
   haiku/trunk/src/bin/Jamfile
Log:
Added small tool diff_zip that I used for building the latest optional
packages.


Modified: haiku/trunk/src/bin/Jamfile
===================================================================
--- haiku/trunk/src/bin/Jamfile	2008-04-06 23:28:50 UTC (rev 24848)
+++ haiku/trunk/src/bin/Jamfile	2008-04-06 23:40:12 UTC (rev 24849)
@@ -23,6 +23,7 @@
 	clear.c
 	clockconfig.c
 #	csplit.c
+	diff_zip.cpp
 	driveinfo.c
 #	echo.c
 	eject.c

Added: haiku/trunk/src/bin/diff_zip.cpp
===================================================================
--- haiku/trunk/src/bin/diff_zip.cpp	2008-04-06 23:28:50 UTC (rev 24848)
+++ haiku/trunk/src/bin/diff_zip.cpp	2008-04-06 23:40:12 UTC (rev 24849)
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2008, Ingo Weinhold, ingo_weinhold at gmx.de. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+
+
+using std::string;
+using std::map;
+
+
+class Directory;
+class Node;
+
+static Node* create_node(Directory* parent, const string& name,
+	const struct stat& st);
+
+
+enum diff_status {
+	DIFF_UNCHANGED,
+	DIFF_REMOVED,
+	DIFF_CHANGED,
+	DIFF_ERROR
+};
+
+
+class EntryWriter {
+public:
+	EntryWriter(int fd)
+		: fFD(fd)
+	{
+	}
+
+	void Write(const char* entry)
+	{
+		write(fFD, entry, strlen(entry));
+		write(fFD, "\n", 1);
+	}
+
+private:
+	int	fFD;
+};
+
+
+class Node {
+public:
+	Node(Directory* parent, const string& name, const struct stat& st)
+		: fParent(parent),
+		  fName(name),
+		  fStat(st)
+	{
+	}
+
+	virtual ~Node()
+	{
+	}
+
+	Directory* Parent() const		{ return fParent; }
+	const string& Name() const		{ return fName; }
+	const struct stat& Stat() const	{ return fStat; }
+
+	string Path() const;
+
+	bool DoStat(struct stat& st) const
+	{
+		string path(Path());
+		if (lstat(path.c_str(), &st) != 0)
+			return false;
+		return true;
+	}
+
+	virtual bool Scan()
+	{
+		return true;
+	}
+
+	virtual diff_status CollectDiffEntries(EntryWriter* out) const
+	{
+		string path(Path());
+		struct stat st;
+
+		diff_status status = DiffEntry(path, st);
+		if (status == DIFF_CHANGED)
+			out->Write(path.c_str());
+
+		return status;
+	}
+
+	virtual void Dump(int level) const
+	{
+		printf("%*s%s\n", level, "", fName.c_str());
+	}
+
+protected:
+	diff_status DiffEntry(const string& path, struct stat& st) const
+	{
+		if (lstat(path.c_str(), &st) == 0) {
+			if (st.st_mode != fStat.st_mode
+				|| st.st_mtime != fStat.st_mtime
+				|| st.st_size != fStat.st_size) {
+				return DIFF_CHANGED;
+			}
+			return DIFF_UNCHANGED;
+		} else if (errno == ENOENT) {
+			// that's OK, the entry was removed
+			return DIFF_REMOVED;
+		} else {
+			// some error
+			fprintf(stderr, "Error: Failed to stat \"%s\": %s\n",
+				path.c_str(), strerror(errno));
+			return DIFF_ERROR;
+		}
+	}
+
+private:
+	Directory*	fParent;
+	string		fName;
+	struct stat	fStat;
+};
+
+
+class Directory : public Node {
+public:
+	Directory(Directory* parent, const string& name, const struct stat& st)
+		: Node(parent, name, st),
+		  fEntries()
+	{
+	}
+
+	void AddEntry(const char* name, Node* node)
+	{
+		fEntries[name] = node;
+	}
+
+	virtual bool Scan()
+	{
+		string path(Path());
+		DIR* dir = opendir(path.c_str());
+		if (dir == NULL) {
+			fprintf(stderr, "Error: Failed to open directory \"%s\": %s\n",
+				path.c_str(), strerror(errno));
+			return false;
+		}
+
+		errno = 0;
+		while (dirent* entry = readdir(dir)) {
+			if (strcmp(entry->d_name, ".") == 0
+				|| strcmp(entry->d_name, "..") == 0) {
+				continue;
+			}
+
+			string entryPath = path + '/' + entry->d_name;
+			struct stat st;
+			if (lstat(entryPath.c_str(), &st) != 0) {
+				fprintf(stderr, "Error: Failed to stat entry \"%s\": %s\n",
+					entryPath.c_str(), strerror(errno));
+				closedir(dir);
+				return false;
+			}
+
+			Node* node = create_node(this, entry->d_name, st);
+			fEntries[entry->d_name] = node;
+
+			errno = 0;
+		}
+
+		if (errno != 0) {
+			fprintf(stderr, "Error: Failed to read directory \"%s\": %s\n",
+				path.c_str(), strerror(errno));
+			closedir(dir);
+			return false;
+		}
+
+		closedir(dir);
+
+		// recursively scan the entries
+		for (EntryMap::iterator it = fEntries.begin(); it != fEntries.end();
+				++it) {
+			Node* node = it->second;
+			if (!node->Scan())
+				return false;
+		}
+
+		return true;
+	}
+
+	virtual diff_status CollectDiffEntries(EntryWriter* out) const
+	{
+		string path(Path());
+		struct stat st;
+
+		diff_status status = DiffEntry(path, st);
+		if (status == DIFF_REMOVED || status == DIFF_ERROR)
+			return status;
+
+		// we print it only if it is no longer a directory
+		if (!S_ISDIR(st.st_mode)) {
+			out->Write(path.c_str());
+			return DIFF_CHANGED;
+		}
+
+		// iterate through the "new" entries
+		DIR* dir = opendir(path.c_str());
+		if (dir == NULL) {
+			fprintf(stderr, "Error: Failed to open directory \"%s\": %s\n",
+				path.c_str(), strerror(errno));
+			return DIFF_ERROR;
+		}
+
+		errno = 0;
+		while (dirent* entry = readdir(dir)) {
+			if (strcmp(entry->d_name, ".") == 0
+				|| strcmp(entry->d_name, "..") == 0) {
+				continue;
+			}
+
+			EntryMap::const_iterator it = fEntries.find(entry->d_name);
+			if (it == fEntries.end()) {
+				// new entry
+				string entryPath = path + "/" + entry->d_name;
+				out->Write(entryPath.c_str());
+			} else {
+				// old entry -- recurse
+				diff_status entryStatus = it->second->CollectDiffEntries(out);
+				if (entryStatus == DIFF_ERROR) {
+					closedir(dir);
+					return status;
+				}
+				if (entryStatus != DIFF_UNCHANGED)
+					status = DIFF_CHANGED;
+			}
+
+			errno = 0;
+		}
+
+		if (errno != 0) {
+			fprintf(stderr, "Error: Failed to read directory \"%s\": %s\n",
+				path.c_str(), strerror(errno));
+			closedir(dir);
+			return DIFF_ERROR;
+		}
+
+		closedir(dir);
+		return status;
+	}
+
+	virtual void Dump(int level) const
+	{
+		Node::Dump(level);
+
+		for (EntryMap::const_iterator it = fEntries.begin();
+				it != fEntries.end(); ++it) {
+			it->second->Dump(level + 1);
+		}
+	}
+
+
+private:
+	typedef map<string, Node*> EntryMap;
+
+	EntryMap	fEntries;
+};
+
+
+string
+Node::Path() const
+{
+	if (fParent == NULL)
+		return fName;
+
+	return fParent->Path() + '/' + fName;
+}
+
+
+static Node*
+create_node(Directory* parent, const string& name, const struct stat& st)
+{
+	if (S_ISDIR(st.st_mode))
+		return new Directory(parent, name, st);
+	return new Node(parent, name, st);
+}
+
+
+int
+main(int argc, const char* const* argv)
+{
+	// the paths are listed after a "--" argument
+	int argi = 1;
+	for (; argi < argc; argi++) {
+		if (strcmp(argv[argi], "--") == 0)
+			break;
+	}
+
+	if (argi + 1 >= argc) {
+		fprintf(stderr, "Usage: %s <zip arguments> ... -- <paths>\n", argv[0]);
+		exit(1);
+	}
+
+	int zipArgCount = argi;
+	const char* const* paths = argv + argi + 1;
+	int pathCount = argc - argi - 1;
+
+	// snapshot the hierarchy
+	Node** rootNodes = new Node*[pathCount];
+
+	for (int i = 0; i < pathCount; i++) {
+		const char* path = paths[i];
+		struct stat st;
+		if (lstat(path, &st) != 0) {
+			fprintf(stderr, "Error: Failed to stat \"%s\": %s\n", path,
+				strerror(errno));
+			exit(1);
+		}
+
+		rootNodes[i] = create_node(NULL, path, st);
+		if (!rootNodes[i]->Scan())
+			exit(1);
+	}
+
+	// create a temp file
+	char tmpFileName[64];
+	sprintf(tmpFileName, "/tmp/diff_zip_%d_XXXXXX", (int)getpid());
+	int tmpFileFD = mkstemp(tmpFileName);
+	if (tmpFileFD < 0) {
+		fprintf(stderr, "Error: Failed create temp file: %s\n",
+			strerror(errno));
+		exit(1);
+	}
+	unlink(tmpFileName);
+
+	// wait
+	{
+		printf("Waiting for changes. Press RETURN to continue...");
+		fflush(stdout);
+		char buffer[32];
+		fgets(buffer, sizeof(buffer), stdin);
+	}
+
+	EntryWriter tmpFile(tmpFileFD);
+
+	for (int i = 0; i < pathCount; i++) {
+		if (rootNodes[i]->CollectDiffEntries(&tmpFile) == DIFF_ERROR)
+			exit(1);
+	}
+
+	// dup the temp file FD to our stdin and exec()
+	dup2(tmpFileFD, 0);
+	close(tmpFileFD);
+	lseek(0, 0, SEEK_SET);
+
+	char** zipArgs = new char*[zipArgCount + 2];
+	zipArgs[0] = strdup("zip");
+	zipArgs[1] = strdup("-@");
+	for (int i = 1; i < zipArgCount; i++)
+		zipArgs[i + 1] = strdup(argv[i]);
+	zipArgs[zipArgCount + 1] = NULL;
+
+	execvp("zip", zipArgs);
+
+	fprintf(stderr, "Error: Failed exec*() zip: %s\n", strerror(errno));
+
+	return 1;
+}




More information about the Haiku-commits mailing list