Crossfire Server, Branches 1.12  R18729
porting.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_porting_c =
3  * "$Id: porting.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2006 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28 
38 #include <string.h>
39 #ifdef WIN32 /* ---win32 exclude/include headers */
40 #include "process.h"
41 #define pid_t int /* we include it non global, because there is a redefinition in python.h */
42 #else
43 #include <ctype.h>
44 #include <errno.h>
45 #include <sys/stat.h>
46 #include <sys/wait.h>
47 
48 #include <sys/param.h>
49 #include <stdio.h>
50 
51 /* Need to pull in the HAVE_... values somehow */
52 /* win32 reminder: always put this in a ifndef win32 block */
53 #include <autoconf.h>
54 #endif
55 
56 #ifdef HAVE_STDLIB_H
57 #include <stdlib.h>
58 #endif
59 
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 
64 #include <stdarg.h>
65 /* Has to be after above includes so we don't redefine some values */
66 #include "global.h"
67 
69 static unsigned int curtmp = 0;
70 
71 /*****************************************************************************
72  * File related functions
73  ****************************************************************************/
74 
87 char *tempnam_local(const char *dir, const char *pfx) {
88  char *name;
89  pid_t pid = getpid();
90 
91 /* HURD does not have a hard limit, but we do */
92 #ifndef MAXPATHLEN
93 #define MAXPATHLEN 4096
94 #endif
95 
96  if (!pfx)
97  pfx = "cftmp.";
98 
99  /* This is a pretty simple method - put the pid as a hex digit and
100  * just keep incrementing the last digit. Check to see if the file
101  * already exists - if so, we'll just keep looking - eventually we should
102  * find one that is free.
103  */
104  if (dir != NULL) {
105  if (!(name = (char *)malloc(MAXPATHLEN)))
106  return(NULL);
107  do {
108 #ifdef HAVE_SNPRINTF
109  (void)snprintf(name, MAXPATHLEN, "%s/%s%hx.%u", dir, pfx, pid, curtmp);
110 #else
111  (void)sprintf(name, "%s/%s%hx%u", dir, pfx, pid, curtmp);
112 #endif
113  curtmp++;
114  } while (access(name, F_OK) != -1);
115  return(name);
116  }
117  return(NULL);
118 }
119 
143 FILE *tempnam_secure(const char *dir, const char *pfx, char **filename) {
144  char *tempname = NULL;
145  int fd;
146  int i;
147  FILE *file = NULL;
148 #define MAXTMPRETRY 10
149 
150  /* Limit number of retries to MAXRETRY */
151  for (i = 0; i < MAXTMPRETRY; i++) {
152  tempname = tempnam_local(dir, pfx);
153  /* tempnam_local only fails for really bad stuff, so lets bail out right
154  * away then.
155  */
156  if (!tempname)
157  return NULL;
158 
159  fd = open(tempname, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
160  if (fd != -1)
161  break;
162  if (errno == EEXIST)
163  LOG(llevError, "Created file detected in tempnam_secure. Someone hoping for a race condition?\n");
164  free(tempname);
165  }
166  /* Check that we successfully got an fd. */
167  if (fd == -1)
168  return NULL;
169 
170  file = fdopen(fd, "w+");
171  if (!file) {
172  LOG(llevError, "fdopen() failed in tempnam_secure()!\n");
173  free(tempname);
174  return NULL;
175  }
176 
177  *filename = tempname;
178  return file;
179 }
180 
192 void remove_directory(const char *path) {
193  DIR *dirp;
194  char buf[MAX_BUF];
195  struct stat statbuf;
196  int status;
197 
198  if ((dirp = opendir(path)) != NULL) {
199  struct dirent *de;
200 
201  for (de = readdir(dirp); de; de = readdir(dirp)) {
202  /* Don't remove '.' or '..' In theory we should do a better
203  * check for .., but the directories we are removing are fairly
204  * limited and should not have dot files in them.
205  */
206  if (de->d_name[0] == '.')
207  continue;
208 
209  /* Linux actually has a type field in the dirent structure,
210  * but that is not portable - stat should be portable
211  */
212  status = stat(de->d_name, &statbuf);
213  if ((status != -1) && (S_ISDIR(statbuf.st_mode))) {
214  snprintf(buf, sizeof(buf), "%s/%s", path, de->d_name);
215  remove_directory(buf);
216  continue;
217  }
218  snprintf(buf, sizeof(buf), "%s/%s", path, de->d_name);
219  if (unlink(buf)) {
220  LOG(llevError, "Unable to remove %s\n", path);
221  }
222  }
223  closedir(dirp);
224  }
225  if (rmdir(path)) {
226  LOG(llevError, "Unable to remove directory %s\n", path);
227  }
228 }
229 
230 #if defined(sgi)
231 
232 #include <stdio.h>
233 #include <stdlib.h>
234 #include <string.h>
235 
236 #define popen fixed_popen
237 
253 FILE *popen_local(const char *command, const char *type) {
254  int fd[2];
255  int pd;
256  FILE *ret;
257  if (!strcmp(type, "r")) {
258  pd = STDOUT_FILENO;
259  } else if (!strcmp(type, "w")) {
260  pd = STDIN_FILENO;
261  } else {
262  return NULL;
263  }
264  if (pipe(fd) != -1) {
265  switch (fork()) {
266  case -1:
267  close(fd[0]);
268  close(fd[1]);
269  break;
270 
271  case 0:
272  close(fd[0]);
273  if ((fd[1] == pd) || (dup2(fd[1], pd) == pd)) {
274  if (fd[1] != pd) {
275  close(fd[1]);
276  }
277  execl("/bin/sh", "sh", "-c", command, NULL);
278  close(pd);
279  }
280  exit(1);
281  break;
282 
283  default:
284  close(fd[1]);
285  if (ret = fdopen(fd[0], type)) {
286  return ret;
287  }
288  close(fd[0]);
289  break;
290  }
291  }
292  return NULL;
293 }
294 
295 #endif /* defined(sgi) */
296 
297 /*****************************************************************************
298  * String related function
299  ****************************************************************************/
300 
310 char *strdup_local(const char *str) {
311  char *c = (char *)malloc(strlen(str)+1);
312  if (c != NULL)
313  strcpy(c, str);
314  return c;
315 }
316 
318 #define DIGIT(x) (isdigit(x) ? (x)-'0' : \
319 islower(x) ? (x)+10-'a' : (x)+10-'A')
320 #define MBASE ('z'-'a'+1+10)
321 
322 #if !defined(HAVE_STRTOL)
323 
339 long strtol(register char *str, char **ptr, register int base) {
340  register long val;
341  register int c;
342  int xx, neg = 0;
343 
344  if (ptr != (char **)0)
345  *ptr = str; /* in case no number is formed */
346  if (base < 0 || base > MBASE)
347  return (0); /* base is invalid */
348  if (!isalnum(c = *str)) {
349  while (isspace(c))
350  c = *++str;
351  switch (c) {
352  case '-':
353  neg++;
354  case '+':
355  c = *++str;
356  }
357  }
358  if (base == 0) {
359  if (c != '0')
360  base = 10;
361  else {
362  if (str[1] == 'x' || str[1] == 'X')
363  base = 16;
364  else
365  base = 8;
366  }
367  }
368  /*
369  * For any base > 10, the digits incrementally following
370  * 9 are assumed to be "abc...z" or "ABC...Z"
371  */
372  if (!isalnum(c) || (xx = DIGIT(c)) >= base)
373  return 0; /* no number formed */
374  if (base == 16 && c == '0' && isxdigit(str[2]) && (str[1] == 'x' || str[1] == 'X'))
375  c = *(str += 2); /* skip over leading "0x" or "0X" */
376  for (val = -DIGIT(c); isalnum(c = *++str) && (xx = DIGIT(c)) < base; )
377  /* accumulate neg avoids surprises near
378  MAXLONG */
379  val = base*val-xx;
380  if (ptr != (char **)0)
381  *ptr = str;
382  return (neg ? val : -val);
383 }
384 #endif
385 
401 #if !defined(HAVE_STRNCASECMP)
402 int strncasecmp(const char *s1, const char *s2, int n) {
403  register int c1, c2;
404 
405  while (*s1 && *s2 && n) {
406  c1 = tolower(*s1);
407  c2 = tolower(*s2);
408  if (c1 != c2)
409  return (c1-c2);
410  s1++;
411  s2++;
412  n--;
413  }
414  if (!n)
415  return (0);
416  return (int)(*s1-*s2);
417 }
418 #endif
419 
420 #if !defined(HAVE_STRCASECMP)
421 
434 int strcasecmp(const char *s1, const char *s2) {
435  register int c1, c2;
436 
437  while (*s1 && *s2) {
438  c1 = tolower(*s1);
439  c2 = tolower(*s2);
440  if (c1 != c2)
441  return (c1-c2);
442  s1++;
443  s2++;
444  }
445  if (*s1 == '\0' && *s2 == '\0')
446  return 0;
447  return (int)(*s1-*s2);
448 }
449 #endif
450 
461 const char *strcasestr_local(const char *s, const char *find) {
462  char c, sc;
463  size_t len;
464 
465  if ((c = *find++) != 0) {
466  c = tolower(c);
467  len = strlen(find);
468  do {
469  do {
470  if ((sc = *s++) == 0)
471  return NULL;
472  } while (tolower(sc) != c);
473  } while (strncasecmp(s, find, len) != 0);
474  s--;
475  }
476  return s;
477 }
478 
479 #if !defined(HAVE_SNPRINTF)
480 
498 int snprintf(char *dest, int max, const char *format, ...) {
499  va_list var;
500  int ret;
501 
502  va_start(var, format);
503  ret = vsprintf(dest, format, var);
504  va_end(var);
505  if (ret > max)
506  abort();
507 
508  return ret;
509 }
510 #endif
511 
525 char *strerror_local(int errnum, char *buf, size_t size) {
526 #if defined(HAVE_STRERROR_R)
527  /* Then what flavour of strerror_r... */
528 # if defined(STRERROR_R_CHAR_P)
529  char *bbuf;
530 
531  buf[0] = 0;
532  bbuf = (char *)strerror_r(errnum, buf, size);
533  if ((buf[0] == 0) && (bbuf != NULL))
534  strncpy(buf, bbuf, size);
535 # else
536  if (strerror_r(errnum, buf, size) != 0) {
537  /* EINVAL and ERANGE are possible errors from this strerror_r */
538  if (errno == ERANGE) {
539  strncat(buf, "Too small buffer.", size);
540  } else if (errno == EINVAL) {
541  strncat(buf, "Error number invalid.", size);
542  }
543  }
544 # endif /* STRERROR_R_CHAR_P */
545 
546 #else /* HAVE_STRERROR_R */
547 
548 # if defined(HAVE_STRERROR)
549  snprintf(buf, size, "%s", strerror(errnum));
550 # else
551 # error If this is C89 the compiler should have strerror!;
552 # endif
553 #endif /* HAVE_STRERROR_R */
554  return buf;
555 }
556 
573 int isqrt(int n) {
574  int result, sum, prev;
575 
576  result = 0;
577  prev = sum = 1;
578  while (sum <= n) {
579  prev += 2;
580  sum += prev;
581  ++result;
582  }
583  return result;
584 }
585 
593 const char *uncomp[NROF_COMPRESS_METHODS][3] = {
594  { NULL, NULL, NULL },
595  { ".Z", UNCOMPRESS, COMPRESS },
596  { ".gz", GUNZIP, GZIP },
597  { ".bz2", BUNZIP, BZIP }
598 };
599 
621 static FILE *open_and_uncompress_file(const char *ext, const char *uncompressor, const char *name, int flag, int *compressed) {
622  struct stat st;
623  char buf[MAX_BUF];
624  char buf2[MAX_BUF];
625  int ret;
626 
627  if (ext == NULL) {
628  ext = "";
629  }
630 
631  if (strlen(name)+strlen(ext) >= sizeof(buf)) {
632  errno = ENAMETOOLONG; /* File name too long */
633  return NULL;
634  }
635  snprintf(buf, sizeof(buf), "%s%s", name, ext);
636 
637  if (stat(buf, &st) != 0) {
638  return NULL;
639  }
640 
641  if (!S_ISREG(st.st_mode)) {
642  errno = EISDIR; /* Not a regular file */
643  return NULL;
644  }
645 
646  if (uncompressor == NULL) {
647  /* open without uncompression */
648  return fopen(buf, "rb");
649  }
650 
651  /* The file name buf (and its substring name) is passed as an argument to a
652  * shell command, therefore check for characters that could confuse the
653  * shell.
654  */
655  if (strpbrk(buf, "'\\\r\n") != NULL) {
656  errno = ENOENT; /* Pretend the file does not exist */
657  return NULL;
658  }
659 
660  if (!flag) {
661  /* uncompress via pipe */
662 
663  if (strlen(uncompressor)+4+strlen(buf)+1 >= sizeof(buf2)) {
664  errno = ENAMETOOLONG; /* File name too long */
665  return NULL;
666  }
667  snprintf(buf2, sizeof(buf2), "%s < '%s'", uncompressor, buf);
668  return popen(buf2, "r");
669  }
670 
671  /* remove compression from file, then open file */
672 
673  if (stat(name, &st) == 0 && !S_ISREG(st.st_mode)) {
674  errno = EISDIR;
675  return NULL;
676  }
677 
678  if (strlen(uncompressor)+4+strlen(buf)+5+strlen(name)+1 >= sizeof(buf2)) {
679  errno = ENAMETOOLONG; /* File name too long */
680  return NULL;
681  }
682  snprintf(buf2, sizeof(buf2), "%s < '%s' > '%s'", uncompressor, buf, name);
683 
684  ret = system(buf2);
685  if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
686  LOG(llevError, "system(%s) returned %d\n", buf2, ret);
687  errno = ENOENT;
688  return NULL;
689  }
690 
691  unlink(buf); /* Delete the original */
692  *compressed = 0; /* Change to "uncompressed file" */
693  chmod(name, st.st_mode); /* Copy access mode from compressed file */
694 
695  return fopen(name, "rb");
696 }
697 
724 FILE *open_and_uncompress(const char *name, int flag, int *compressed) {
725  size_t i;
726  FILE *fp;
727 
728  for (i = 0; i < NROF_COMPRESS_METHODS; i++) {
729  *compressed = i;
730  fp = open_and_uncompress_file(uncomp[i][0], uncomp[i][1], name, flag, compressed);
731  if (fp != NULL) {
732  return fp;
733  }
734  }
735 
736  errno = ENOENT;
737  return NULL;
738 }
739 
748 void close_and_delete(FILE *fp, int compressed) {
749  if (compressed)
750  pclose(fp);
751  else
752  fclose(fp);
753 }
754 
764 void make_path_to_file(const char *filename) {
765  char buf[MAX_BUF], *cp = buf;
766  struct stat statbuf;
767 
768  if (!filename || !*filename)
769  return;
770 
771  strcpy(buf, filename);
772  LOG(llevDebug, "make_path_tofile %s...\n", filename);
773  while ((cp = strchr(cp+1, (int)'/'))) {
774  *cp = '\0';
775  if (stat(buf, &statbuf) || !S_ISDIR(statbuf.st_mode)) {
776  LOG(llevDebug, "Was not dir: %s\n", buf);
777  if (mkdir(buf, SAVE_DIR_MODE)) {
778  char err[MAX_BUF];
779 
780  LOG(llevError, "Cannot mkdir %s: %s\n", buf, strerror_local(errno, err, sizeof(err)));
781  return;
782  }
783  }
784  *cp = '/';
785  }
786 }
char * tempnam_local(const char *dir, const char *pfx)
Definition: porting.c:87
long strtol(register char *str, char **ptr, register int base)
Definition: porting.c:339
void make_path_to_file(const char *filename)
Definition: porting.c:764
void remove_directory(const char *path)
Definition: porting.c:192
#define popen(__a, __b)
Definition: win32.h:70
DIR * opendir(const char *)
Definition: win32.c:78
#define F_OK
Definition: win32.h:76
void close_and_delete(FILE *fp, int compressed)
Definition: porting.c:748
#define MAXPATHLEN
#define MBASE
Definition: porting.c:320
#define mkdir(__a, __b)
Definition: win32.h:68
#define COMPRESS
Definition: win32.h:116
Definition: win32.h:128
Definition: win32.h:138
#define UNCOMPRESS
Definition: win32.h:117
#define WEXITSTATUS(x)
Definition: win32.h:106
FILE * tempnam_secure(const char *dir, const char *pfx, char **filename)
Definition: porting.c:143
#define BUNZIP
Definition: win32.h:121
#define GZIP
Definition: win32.h:118
#define getpid()
Definition: win32.h:69
#define NROF_COMPRESS_METHODS
Definition: global.h:201
#define BZIP
Definition: win32.h:120
char d_name[_MAX_FNAME+1]
Definition: win32.h:132
char * strdup_local(const char *str)
Definition: porting.c:310
#define MAX_BUF
Definition: define.h:81
static FILE * open_and_uncompress_file(const char *ext, const char *uncompressor, const char *name, int flag, int *compressed)
Definition: porting.c:621
int strncasecmp(const char *s1, const char *s2, int n)
Definition: porting.c:402
static unsigned int curtmp
Definition: porting.c:69
#define tolower(C)
Definition: c_new.c:42
#define MAXTMPRETRY
#define pclose(__a)
Definition: win32.h:71
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
const char * uncomp[NROF_COMPRESS_METHODS][3]
Definition: porting.c:593
#define unlink(__a)
Definition: win32.h:67
int isqrt(int n)
Definition: porting.c:573
struct dirent * readdir(DIR *)
Definition: win32.c:116
int strcasecmp(const char *s1, const char *s2)
Definition: porting.c:434
int closedir(DIR *)
Definition: win32.c:149
#define S_ISDIR(x)
Definition: win32.h:80
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
const char * strcasestr_local(const char *s, const char *find)
Definition: porting.c:461
#define SAVE_DIR_MODE
Definition: config.h:635
#define S_IRUSR
Definition: win32.h:102
#define S_IWUSR
Definition: win32.h:93
char * strerror_local(int errnum, char *buf, size_t size)
Definition: porting.c:525
#define S_ISREG(x)
Definition: win32.h:81
#define WIFEXITED(x)
Definition: win32.h:105
#define DIGIT(x)
Definition: porting.c:318
FILE * open_and_uncompress(const char *name, int flag, int *compressed)
Definition: porting.c:724
#define GUNZIP
Definition: win32.h:119