Rather than using a string-based path, we can restore the working
directory via a file descriptor and use of fchdir().

>From the getcwd manpage:
    Opening the current directory (".") and calling fchdir(2) to
    return is usually a faster and more reliable alternative when
    sufficiently many file descriptors are available.

Signed-off-by: Dan McGee <[email protected]>
---
 lib/libalpm/add.c    |   19 ++++++++++++-------
 lib/libalpm/handle.c |    2 +-
 lib/libalpm/util.c   |   40 ++++++++++++++++++++++++----------------
 3 files changed, 37 insertions(+), 24 deletions(-)

diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index b526145..eb05f84 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -25,6 +25,7 @@
 #include <time.h>
 #include <string.h>
 #include <limits.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -528,8 +529,7 @@ static int commit_single_pkg(alpm_handle_t *handle, 
alpm_pkg_t *newpkg,
        if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) {
                struct archive *archive;
                struct archive_entry *entry;
-               char cwd[PATH_MAX] = "";
-               int restore_cwd = 0;
+               int cwdfd;
 
                _alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n");
 
@@ -551,10 +551,11 @@ static int commit_single_pkg(alpm_handle_t *handle, 
alpm_pkg_t *newpkg,
                }
 
                /* save the cwd so we can restore it later */
-               if(getcwd(cwd, PATH_MAX) == NULL) {
+               do {
+                       cwdfd = open(".", O_RDONLY);
+               } while(cwdfd == -1 && errno == EINTR);
+               if(cwdfd < 0) {
                        _alpm_log(handle, ALPM_LOG_ERROR, _("could not get 
current working directory\n"));
-               } else {
-                       restore_cwd = 1;
                }
 
                /* libarchive requires this for extracting hard links */
@@ -607,8 +608,12 @@ static int commit_single_pkg(alpm_handle_t *handle, 
alpm_pkg_t *newpkg,
                archive_read_finish(archive);
 
                /* restore the old cwd if we have it */
-               if(restore_cwd && chdir(cwd) != 0) {
-                       _alpm_log(handle, ALPM_LOG_ERROR, _("could not change 
directory to %s (%s)\n"), cwd, strerror(errno));
+               if(cwdfd >= 0) {
+                       if(fchdir(cwdfd) != 0) {
+                               _alpm_log(handle, ALPM_LOG_ERROR,
+                                               _("could not restore working 
directory (%s)\n"), strerror(errno));
+                       }
+                       close(cwdfd);
                }
 
                if(errors) {
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 5fb4f2b..dcd81ce 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -115,7 +115,7 @@ int _alpm_handle_lock(alpm_handle_t *handle)
        do {
                fd = open(handle->lockfile, O_WRONLY | O_CREAT | O_EXCL, 0000);
        } while(fd == -1 && errno == EINTR);
-       if(fd > 0) {
+       if(fd >= 0) {
                FILE *f = fdopen(fd, "w");
                fprintf(f, "%ld\n", (long)getpid());
                fflush(f);
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index f4fecab..e2f2f44 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <dirent.h>
+#include <fcntl.h>
 #include <time.h>
 #include <syslog.h>
 #include <errno.h>
@@ -277,8 +278,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char 
*archive, const char *prefix,
        mode_t oldmask;
        struct archive *_archive;
        struct archive_entry *entry;
-       char cwd[PATH_MAX];
-       int restore_cwd = 0;
+       int cwdfd;
 
        if((_archive = archive_read_new()) == NULL) {
                RET_ERR(handle, ALPM_ERR_LIBARCHIVE, 1);
@@ -297,10 +297,11 @@ int _alpm_unpack(alpm_handle_t *handle, const char 
*archive, const char *prefix,
        oldmask = umask(0022);
 
        /* save the cwd so we can restore it later */
-       if(getcwd(cwd, PATH_MAX) == NULL) {
+       do {
+               cwdfd = open(".", O_RDONLY);
+       } while(cwdfd == -1 && errno == EINTR);
+       if(cwdfd < 0) {
                _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current 
working directory\n"));
-       } else {
-               restore_cwd = 1;
        }
 
        /* just in case our cwd was removed in the upgrade operation */
@@ -365,10 +366,14 @@ int _alpm_unpack(alpm_handle_t *handle, const char 
*archive, const char *prefix,
 cleanup:
        umask(oldmask);
        archive_read_finish(_archive);
-       if(restore_cwd && chdir(cwd) != 0) {
-               _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory 
to %s (%s)\n"),
-                               cwd, strerror(errno));
+       if(cwdfd >= 0) {
+               if(fchdir(cwdfd) != 0) {
+                       _alpm_log(handle, ALPM_LOG_ERROR,
+                                       _("could not restore working directory 
(%s)\n"), strerror(errno));
+               }
+               close(cwdfd);
        }
+
        return ret;
 }
 
@@ -490,17 +495,16 @@ int _alpm_logaction(alpm_handle_t *handle, const char 
*fmt, va_list args)
 
 int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const 
argv[])
 {
-       char cwd[PATH_MAX];
        pid_t pid;
-       int pipefd[2];
-       int restore_cwd = 0;
+       int pipefd[2], cwdfd;
        int retval = 0;
 
        /* save the cwd so we can restore it later */
-       if(getcwd(cwd, PATH_MAX) == NULL) {
+       do {
+               cwdfd = open(".", O_RDONLY);
+       } while(cwdfd == -1 && errno == EINTR);
+       if(cwdfd < 0) {
                _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current 
working directory\n"));
-       } else {
-               restore_cwd = 1;
        }
 
        /* just in case our cwd was removed in the upgrade operation */
@@ -598,8 +602,12 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char 
*path, char *const argv[]
        }
 
 cleanup:
-       if(restore_cwd && chdir(cwd) != 0) {
-               _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory 
to %s (%s)\n"), cwd, strerror(errno));
+       if(cwdfd >= 0) {
+               if(fchdir(cwdfd) != 0) {
+                       _alpm_log(handle, ALPM_LOG_ERROR,
+                                       _("could not restore working directory 
(%s)\n"), strerror(errno));
+               }
+               close(cwdfd);
        }
 
        return retval;
-- 
1.7.6.1


Reply via email to