/* wydawca - automatic release submission daemon Copyright (C) 2011,2013 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; }