aboutsummaryrefslogtreecommitdiff
path: root/src/pushd.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-05-10 23:12:02 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-05-11 00:28:52 +0300
commitdb81e378576dcc5510032c72060e48e562f208c9 (patch)
tree914c5f277a5fad050527a5c5da815f521e8023dc /src/pushd.c
parent84db86f0151385a8f05483bf691fde86b4e4e153 (diff)
downloadwydawca-db81e378576dcc5510032c72060e48e562f208c9.tar.gz
wydawca-db81e378576dcc5510032c72060e48e562f208c9.tar.bz2
Remove save-cwd.
* src/pushd.c: New file. * src/Makefile.am: Add pushd.c * src/wydawca.h (push_dir, pop_dir): New functions. * src/diskio.c: Use push_dir/pop_dir. * src/exec.c: Likewise. * src/gpg.c: Likewise. * gnulib.modules: Remove save-cwd. * tests/pushck.c: New file. * tests/pushdir.at: New file. * tests/testsuite.at: Add pushdir.at * tests/Makefile.am: Likewise. * tests/.gitignore: Add pushck.
Diffstat (limited to 'src/pushd.c')
-rw-r--r--src/pushd.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/pushd.c b/src/pushd.c
new file mode 100644
index 0000000..6de10a6
--- /dev/null
+++ b/src/pushd.c
@@ -0,0 +1,162 @@
+/* wydawca - automatic release submission daemon
+ Copyright (C) 2011 Sergey Poznyakoff
+
+ Wydawca is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ Wydawca is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with wydawca. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "wydawca.h"
+
+struct saved_dir
+{
+ struct saved_dir *prev;
+ int fd;
+ char *name;
+};
+
+struct saved_dir *dir_stack;
+
+#ifndef O_SEARCH
+# define O_SEARCH 0
+#endif
+
+char *
+getcwd_alloc (void)
+{
+ size_t size = 0;
+ char *buf = NULL;
+ char *p;
+
+ do
+ {
+ if (!buf)
+ {
+ size = 64;
+ buf = malloc (size);
+ }
+ else
+ {
+ char *np;
+ size_t ns = 2 * size;
+ if (ns < size)
+ {
+ free (buf);
+ errno = ENOMEM;
+ return NULL;
+ }
+ size = ns;
+ np = realloc (buf, size);
+ if (!np)
+ free (buf);
+ buf = np;
+ }
+ if (!buf)
+ return NULL;
+ }
+ while ((p = getcwd (buf, size)) == NULL && errno == ERANGE);
+ if (!p)
+ {
+ int ec = errno;
+ free (buf);
+ buf = NULL;
+ errno = ec;
+ }
+ return buf;
+}
+
+static int
+_save_dir (struct saved_dir *sd)
+{
+ int fd;
+
+#ifdef HAVE_FCHDIR
+ fd = open (".", O_SEARCH);
+#else
+ fd = -1;
+#endif
+ if (fd == -1)
+ {
+ sd->name = getcwd_alloc ();
+ if (!sd->name)
+ return errno;
+ }
+ else
+ sd->name = NULL;
+ sd->fd = fd;
+ return 0;
+}
+
+static void
+_drop_dir (struct saved_dir *sd)
+{
+ if (sd->fd != -1)
+ close (sd->fd);
+ free (sd->name);
+ free (sd);
+}
+
+static int
+_push_dir (struct saved_dir *sd, const char *dirname)
+{
+ int rc = _save_dir (sd);
+ if (rc)
+ return rc;
+ if (dirname && chdir (dirname))
+ {
+ rc = errno;
+ _drop_dir (sd);
+ return rc;
+ }
+ return 0;
+}
+
+int
+push_dir (const char *dirname)
+{
+ int rc;
+ struct saved_dir *sd = malloc (sizeof (*sd));
+
+ if (!sd)
+ return errno;
+ rc = _push_dir (sd, dirname);
+ if (rc)
+ {
+ errno = rc;
+ return -1;
+ }
+ sd->prev = dir_stack;
+ dir_stack = sd;
+ return 0;
+}
+
+int
+pop_dir ()
+{
+ struct saved_dir *sd = dir_stack;
+ int rc;
+
+ if (!sd)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ dir_stack = sd->prev;
+ if (sd->fd != -1)
+ rc = fchdir (sd->fd);
+ else
+ rc = chdir (sd->name);
+ if (rc)
+ rc = errno;
+ _drop_dir (sd);
+ errno = rc;
+ return rc;
+}

Return to:

Send suggestions and report system problems to the System administrator.