/* 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 . */ #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; }