Atrinik Server 2.5
server/porting.c
Go to the documentation of this file.
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 
00034 #include <global.h>
00035 
00037 static uint32 curtmp = 0;
00038 
00047 char *tempnam_local(const char *dir, const char *pfx)
00048 {
00049     char *name;
00050     pid_t pid = getpid();
00051 
00052     if (!pfx)
00053     {
00054         pfx = "tmp.";
00055     }
00056 
00057     /* This is a pretty simple method - put the pid as a hex digit and
00058      * just keep incrementing the last digit. Check to see if the file
00059      * already exists - if so, we'll just keep looking - eventually we
00060      * should find one that is free. */
00061     if (dir)
00062     {
00063         if (!(name = (char *) malloc(MAXPATHLEN)))
00064         {
00065             return NULL;
00066         }
00067 
00068         do
00069         {
00070             snprintf(name, MAXPATHLEN, "%s/%s%hx.%d", dir, pfx, pid, curtmp);
00071             curtmp++;
00072         }
00073         while (access(name, F_OK) != -1);
00074 
00075         return name;
00076     }
00077 
00078     return NULL;
00079 }
00080 
00087 char *strdup_local(const char *str)
00088 {
00089     size_t len = strlen(str) + 1;
00090     void *new = malloc(len);
00091 
00092     if (!new)
00093     {
00094         return NULL;
00095     }
00096 
00097     return (char *) memcpy(new, str, len);
00098 }
00099 
00105 char *strerror_local(int errnum)
00106 {
00107 #if defined(HAVE_STRERROR)
00108     return strerror(errnum);
00109 #else
00110 #   error Missing strerror().
00111 #endif
00112 }
00113 
00118 unsigned long isqrt(unsigned long n)
00119 {
00120     unsigned long op = n, res = 0, one;
00121 
00122     /* "one" starts at the highest power of four <= than the argument. */
00123     one = 1 << 30;
00124 
00125     while (one > op)
00126     {
00127         one >>= 2;
00128     }
00129 
00130     while (one != 0)
00131     {
00132         if (op >= res + one)
00133         {
00134             op -= res + one;
00135             /* Faster than 2 * one. */
00136             res += one << 1;
00137         }
00138 
00139         res >>= 1;
00140         one >>= 2;
00141     }
00142 
00143     return res;
00144 }
00145 
00153 char *uncomp[NROF_COMPRESS_METHODS][3] =
00154 {
00155     {NULL, NULL, NULL},
00156     {".Z", UNCOMPRESS, COMPRESS},
00157     {".gz", GUNZIP, GZIP},
00158     {".bz2", BUNZIP, BZIP}
00159 };
00160 
00172 static FILE *open_and_uncompress_file(const char *ext, const char *uncompressor, const char *name, int flag, int *compressed)
00173 {
00174     struct stat st;
00175     char buf[MAX_BUF], buf2[MAX_BUF];
00176     int ret;
00177 
00178     if (!ext)
00179     {
00180         ext = "";
00181     }
00182 
00183     if (strlen(name) + strlen(ext) >= sizeof(buf))
00184     {
00185         /* File name too long */
00186         errno = ENAMETOOLONG;
00187         return NULL;
00188     }
00189 
00190     snprintf(buf, sizeof(buf), "%s%s", name, ext);
00191 
00192     if (stat(buf, &st) != 0)
00193     {
00194         return NULL;
00195     }
00196 
00197     if (!S_ISREG(st.st_mode))
00198     {
00199         /* Not a regular file */
00200         errno = EISDIR;
00201         return NULL;
00202     }
00203 
00204     if (uncompressor == NULL)
00205     {
00206         /* Open without uncompression */
00207         return fopen(buf, "rb");
00208     }
00209 
00210     /* The file name buf (and its substring name) is passed as an argument to a
00211      * shell command, therefore check for characters that could confuse the
00212      * shell. */
00213     if (strpbrk(buf, "'\\\r\n") != NULL)
00214     {
00215         /* Pretend the file does not exist */
00216         errno = ENOENT;
00217         return NULL;
00218     }
00219 
00220     if (!flag)
00221     {
00222         /* Uncompress via pipe */
00223         if (strlen(uncompressor) + 4 + strlen(buf) + 1 >= sizeof(buf2))
00224         {
00225             /* File name too long */
00226             errno = ENAMETOOLONG;
00227             return NULL;
00228         }
00229 
00230         snprintf(buf2, sizeof(buf2), "%s < '%s'", uncompressor, buf);
00231         return popen(buf2, "r");
00232     }
00233 
00234     /* Remove compression from file, then open file */
00235     if (stat(name, &st) == 0 && !S_ISREG(st.st_mode))
00236     {
00237         errno = EISDIR;
00238         return NULL;
00239     }
00240 
00241     if (strlen(uncompressor) + 4 + strlen(buf) + 5 + strlen(name) + 1 >= sizeof(buf2))
00242     {
00243         /* File name too long */
00244         errno = ENAMETOOLONG;
00245         return NULL;
00246     }
00247 
00248     snprintf(buf2, sizeof(buf2), "%s < '%s' > '%s'", uncompressor, buf, name);
00249 
00250     ret = system(buf2);
00251 
00252     if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
00253     {
00254         LOG(llevBug, "system(%s) returned %d\n", buf2, ret);
00255         errno = ENOENT;
00256         return NULL;
00257     }
00258 
00259     /* Delete the original */
00260     unlink(buf);
00261     /* Change to "uncompressed file" */
00262     *compressed = 0;
00263     /* Copy access mode from compressed file */
00264     chmod(name, st.st_mode);
00265 
00266     return fopen(name, "rb");
00267 }
00268 
00279 FILE *open_and_uncompress(const char *name, int flag, int *compressed)
00280 {
00281     size_t i;
00282     FILE *fp;
00283 
00284     for (i = 0; i < NROF_COMPRESS_METHODS; i++)
00285     {
00286         *compressed = i;
00287         fp = open_and_uncompress_file(uncomp[i][0], uncomp[i][1], name, flag, compressed);
00288 
00289         if (fp)
00290         {
00291             return fp;
00292         }
00293     }
00294 
00295     errno = ENOENT;
00296     return NULL;
00297 }
00298 
00303 void close_and_delete(FILE *fp, int compressed)
00304 {
00305     if (compressed)
00306     {
00307         pclose(fp);
00308     }
00309     else
00310     {
00311         fclose(fp);
00312     }
00313 }
00314 
00319 void make_path_to_file(char *filename)
00320 {
00321     char buf[MAX_BUF], *cp = buf;
00322     struct stat statbuf;
00323 
00324     if (!filename || !*filename)
00325     {
00326         return;
00327     }
00328 
00329     strcpy(buf, filename);
00330 
00331     while ((cp = strchr(cp + 1, '/')))
00332     {
00333         *cp = '\0';
00334 
00335         if (stat(buf, &statbuf) || !S_ISDIR(statbuf.st_mode))
00336         {
00337             if (mkdir(buf, 0777))
00338             {
00339                 LOG(llevBug, "Cannot mkdir %s: %s\n", buf, strerror_local(errno));
00340                 return;
00341             }
00342         }
00343 
00344         *cp = '/';
00345     }
00346 }
00347 
00353 const char *strcasestr_local(const char *s, const char *find)
00354 {
00355     char c, sc;
00356     size_t len;
00357 
00358     if ((c = *find++) != 0)
00359     {
00360         c = tolower(c);
00361         len = strlen(find);
00362 
00363         do
00364         {
00365             do
00366             {
00367                 if ((sc = *s++) == 0)
00368                 {
00369                     return NULL;
00370                 }
00371             }
00372             while (tolower(sc) != c);
00373         }
00374         while (strncasecmp(s, find, len) != 0);
00375 
00376         s--;
00377     }
00378 
00379     return s;
00380 }
00381