cGit-UI for Git Repositories

cGit-UI – is a web interface for Git Repositories. cGit CGI script is writen in C and therefore it's fast enough

12 Commits   0 Branches   1 Tag
     5         kx 
     5         kx #ifdef HAVE_CONFIG_H
     5         kx #include <config.h>
     5         kx #endif
     5         kx 
     5         kx #include <stdlib.h>
     5         kx #include <stdio.h>
     5         kx #include <sys/sysinfo.h>
     5         kx #include <sys/types.h>
     5         kx #include <stdint.h>
     5         kx #include <dirent.h>
     5         kx #include <sys/stat.h> /* chmod(2)    */
     5         kx #include <sys/file.h>
     5         kx #include <sys/mman.h>
     5         kx #include <fcntl.h>
     5         kx #include <limits.h>
     5         kx #include <string.h>   /* strdup(3)   */
     5         kx #include <libgen.h>   /* basename(3) */
     5         kx #include <ctype.h>    /* tolower(3)  */
     5         kx #include <errno.h>
     5         kx #include <time.h>
     5         kx #include <sys/time.h>
     5         kx #include <pwd.h>
     5         kx #include <grp.h>
     5         kx #include <stdarg.h>
     5         kx #include <poll.h>
     5         kx #include <unistd.h>
     5         kx 
     5         kx #include <defs.h>
     5         kx #include <wrapper.h>
     5         kx 
     5         kx 
     5         kx #define WRAPPER_ERRMSG_SIZE 4096
     5         kx 
     5         kx void wrapper_error( const char *fmt, ... )
     5         kx {
     5         kx   va_list arg_ptr;
     5         kx   char  buf[WRAPPER_ERRMSG_SIZE];
     5         kx   char  msg[WRAPPER_ERRMSG_SIZE];
     5         kx   char *format = "%s: %s\n";
     5         kx 
     5         kx   va_start( arg_ptr, fmt );
     5         kx 
     5         kx   vsnprintf( msg, WRAPPER_ERRMSG_SIZE, (const void *)fmt, arg_ptr );
     5         kx 
     5         kx   va_end( arg_ptr ); /* Reset variable arguments. */
     5         kx 
     5         kx   snprintf( buf, WRAPPER_ERRMSG_SIZE, format, "wrapper", msg );
     5         kx 
     5         kx   (void)write( STDERR_FILENO, buf, strlen( buf ) );
     5         kx 
     5         kx   exit( 1 );
     5         kx }
     5         kx 
     5         kx wrapper_errfunc wrapper_fatal = wrapper_error;
     5         kx 
     5         kx 
     5         kx char *xstrdup( const char *str )
     5         kx {
     5         kx   char *ret;
     5         kx 
     5         kx   ret = strdup( str );
     5         kx   if( !ret )
     5         kx     wrapper_fatal( "Out of memory, strdup failed" );
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx void *xmalloc( size_t size )
     5         kx {
     5         kx   void *ret;
     5         kx 
     5         kx   ret = malloc( size );
     5         kx   if( !ret )
     5         kx   {
     5         kx     wrapper_fatal( "Out of memory, malloc failed (tried to allocate %lu bytes)", (unsigned long)size );
     5         kx     return NULL;
     5         kx   }
     5         kx   memset( ret, 0, size );
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx void *xrealloc( void *ptr, size_t size )
     5         kx {
     5         kx   void *ret = NULL;
     5         kx 
     5         kx   ret = realloc( ptr, size );
     5         kx   if( !ret && !size )
     5         kx     ret = realloc( ptr, 1 );
     5         kx   if( !ret )
     5         kx     wrapper_fatal( "Out of memory, realloc failed" );
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx /************************************************************************
     5         kx   Limit size of IO chunks, because huge chunks only cause pain.
     5         kx   OS X 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
     5         kx   the absence of bugs, large chunks can result in bad latencies when
     5         kx   you decide to kill the process.
     5         kx 
     5         kx   We pick 8 MiB as our default, but if the platform defines SSIZE_MAX
     5         kx   that is smaller than that, clip it to SSIZE_MAX, as a call to read(2)
     5         kx   or write(2) larger than that is allowed to fail. As the last resort,
     5         kx   we allow a port to pass via CFLAGS e.g. "-DMAX_IO_SIZE=value" to
     5         kx   override this, if the definition of SSIZE_MAX given by the platform
     5         kx   is broken.
     5         kx  ************************************************************************/
     5         kx #ifndef MAX_IO_SIZE
     5         kx # define MAX_IO_SIZE_DEFAULT (8*1024*1024)
     5         kx # if defined(SSIZE_MAX) && (SSIZE_MAX < MAX_IO_SIZE_DEFAULT)
     5         kx #  define MAX_IO_SIZE SSIZE_MAX
     5         kx # else
     5         kx #  define MAX_IO_SIZE MAX_IO_SIZE_DEFAULT
     5         kx # endif
     5         kx #endif
     5         kx 
     5         kx /*
     5         kx   xopen() is the same as open(), but it die()s if the open() fails.
     5         kx  */
     5         kx int xopen( const char *path, int oflag, ... )
     5         kx {
     5         kx   mode_t mode = 0;
     5         kx   va_list ap;
     5         kx 
     5         kx   /*
     5         kx     va_arg() will have undefined behavior if the specified type is not
     5         kx     compatible with the argument type. Since integers are promoted to
     5         kx     ints, we fetch the next argument as an int, and then cast it to a
     5         kx     mode_t to avoid undefined behavior.
     5         kx    */
     5         kx   va_start( ap, oflag );
     5         kx   if( oflag & O_CREAT )
     5         kx     mode = va_arg( ap, int );
     5         kx   va_end( ap );
     5         kx 
     5         kx   for( ;; )
     5         kx   {
     5         kx     int fd = open( path, oflag, mode );
     5         kx     if( fd >= 0 )
     5         kx       return fd;
     5         kx     if( errno == EINTR )
     5         kx       continue;
     5         kx 
     5         kx     if( (oflag & O_RDWR) == O_RDWR )
     5         kx       wrapper_fatal( "could not open '%s' for reading and writing", path );
     5         kx     else if( (oflag & O_WRONLY) == O_WRONLY )
     5         kx       wrapper_fatal( "could not open '%s' for writing", path );
     5         kx     else
     5         kx       wrapper_fatal( "could not open '%s' for reading", path );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static int handle_nonblock( int fd, short poll_events, int err )
     5         kx {
     5         kx   struct pollfd pfd;
     5         kx 
     5         kx   if( err != EAGAIN && err != EWOULDBLOCK )
     5         kx     return 0;
     5         kx 
     5         kx   pfd.fd = fd;
     5         kx   pfd.events = poll_events;
     5         kx 
     5         kx   /*
     5         kx     no need to check for errors, here;
     5         kx     a subsequent read/write will detect unrecoverable errors
     5         kx    */
     5         kx   poll( &pfd, 1, -1 );
     5         kx   return 1;
     5         kx }
     5         kx 
     5         kx /*
     5         kx   xread() is the same a read(), but it automatically restarts read()
     5         kx   operations with a recoverable error (EAGAIN and EINTR). xread()
     5         kx   DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
     5         kx  */
     5         kx ssize_t xread(int fd, void *buf, size_t len)
     5         kx {
     5         kx   ssize_t nr;
     5         kx 
     5         kx   if( len > MAX_IO_SIZE )
     5         kx     len = MAX_IO_SIZE;
     5         kx 
     5         kx   while( 1 )
     5         kx   {
     5         kx     nr = read( fd, buf, len );
     5         kx     if( nr < 0 )
     5         kx     {
     5         kx       if( errno == EINTR )
     5         kx         continue;
     5         kx       if( handle_nonblock(fd, POLLIN, errno) )
     5         kx         continue;
     5         kx     }
     5         kx     return nr;
     5         kx   }
     5         kx }
     5         kx 
     5         kx /*
     5         kx   xwrite() is the same a write(), but it automatically restarts write()
     5         kx   operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
     5         kx   GUARANTEE that "len" bytes is written even if the operation is successful.
     5         kx  */
     5         kx ssize_t xwrite( int fd, const void *buf, size_t len )
     5         kx {
     5         kx   ssize_t nr;
     5         kx 
     5         kx   if( len > MAX_IO_SIZE )
     5         kx     len = MAX_IO_SIZE;
     5         kx 
     5         kx   while( 1 )
     5         kx   {
     5         kx     nr = write( fd, buf, len );
     5         kx     if( nr < 0 )
     5         kx     {
     5         kx       if( errno == EINTR )
     5         kx         continue;
     5         kx       if( handle_nonblock(fd, POLLOUT, errno) )
     5         kx         continue;
     5         kx     }
     5         kx     return nr;
     5         kx   }
     5         kx }
     5         kx 
     5         kx ssize_t read_in_full( int fd, void *buf, size_t count )
     5         kx {
     5         kx   char *p = buf;
     5         kx   ssize_t total = 0;
     5         kx 
     5         kx   while( count > 0 )
     5         kx   {
     5         kx     ssize_t loaded = xread( fd, p, count );
     5         kx 
     5         kx     if (loaded < 0)
     5         kx       return -1;
     5         kx 
     5         kx     if (loaded == 0)
     5         kx       return total;
     5         kx 
     5         kx     count -= loaded;
     5         kx         p += loaded;
     5         kx     total += loaded;
     5         kx   }
     5         kx 
     5         kx   return total;
     5         kx }
     5         kx 
     5         kx ssize_t write_in_full( int fd, const void *buf, size_t count )
     5         kx {
     5         kx   const char *p = buf;
     5         kx   ssize_t total = 0;
     5         kx 
     5         kx   while( count > 0 )
     5         kx   {
     5         kx     ssize_t written = xwrite( fd, p, count );
     5         kx     if( written < 0 )
     5         kx        return -1;
     5         kx 
     5         kx     if( !written )
     5         kx     {
     5         kx       errno = ENOSPC;
     5         kx       return -1;
     5         kx     }
     5         kx     count -= written;
     5         kx         p += written;
     5         kx     total += written;
     5         kx   }
     5         kx 
     5         kx   return total;
     5         kx }
     5         kx 
     5         kx int xdup( int fd )
     5         kx {
     5         kx   int ret = dup( fd );
     5         kx   if( ret < 0 )
     5         kx     wrapper_fatal( "dup failed" );
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx /*
     5         kx   xfopen() is the same as fopen(), but it die()s if the fopen() fails.
     5         kx  */
     5         kx FILE *xfopen( const char *path, const char *mode )
     5         kx {
     5         kx   for( ;;  )
     5         kx   {
     5         kx     FILE *fp = fopen( path, mode );
     5         kx     if (fp)
     5         kx       return fp;
     5         kx     if (errno == EINTR)
     5         kx       continue;
     5         kx 
     5         kx     if( *mode && mode[1] == '+' )
     5         kx       wrapper_fatal( "could not open '%s' for reading and writing", path );
     5         kx     else if( *mode == 'w' || *mode == 'a' )
     5         kx       wrapper_fatal( "could not open '%s' for writing", path );
     5         kx     else
     5         kx       wrapper_fatal( "could not open '%s' for reading", path );
     5         kx   }
     5         kx }
     5         kx 
     5         kx FILE *xfdopen( int fd, const char *mode )
     5         kx {
     5         kx   FILE *stream = fdopen( fd, mode );
     5         kx   if( stream == NULL )
     5         kx     wrapper_fatal( "Out of memory? fdopen failed" );
     5         kx   return stream;
     5         kx }