Commit 8ea3640398f7d39378ee8b64ecf67fa701265eaf

Authored by Imanol-Mikel Barba Sabariego
1 parent 6f9d59b6

Fixing bugs and changing chunk interface to something more sensible

Showing 2 changed files with 226 additions and 0 deletions
chunk.c 0 → 100644
  1 +#include "chunk.h"
  2 +
  3 +RegionID translateChunkToRegion(int x, int z);
  4 +RegionID translateCoordsToRegion(double x, double y, double z);
  5 +ChunkID translateCoordsToChunk(double x, double y, double z);
  6 +int overwriteChunk(const char* regionFolder, ChunkID chunk, void* chunkData, size_t chunkLength);
  7 +ssize_t loadChunk(const char* regionFolder, ChunkID chunk, void** chunkData);
  8 +
  9 +RegionID translateChunkToRegion(int x, int z) {
  10 + RegionID region;
  11 + region.x = x/CHUNKS_PER_REGION;
  12 + region.z = z/CHUNKS_PER_REGION;
  13 + return region;
  14 +}
  15 +
  16 +RegionID translateCoordsToRegion(double x, double y, double z) {
  17 + ChunkID chunk = translateCoordsToChunk(x,y,z);
  18 + return translateChunkToRegion(chunk.x,chunk.z);
  19 +}
  20 +
  21 +ChunkID translateCoordsToChunk(double x, double y, double z) {
  22 + ChunkID chunk;
  23 + chunk.x = x/BLOCKS_PER_CHUNK;
  24 + chunk.z = z/BLOCKS_PER_CHUNK;
  25 + return chunk;
  26 +}
  27 +
  28 +int overwriteChunk(const char* regionFolder, ChunkID chunk, void* chunkData, size_t chunkLength) {
  29 + RegionID region = translateChunkToRegion(chunk.x,chunk.z);
  30 + ChunkID relativeChunk;
  31 + relativeChunk.x = chunk.x % 32;
  32 + relativeChunk.z = chunk.z % 32;
  33 +
  34 + char* regionFilename = calloc(MAX_REGION_FILENAME_LENGTH + strlen(regionFolder),sizeof(char));
  35 + sprintf(regionFilename,"%s/r.%d.%d.mca.new",regionFolder,region.x,region.z);
  36 +
  37 + if(access(regionFilename,R_OK | W_OK) == -1) {
  38 + fprintf(stderr,"Can't access file %s: %s\n",regionFilename,strerror(errno));
  39 + return -1;
  40 + }
  41 +
  42 + int fd = open(regionFilename,O_RDWR);
  43 + if(fd == -1) {
  44 + fprintf(stderr,"Unable to open region file %s: %s\n",regionFilename,strerror(errno));
  45 + return -2;
  46 + }
  47 + free(regionFilename);
  48 +
  49 + uint32_t chunkHeaderOffset;
  50 + if(pread(fd,&chunkHeaderOffset,sizeof(uint32_t),(relativeChunk.x + relativeChunk.z * CHUNK_OFFSET_LENGTH) * sizeof(uint32_t)) == -1) {
  51 + close(fd);
  52 + fprintf(stderr,"Unable to read chunk header offset: %s\n",strerror(errno));
  53 + return -3;
  54 + }
  55 + uint32_t totalChunkLength = (chunkHeaderOffset >> 24) * 4096;
  56 + chunkHeaderOffset = (__bswap_32(chunkHeaderOffset & 0x00FFFFFF) >> 8) * CHUNK_SECTOR_SIZE;
  57 + int pos = lseek(fd,chunkHeaderOffset,SEEK_SET);
  58 + if(pos == -1) {
  59 + close(fd);
  60 + fprintf(stderr,"Unable to seek to header offset: %s\n",strerror(errno));
  61 + return -4;
  62 + }
  63 +
  64 + ChunkHeader header;
  65 + if(pread(fd,&header,sizeof(ChunkHeader),pos) <= 0) {
  66 + close(fd);
  67 + fprintf(stderr,"Unable to read chunk header: %s\n",strerror(errno));
  68 + return -5;
  69 + }
  70 + header.length = __bswap_32(header.length);
  71 +
  72 + void* compressedChunk;
  73 + ssize_t compressedChunkLength = deflateGzip(chunkData,chunkLength,&compressedChunk,(header.compressionType == COMPRESSION_TYPE_ZLIB));
  74 + if(compressedChunkLength > totalChunkLength) {
  75 + // insert new 4096 blocks
  76 + }
  77 + header.length = __bswap_32((uint32_t)compressedChunkLength+1);
  78 + if(write(fd,&header,sizeof(ChunkHeader)) <= 0) {
  79 + close(fd);
  80 + free(compressedChunk);
  81 + fprintf(stderr,"Unable to read chunk header: %s\n",strerror(errno));
  82 + return -6;
  83 + }
  84 + ssize_t nWritten = 0;
  85 + size_t totalWritten = 0;
  86 +
  87 + while((nWritten = write(fd,compressedChunk+totalWritten,compressedChunkLength-totalWritten))) {
  88 + if(nWritten == -1) {
  89 + if(errno == EINTR) {
  90 + continue;
  91 + }
  92 + fprintf(stderr,"Unable to write chunk: %s\n",strerror(errno));
  93 + close(fd);
  94 + free(compressedChunk);
  95 + return -7;
  96 + }
  97 + totalWritten += nWritten;
  98 + }
  99 + close(fd);
  100 + free(compressedChunk);
  101 + return 0;
  102 +}
  103 +
  104 +ssize_t loadChunk(const char* regionFolder, ChunkID chunk, void** chunkData) {
  105 + RegionID region = translateChunkToRegion(chunk.x,chunk.z);
  106 + ChunkID relativeChunk;
  107 + relativeChunk.x = chunk.x % 32;
  108 + relativeChunk.z = chunk.z % 32;
  109 +
  110 + char* regionFilename = calloc(MAX_REGION_FILENAME_LENGTH + strlen(regionFolder),sizeof(char));
  111 + sprintf(regionFilename,"%s/r.%d.%d.mca",regionFolder,region.x,region.z);
  112 +
  113 + if(access(regionFilename,R_OK) == -1) {
  114 + fprintf(stderr,"Can't access file %s: %s\n",regionFilename,strerror(errno));
  115 + return -1;
  116 + }
  117 +
  118 + int fd = open(regionFilename,O_RDONLY);
  119 + if(fd == -1) {
  120 + fprintf(stderr,"Unable to open region file %s: %s\n",regionFilename,strerror(errno));
  121 + return -2;
  122 + }
  123 + free(regionFilename);
  124 +
  125 + uint32_t chunkHeaderOffset;
  126 + if(pread(fd,&chunkHeaderOffset,sizeof(uint32_t),(relativeChunk.x + relativeChunk.z * CHUNK_OFFSET_LENGTH) * sizeof(uint32_t)) == -1) {
  127 + close(fd);
  128 + fprintf(stderr,"Unable to read chunk header offset: %s\n",strerror(errno));
  129 + return -3;
  130 + }
  131 + chunkHeaderOffset = (__bswap_32(chunkHeaderOffset & 0x00FFFFFF) >> 8) * CHUNK_SECTOR_SIZE;
  132 +
  133 + if(lseek(fd,chunkHeaderOffset,SEEK_SET) == -1) {
  134 + close(fd);
  135 + fprintf(stderr,"Unable to seek to header offset: %s\n",strerror(errno));
  136 + return -4;
  137 + }
  138 +
  139 + ChunkHeader header;
  140 + if(read(fd,&header,sizeof(ChunkHeader)) <= 0) {
  141 + close(fd);
  142 + fprintf(stderr,"Unable to read chunk header: %s\n",strerror(errno));
  143 + return -5;
  144 + }
  145 + header.length = __bswap_32(header.length);
  146 + ssize_t chunkLength = header.length;
  147 +
  148 + void* compressedChunk = calloc(chunkLength,sizeof(char));
  149 + ssize_t nRead = 0;
  150 + size_t totalRead = 0;
  151 +
  152 + while((nRead = read(fd,compressedChunk+totalRead,chunkLength-totalRead))) {
  153 + if(nRead == -1) {
  154 + if(errno == EINTR) {
  155 + continue;
  156 + }
  157 + fprintf(stderr,"Unable to read chunk: %s\n",strerror(errno));
  158 + close(fd);
  159 + free(compressedChunk);
  160 + return -6;
  161 + }
  162 + totalRead += nRead;
  163 + }
  164 + close(fd);
  165 +
  166 + void *decompressedChunk;
  167 + chunkLength = inflateGzip(compressedChunk,chunkLength,&decompressedChunk,(header.compressionType == COMPRESSION_TYPE_ZLIB));
  168 +
  169 + if(chunkLength <= 0) {
  170 + fprintf(stderr,"Error while decompressing chunk\n");
  171 + return -8;
  172 + }
  173 + free(compressedChunk);
  174 +
  175 + *chunkData = decompressedChunk;
  176 + return chunkLength;
  177 +}
0 178 \ No newline at end of file
... ...
chunk.h 0 → 100644
  1 +#ifndef _CHUNK_H
  2 +#define _CHUNK_H
  3 +
  4 +#include <stdlib.h>
  5 +#include <unistd.h>
  6 +#include <stdio.h>
  7 +#include <errno.h>
  8 +#include <fcntl.h>
  9 +#include <stdint.h>
  10 +#include <string.h>
  11 +#include <byteswap.h>
  12 +
  13 +#include "compression.h"
  14 +
  15 +#define BLOCKS_PER_CHUNK 16
  16 +#define CHUNKS_PER_REGION 32
  17 +#define CHUNK_OFFSET_LENGTH 32
  18 +#define CHUNK_SECTOR_SIZE 4096
  19 +
  20 +// 58593 is the maximum number of regions containing 32 chunks in any direction
  21 +// Thus, biggest filename is:
  22 +// r.-58593.-58593.mca
  23 +#define MAX_REGION_FILENAME_LENGTH 32 // Just to round up
  24 +
  25 +enum COMPRESSION_TYPE {
  26 + COMPRESSION_TYPE_GZIP = 1,
  27 + COMPRESSION_TYPE_ZLIB = 2
  28 +};
  29 +
  30 +typedef struct RegionID {
  31 + int x;
  32 + int z;
  33 +} RegionID;
  34 +
  35 +typedef struct ChunkID {
  36 + int x;
  37 + int z;
  38 +} ChunkID;
  39 +
  40 +typedef struct __attribute__((packed)) ChunkHeader {
  41 + uint32_t length;
  42 + uint8_t compressionType;
  43 +} ChunkHeader;
  44 +
  45 +ChunkID translateCoordsToChunk(double x, double y, double z);
  46 +int overwriteChunk(const char* regionFolder, ChunkID chunk, void* chunkData, size_t chunkLength);
  47 +ssize_t loadChunk(const char* regionFolder, ChunkID chunk, void** chunkData);
  48 +
  49 +#endif
0 50 \ No newline at end of file
... ...