void* mmc_map( char* filename, struct stat* sbP, struct timeval* nowP ) { time_t now; struct stat sb; Map* m; int fd; /* Stat the file, if necessary. */ if ( sbP != (struct stat*) 0 ) sb = *sbP; else { if ( stat( filename, &sb ) != 0 ) { syslog( LOG_ERR, "stat - %m" ); return (void*) 0; } } /* Get the current time, if necessary. */ if ( nowP != (struct timeval*) 0 ) now = nowP->tv_sec; else now = time( (time_t*) 0 ); /* See if we have it mapped already, via the hash table. */ if ( check_hash_size() < 0 ) { syslog( LOG_ERR, "check_hash_size() failure" ); return (void*) 0; } m = find_hash( sb.st_ino, sb.st_dev, sb.st_size, sb.st_ctime ); if ( m != (Map*) 0 ) { /* Yep. Just return the existing map */ ++m->refcount; m->reftime = now; return m->addr; } /* Open the file. */ fd = open( filename, O_RDONLY ); if ( fd < 0 ) { syslog( LOG_ERR, "open - %m" ); return (void*) 0; } /* Find a free Map entry or make a new one. */ if ( free_maps != (Map*) 0 ) { m = free_maps; free_maps = m->next; --free_count; } else { m = (Map*) malloc( sizeof(Map) ); if ( m == (Map*) 0 ) { (void) close( fd ); syslog( LOG_ERR, "out of memory allocating a Map" ); return (void*) 0; } ++alloc_count; } /* Fill in the Map entry. */ m->ino = sb.st_ino; m->dev = sb.st_dev; m->size = sb.st_size; m->ctime = sb.st_ctime; m->refcount = 1; m->reftime = now; /* Avoid doing anything for zero-length files; some systems don't like ** to mmap them, other systems dislike mallocing zero bytes. */ if ( m->size == 0 ) m->addr = (void*) 1; /* arbitrary non-NULL address */ else { size_t size_size = (size_t) m->size; /* loses on files >2GB */ #ifdef HAVE_MMAP /* Map the file into memory. */ m->addr = mmap( 0, size_size, PROT_READ, MAP_PRIVATE, fd, 0 ); if ( m->addr == (void*) -1 && errno == ENOMEM ) { /* Ooo, out of address space. Free all unreferenced maps ** and try again. */ panic(); m->addr = mmap( 0, size_size, PROT_READ, MAP_PRIVATE, fd, 0 ); } if ( m->addr == (void*) -1 ) { syslog( LOG_ERR, "mmap - %m" ); (void) close( fd ); free( (void*) m ); --alloc_count; return (void*) 0; } #else /* HAVE_MMAP */ /* Read the file into memory. */ m->addr = (void*) malloc( size_size ); if ( m->addr == (void*) 0 ) { /* Ooo, out of memory. Free all unreferenced maps ** and try again. */ panic(); m->addr = (void*) malloc( size_size ); } if ( m->addr == (void*) 0 ) { syslog( LOG_ERR, "out of memory storing a file" ); (void) close( fd ); free( (void*) m ); --alloc_count; return (void*) 0; } if ( httpd_read_fully( fd, m->addr, size_size ) != size_size ) { syslog( LOG_ERR, "read - %m" ); (void) close( fd ); free( (void*) m ); --alloc_count; return (void*) 0; } #endif /* HAVE_MMAP */ } (void) close( fd ); /* Put the Map into the hash table. */ if ( add_hash( m ) < 0 ) { syslog( LOG_ERR, "add_hash() failure" ); free( (void*) m ); --alloc_count; return (void*) 0; } /* Put the Map on the active list. */ m->next = maps; maps = m; ++map_count; /* Update the total byte count. */ mapped_bytes += m->size; /* And return the address. */ return m->addr; }
void* mmc_map( char* filename, struct stat* sbP ) { struct stat sb; Map* m; int fd; /* Stat the file if necessary. */ if ( sbP != (struct stat*) 0 ) sb = *sbP; else { if ( stat( filename, &sb ) != 0 ) { syslog( LOG_ERR, "stat - %m" ); return (void*) 0; } } /* See if we have it mapped already, via the hash table. */ if ( check_hash_size() < 0 ) { syslog( LOG_ERR, "check_hash_size() failure" ); return (void*) 0; } m = find_hash( sb.st_ino, sb.st_dev, sb.st_size, sb.st_mtime ); if ( m != (Map*) 0 ) { /* Yep. */ ++m->refcount; return m->addr; } /* Nope. Open the file. */ fd = open( filename, O_RDONLY ); if ( fd < 0 ) { syslog( LOG_ERR, "open - %m" ); return (void*) 0; } /* Find a free Map entry or make a new one. */ if ( free_maps != (Map*) 0 ) { m = free_maps; free_maps = m->next; --free_count; } else { m = (Map*) malloc( sizeof(Map) ); if ( m == (Map*) 0 ) { (void) close( fd ); return (void*) 0; } } /* Fill in the Map entry. */ m->ino = sb.st_ino; m->dev = sb.st_dev; m->size = sb.st_size; m->mtime = sb.st_mtime; m->refcount = 1; /* Avoid doing anything for zero-length files; some systems don't like ** to mmap them, other systems dislike mallocing zero bytes. */ if ( m->size == 0 ) m->addr = (void*) 1; /* arbitrary non-NULL address */ else { #ifdef HAVE_MMAP /* Map the file into memory. */ m->addr = mmap( 0, m->size, PROT_READ, MAP_SHARED, fd, 0 ); if ( m->addr == (void*) -1 ) { syslog( LOG_ERR, "mmap - %m" ); (void) close( fd ); free( (void*) m ); return (void*) 0; } #else /* HAVE_MMAP */ /* Read the file into memory. */ m->addr = (void*) malloc( m->size ); if ( m->addr == (void*) 0 ) { syslog( LOG_ERR, "not enough memory" ); (void) close( fd ); free( (void*) m ); return (void*) 0; } if ( read( fd, m->addr, m->size ) != m->size ) { syslog( LOG_ERR, "read - %m" ); (void) close( fd ); free( (void*) m ); return (void*) 0; } #endif /* HAVE_MMAP */ } (void) close( fd ); /* Put the Map into the hash table. */ if ( add_hash( m ) < 0 ) { syslog( LOG_ERR, "add_hash() failure" ); free( (void*) m ); return (void*) 0; } /* Put the Map on the active list. */ m->next = maps; maps = m; ++map_count; /* And return the address. */ return m->addr; }