hmt/file.c

140 lines
2.4 KiB
C

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <time.h>
#include <strings.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "lint.h"
struct hmt *
open_file(char *filename, int readonly)
{
struct hmt *hmt;
struct stat st;
char *ext;
uint16_t magic;
if (!(hmt = malloc(sizeof(struct hmt))))
{
perror("malloc");
return NULL;
}
if (debug)
printf("Opening file '%s' (readonly=%d)\n", filename, readonly);
strcpy(hmt->fname, filename);
if ((ext = strrchr(hmt->fname, '.')))
{
ext++;
if (debug)
printf(" Extension: '%s'", ext);
if (strcmp(ext, "hmt"))
{
*ext = '\0';
strcat(hmt->fname, "hmt");
}
}
else
strcat(hmt->fname, ".hmt");
if (debug)
printf(" Actual: '%s'\n", hmt->fname);
if (stat(hmt->fname, &st) == -1)
{
perror(hmt->fname);
free(hmt);
return NULL;
}
hmt->binsize = st.st_size;
if (debug)
printf("Opening %s, %lu bytes.\n", hmt->fname,
(unsigned long)hmt->binsize);
hmt->readonly = readonly;
if ((hmt->fd = open(hmt->fname, readonly ? O_RDONLY : O_RDWR, 0)) == -1)
{
perror(hmt->fname);
free(hmt);
return NULL;
}
hmt->bin = (uint8_t *)mmap(NULL, hmt->binsize,
readonly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED, hmt->fd, 0);
if (hmt->bin == MAP_FAILED)
{
if (debug)
printf("mmap() failed, falling back to read.\n");
/* This occurs if the underlying filesystem does not support
* mmap, e.g. NTFS. Fallback to holding the file in memory.
*/
if (!(hmt->bin = (uint8_t *)malloc(hmt->binsize)))
{
perror("malloc");
free(hmt);
close(hmt->fd);
return NULL;
}
read(hmt->fd, hmt->bin, hmt->binsize);
hmt->mmapped = 0;
}
else
{
if (debug)
printf("File mapped into memory.\n");
hmt->mmapped = 1;
}
magic = read_uint16(hmt->bin, 0);
if (magic != 0x1701)
{
printf("Invalid HMT file, %s\n", hmt->fname);
close_file(hmt);
return NULL;
}
hmt->modified = 0;
parse_hmt(hmt);
return hmt;
}
void
close_file(struct hmt *hmt)
{
if (debug)
printf("Closing file.\n");
if (hmt->mmapped)
munmap((void *)hmt->bin, hmt->binsize);
else
{
if (hmt->modified && !hmt->readonly)
{
lseek(hmt->fd, SEEK_SET, 0);
write(hmt->fd, hmt->bin, hmt->binsize);
}
free(hmt->bin);
}
if (hmt->fd > 0)
close(hmt->fd);
hmt->fd = -1;
}