[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