Annotation of 43BSDReno/contrib/isode-beta/dirent/getcwd.c, revision 1.1.1.1

1.1       root        1: /*
                      2:        getcwd -- get current working directory name (POSIX and SVID compatible)
                      3: 
                      4:        last edit:      21-Sep-1987     D A Gwyn
                      5: 
                      6:        This public-domain getcwd() routine can be used to replace the UNIX
                      7:        System V library routine (which uses popen() to capture the output of
                      8:        the "pwd" command).  Once that is done, "pwd" can be reimplemented as
                      9:        just puts(getcwd()).
                     10: 
                     11:        This implementation depends on every directory having entries for
                     12:        "." and "..".  It also depends on the internals of the <dirent.h>
                     13:        data structures to some degree.
                     14: 
                     15:        I considered using chdir() to ascend the hierarchy, followed by a
                     16:        final chdir() to the path being returned by getcwd() to restore the
                     17:        location, but decided that error recovery was too difficult that way.
                     18:        The algorithm I settled on was inspired by my rewrite of the "pwd"
                     19:        utility, combined with the dotdots[] array trick from the SVR2 shell.
                     20: */
                     21: 
                     22: #include       <sys/types.h>
                     23: #include       <sys/stat.h>
                     24: #include       "usr.dirent.h"
                     25: #include       <errno.h>
                     26: 
                     27: typedef char   *pointer;               /* (void *) if you have it */
                     28: 
                     29: extern void    free();
                     30: extern pointer malloc();
                     31: extern int     fstat(), stat();
                     32: 
                     33: extern int     errno;                  /* normally done by <errno.h> */
                     34: 
                     35: #ifndef NULL
                     36: #define        NULL    0                       /* amorphous null pointer constant */
                     37: #endif
                     38: 
                     39: #ifndef NAME_MAX
                     40: #define        NAME_MAX        255             /* maximum directory entry size */
                     41: #endif
                     42: 
                     43: char   *
                     44: getcwd( buf, size )                    /* returns pointer to CWD pathname */
                     45:        char            *buf;           /* where to put name (NULL to malloc) */
                     46:        int             size;           /* size of buf[] or malloc()ed memory */
                     47:        {
                     48:        static char     dotdots[] =
                     49: "../../../../../../../../../../../../../../../../../../../../../../../../../..";
                     50:        char            *dotdot;        /* -> dotdots[.], right to left */
                     51:        DIR             *dirp;          /* -> parent directory stream */
                     52:        struct dirent   *dir;           /* -> directory entry */
                     53:        struct stat     stat1, stat2;   /* info from stat() */
                     54:        struct stat     *d = &stat1;    /* -> info about "." */
                     55:        struct stat     *dd = &stat2;   /* -> info about ".." */
                     56:        register char   *buffer;        /* local copy of buf, or malloc()ed */
                     57:        char            *bufend;        /* -> buffer[size] */
                     58:        register char   *endp;          /* -> end of reversed string */
                     59:        register char   *dname;         /* entry name ("" for root) */
                     60:        int             serrno = errno; /* save entry errno */
                     61: 
                     62:        if ( size == 0 )
                     63:                {
                     64:                errno = EINVAL;         /* invalid argument */
                     65:                return NULL;
                     66:                }
                     67: 
                     68:        if ( (buffer = buf) == NULL     /* wants us to malloc() the string */
                     69:          && (buffer = (char *)malloc( (unsigned)size )) == NULL
                     70:           )    {
                     71:                errno = ENOMEM;         /* cannot malloc() specified size */
                     72:                return NULL;
                     73:                }
                     74: 
                     75:        if ( stat( ".", dd ) != 0 )     /* prime the pump */
                     76:                goto error;             /* errno already set */
                     77: 
                     78:        endp = buffer;                  /* initially, empty string */
                     79:        bufend = &buffer[size];
                     80: 
                     81:        for ( dotdot = &dotdots[sizeof(dotdots)]; dotdot != dotdots; )
                     82:                {
                     83:                dotdot -= 3;            /* include one more "/.." section */
                     84:                                        /* (first time is actually "..") */
                     85: 
                     86:                /* swap stat() info buffers */
                     87:                {
                     88:                register struct stat    *temp = d;
                     89: 
                     90:                d = dd;                 /* new current dir is old parent dir */
                     91:                dd = temp;
                     92:                }
                     93: 
                     94:                if ( (dirp = opendir( dotdot )) == NULL )       /* new parent */
                     95:                        goto error;     /* errno already set */
                     96: 
                     97:                if ( fstat( dirp->dd_fd, dd ) != 0 )
                     98:                        {
                     99:                        serrno = errno; /* set by fstat() */
                    100:                        (void)closedir( dirp );
                    101:                        errno = serrno; /* in case closedir() clobbered it */
                    102:                        goto error;
                    103:                        }
                    104: 
                    105:                if ( d->st_dev == dd->st_dev )
                    106:                        {               /* not crossing a mount point */
                    107:                        if ( d->st_ino == dd->st_ino )
                    108:                                {       /* root directory */
                    109:                                dname = "";
                    110:                                goto append;
                    111:                                }
                    112: 
                    113:                        do
                    114:                                if ( (dir = readdir( dirp )) == NULL )
                    115:                                        {
                    116:                                        (void)closedir( dirp );
                    117:                                        errno = ENOENT; /* missing entry */
                    118:                                        goto error;
                    119:                                        }
                    120:                        while ( dir->d_ino != d->st_ino );
                    121:                        }
                    122:                else    {               /* crossing a mount point */
                    123:                        struct stat     t;      /* info re. test entry */
                    124:                        char            name[sizeof(dotdots) + 1 + NAME_MAX];
                    125: 
                    126:                        (void)strcpy( name, dotdot );
                    127:                        dname = &name[strlen( name )];
                    128:                        *dname++ = '/';
                    129: 
                    130:                        do      {
                    131:                                if ( (dir = readdir( dirp )) == NULL )
                    132:                                        {
                    133:                                        (void)closedir( dirp );
                    134:                                        errno = ENOENT; /* missing entry */
                    135:                                        goto error;
                    136:                                        }
                    137: 
                    138:                                (void)strcpy( dname, dir->d_name );
                    139:                                /* must fit if NAME_MAX is not a lie */
                    140:                                }
                    141:                        while ( stat( name, &t ) != 0
                    142:                             || t.st_ino != d->st_ino
                    143:                             || t.st_dev != d->st_dev
                    144:                              );
                    145:                        }
                    146: 
                    147:                dname = dir->d_name;
                    148: 
                    149:                /* append "/" and reversed dname string onto buffer */
                    150:     append:
                    151:                if ( endp != buffer     /* avoid trailing / in final name */
                    152:                  || dname[0] == '\0'   /* but allow "/" when CWD is root */
                    153:                   )
                    154:                        *endp++ = '/';
                    155: 
                    156:                {
                    157:                register char   *app;   /* traverses dname string */
                    158: 
                    159:                for ( app = dname; *app != '\0'; ++app )
                    160:                        ;
                    161: 
                    162:                if ( app - dname >= bufend - endp )
                    163:                        {
                    164:                        (void)closedir( dirp );
                    165:                        errno = ERANGE; /* won't fit allotted space */
                    166:                        goto error;
                    167:                        }
                    168: 
                    169:                while ( app != dname )
                    170:                        *endp++ = *--app;
                    171:                }
                    172: 
                    173:                (void)closedir( dirp );
                    174: 
                    175:                if ( dname[0] == '\0' ) /* reached root; wrap it up */
                    176:                        {
                    177:                        register char   *startp;        /* -> buffer[.] */
                    178: 
                    179:                        *endp = '\0';   /* plant null terminator */
                    180: 
                    181:                        /* straighten out reversed pathname string */
                    182:                        for ( startp = buffer; --endp > startp; ++startp )
                    183:                                {
                    184:                                char    temp = *endp;
                    185: 
                    186:                                *endp = *startp;
                    187:                                *startp = temp;
                    188:                                }
                    189: 
                    190:                        errno = serrno; /* restore entry errno */
                    191:                        return buffer;
                    192:                        }
                    193:                }
                    194: 
                    195:        errno = ENOMEM;                 /* actually, algorithm failure */
                    196: 
                    197:     error:
                    198:        if ( buf == NULL )
                    199:                free( (pointer)buffer );
                    200: 
                    201:        return NULL;
                    202:        }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.