Annotation of 43BSDReno/contrib/isode-beta/dirent/getcwd.c, revision 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.