a getwd that works

a getwd that works

Post by pefv.. » Mon, 14 Jan 1991 12:42:45



As was pointed out, I was wrong about getwd(3)'s return value.  Sorry.
Nevertheless, it can fail for pathnames that are too long and I need something
better.

So I wrote my own.  Here's the code with a main() included, effectively making
it pwd(1).  Interestingly enough, for really long pathnames this version will
work ok while the pwd(1) on my machine (a Sun) will cut off part of the
beginning of the pathname.  One caveat: On this Sun, cc -O3 works well.  I did
try it on a Convex and it seemed slow, even with optimization.

All flames and improvements to the code are encouraged.

/* pwd */
/* Christopher Phillips */
/* 1/11/90 */

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/param.h>
#include <malloc.h>

main()
{
    char *cwd, *getwd();

    if ((cwd = getwd()) == NULL) {
        perror("pwd");
        return 1;
    } else {
        printf("%s\n", cwd);
        return 0;
    }

Quote:}

/* From here down (plus the above #include's) is getwd(3) except for
   3 differences:
   1) the calling syntax is now   char *getwd()
   2) the absolute pathname may be longer than MAXPATHLEN
   3) since malloc(3V) (and subsequently realloc(3V))
      is used, the result may be freed using free(3V) */

char **beginptr = NULL, *endptr = NULL;
int length = 0, maxlen = 1;
int rootinode, rootdev;

char *getwd()
{
    char *dir, *buildwd();
    struct stat rootbuf;

    if ((dir = malloc(2)) == NULL) {
        perror("getwd: can't malloc");
        return NULL;
    }
    beginptr = &dir;
    endptr = dir;

    if (stat("/", &rootbuf) == -1) {
        perror("getwd: can't stat /");
        return NULL;
    }
    rootinode = rootbuf.st_ino;
    rootdev = rootbuf.st_dev;

    return buildwd();

Quote:}

/* buildwd recursively "builds" the directory name backwards until the
   root directory is reached, in which case the name is reversed */
static char *buildwd()
{
    ino_t inode;
    dev_t dev;
    int add();
    struct stat stbuf;
    DIR *dfd;
    struct dirent *dp;
    void reverse();

    if (stat(".", &stbuf) == -1) {
        perror("getwd: can't stat .");
        return NULL;
    }
    inode = stbuf.st_ino;
    dev = stbuf.st_dev;
    if (inode == rootinode && dev == rootdev) {
        if (**beginptr == '\0')
            return "/";
        else {
            reverse(*beginptr);
            return *beginptr;
        }
    } else if (chdir("..") == -1) {
        perror("getwd: can't chdir ..");
        return NULL;
    }
    if ((dfd = opendir(".")) == NULL) {
        perror("getwd: can't open dir .");
        return NULL;
    }
    while ((dp = readdir(dfd)) != NULL) {
        if (stat(dp->d_name, &stbuf) == -1) {
            perror("getwd: can't stat .");
            return NULL;
        }
        if (stbuf.st_ino == inode && stbuf.st_dev == dev)
            break;
    }
    if (dp == NULL)
        return NULL;
    if (add(beginptr, &endptr, dp->d_name, dp->d_namlen) == -1)
        return NULL;
    if (buildwd() == NULL)
        return NULL;
    else
        return *beginptr;

Quote:}

/* add reverse "str" and adds it and a "/" to the directory name */
int add(first, last, str, len)
char **first, **last, *str;
int len;
{
    off_t diff;

    if (length + len + 2 > maxlen) {   /* 1 for '/' and 1 for '\0' */
        maxlen += MAXPATHLEN;
        diff = *last - *first;
        if ((*first = realloc(*first, maxlen + 1)) == NULL) {
            perror("getwd: can't realloc");
            return -1;
        }
        *last = *first + diff;
    }
    reverse(str);
    *last = strcpy(*last, str) + len;
    *(*last)++ = '/'; /* realloc will make sure the string is null-terminated */
    return 0;

Quote:}

/* reverse reverse a string so that "string" becomes "gnirts" */
void reverse(s)
char *s;
{
    int len, i;
    char *t, c;

    len = strlen(s);
    t = &s[len - 1];
    for (i = 0; i < len / 2; i++) {
        c = *s;
        *s++ = *t;
        *t-- = c;
    }

Quote:}

 
 
 

1. emacs: `getwd' failed: getwd: can't open ...

Is anybody out there (not in vacation)? I have a question concerning
getpwd on an NFS-mounted filesystem.

Local  host: bimacs, mv3200, ultrix3.0
remote host: birisc, ds5200, ultrix4.0

Bimacs mounts /u/private from birisc, "mount" says:

birisc:/u/private on /nfs/birisc/u/private type nfs (rw,hard,bg,intr,nosuid,rsize=4096,wsize=4096)

Now:

% ls -l /u/private
lrwxr-xr-x  1 root      21 Dec 26 15:58 /u/private -> /nfs/birisc/u/private
% cd /u/private/x/y/z   # cd /nfs/birisc/u/private yields the same results.
% pwd
/u/private/x/y/z
% emacs
emacs: `getwd' failed: getwd: can't open ...
% ls ..
[works]

All other regular commands (cat, less, ls, cp) works fine.

This situation occurs sometimes, usually after a crash+reboot of the
server, even after umount+mount the situation persists. Why ?

--
| Israel Yedidya, Math & CS Department, Bar-Ilan U, Ramat-Gan, ISRAEL. |
+----------------------------------------------------------------------+

|           Uucp: ...!uunet!mcvax!humus!bimacs!yedidya                 |
\----------------------------------------------------------------------/
 \--- If someone proves there is no God, I'll stop being religious ---/
  --------------------------------------------------------------------

2. Another ppp problem

3. getwd() equiv that works over a network?

4. linux on an ibook ?

5. does getwd perform a little magic or what?

6. help with system configuration

7. DOSEMU emumodule screwing up getwd

8. Linux Bridge Job - Dallas, Texas

9. getwd can′t open...

10. use of getwd

11. getwd, getcwd and libc.so.2.5.18 errors

12. replacement getwd(3).

13. GETWD error compiling NCSA HTTPD under Unixware