|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 #include "zlib.h" 00032 00036 static update_file_struct *update_files; 00038 static size_t update_files_num; 00039 00044 static void updates_file_new(const char *filename, struct stat *sb) 00045 { 00046 char *contents, *compressed; 00047 size_t st_size, numread; 00048 FILE *fp; 00049 00050 update_files = realloc(update_files, sizeof(update_file_struct) * (update_files_num + 1)); 00051 00052 if (!update_files) 00053 { 00054 LOG(llevError, "updates_file_new(): Out of memory.\n"); 00055 return; 00056 } 00057 00058 st_size = sb->st_size; 00059 /* Allocate a buffer to hold the whole file. */ 00060 contents = malloc(st_size); 00061 00062 if (!contents) 00063 { 00064 LOG(llevError, "updates_file_new(): Out of memory.\n"); 00065 return; 00066 } 00067 00068 fp = fopen(filename, "rb"); 00069 00070 if (!fp) 00071 { 00072 LOG(llevError, "updates_file_new(): Could not open file '%s' for reading.\n", filename); 00073 return; 00074 } 00075 00076 numread = fread(contents, 1, st_size, fp); 00077 fclose(fp); 00078 00079 update_files[update_files_num].filename = strdup(filename + strlen(UPDATES_DIR_NAME) + 1); 00080 update_files[update_files_num].checksum = crc32(1L, (const unsigned char FAR *) contents, numread); 00081 update_files[update_files_num].ucomp_len = numread; 00082 /* Calculate the upper bound of the compressed size. */ 00083 numread = compressBound(st_size); 00084 /* Allocate a buffer to hold the compressed file. */ 00085 compressed = malloc(numread); 00086 00087 if (!compressed) 00088 { 00089 LOG(llevError, "updates_file_new(): Out of memory.\n"); 00090 return; 00091 } 00092 00093 compress2((Bytef *) compressed, (uLong *) &numread, (const unsigned char FAR *) contents, st_size, Z_BEST_COMPRESSION); 00094 update_files[update_files_num].contents = malloc(numread); 00095 00096 if (!update_files[update_files_num].contents) 00097 { 00098 LOG(llevError, "updates_file_new(): Out of memory.\n"); 00099 return; 00100 } 00101 00102 memcpy(update_files[update_files_num].contents, compressed, numread); 00103 update_files[update_files_num].len = numread; 00104 00105 /* Free temporary buffers. */ 00106 free(contents); 00107 free(compressed); 00108 00109 /* 1 for the command type, xxx for the filename, 1 for trailing newline 00110 * of the filename, 4 for original uncompressed length. */ 00111 update_files[update_files_num].sl.buf = malloc(1 + strlen(filename) + 1 + 4 + update_files[update_files_num].len); 00112 /* Set the type. */ 00113 SOCKET_SET_BINARY_CMD(&update_files[update_files_num].sl, BINARY_CMD_FILE_UPD); 00114 /* Add the filename. */ 00115 SockList_AddString(&update_files[update_files_num].sl, update_files[update_files_num].filename); 00116 /* The uncompressed length. */ 00117 SockList_AddInt(&update_files[update_files_num].sl, update_files[update_files_num].ucomp_len); 00118 /* Add the file contents. */ 00119 memcpy(update_files[update_files_num].sl.buf + update_files[update_files_num].sl.len, update_files[update_files_num].contents, update_files[update_files_num].len); 00120 update_files[update_files_num].sl.len += update_files[update_files_num].len; 00121 00122 LOG(llevDebug, " Loaded '%s': ucomp: %"FMT64U", comp: %"FMT64U" (%3.1f%%), CRC32: %lx.\n", filename, (uint64) update_files[update_files_num].ucomp_len, (uint64) numread, (float) (numread * 100) / update_files[update_files_num].ucomp_len, update_files[update_files_num].checksum); 00123 update_files_num++; 00124 } 00125 00131 static int updates_file_compare(const void *a, const void *b) 00132 { 00133 return strcmp(((update_file_struct *) a)->filename, ((update_file_struct *) b)->filename); 00134 } 00135 00140 static update_file_struct *updates_file_find(const char *filename) 00141 { 00142 update_file_struct key; 00143 00144 key.filename = (char *) filename; 00145 return bsearch((void *) &key, (void *) update_files, update_files_num, sizeof(update_file_struct), updates_file_compare); 00146 } 00147 00151 static void updates_traverse(const char *path) 00152 { 00153 DIR *dir = opendir(path); 00154 struct dirent *d; 00155 char filename[HUGE_BUF]; 00156 struct stat sb; 00157 00158 if (!dir) 00159 { 00160 LOG(llevError, "traverse_updates(): Could not open directory '%s'.\n", path); 00161 return; 00162 } 00163 00164 while ((d = readdir(dir))) 00165 { 00166 /* Ignore . and .. entries. */ 00167 if (!strncmp(d->d_name, ".", NAMLEN(d)) || !strncmp(d->d_name, "..", NAMLEN(d))) 00168 { 00169 continue; 00170 } 00171 00172 snprintf(filename, sizeof(filename), "%s/%s", path, d->d_name); 00173 stat(filename, &sb); 00174 00175 /* Go recursively through directories. */ 00176 if (S_ISDIR(sb.st_mode)) 00177 { 00178 updates_traverse(filename); 00179 continue; 00180 } 00181 00182 updates_file_new(filename, &sb); 00183 } 00184 00185 closedir(dir); 00186 } 00187 00191 void updates_init() 00192 { 00193 char path[HUGE_BUF]; 00194 FILE *fp; 00195 size_t i; 00196 00197 update_files = NULL; 00198 update_files_num = 0; 00199 00200 LOG(llevDebug, "Loading client updates...\n"); 00201 updates_traverse(UPDATES_DIR_NAME); 00202 /* Sort the entries. */ 00203 qsort((void *) update_files, update_files_num, sizeof(update_file_struct), (void *) (int (*)()) updates_file_compare); 00204 00205 snprintf(path, sizeof(path), "%s/%s", settings.localdir, UPDATES_FILE_NAME); 00206 LOG(llevDebug, "Creating '%s'...\n", path); 00207 fp = fopen(path, "wb"); 00208 00209 if (!fp) 00210 { 00211 LOG(llevError, "updates_init(): Could not open file '%s' for writing.\n", path); 00212 return; 00213 } 00214 00215 for (i = 0; i < update_files_num; i++) 00216 { 00217 update_file_struct *tmp = &update_files[i]; 00218 00219 fprintf(fp, "%s %"FMT64U" %lx\n", tmp->filename, (uint64) tmp->ucomp_len, tmp->checksum); 00220 } 00221 00222 fclose(fp); 00223 } 00224 00230 void cmd_request_update(char *buf, int len, socket_struct *ns) 00231 { 00232 update_file_struct *tmp; 00233 00234 /* We assume all the update files will have at least 2 letters 00235 * (including directories they are in). */ 00236 if (ns->status != Ns_Add || !buf || len < 2) 00237 { 00238 return; 00239 } 00240 00241 /* Try to find the file. */ 00242 tmp = updates_file_find(buf); 00243 00244 /* Invalid file. */ 00245 if (!tmp) 00246 { 00247 return; 00248 } 00249 00250 Send_With_Handling(ns, &tmp->sl); 00251 }
1.7.4