Crossfire Server, Trunk  R20513
porting.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
23 #include <assert.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #ifdef WIN32 /* ---win32 exclude/include headers */
32 #include "process.h"
33 #else
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <sys/wait.h>
37 #endif
38 
39 /* Has to be after above includes so we don't redefine some values */
40 #include "global.h"
41 
42 /*****************************************************************************
43  * File related functions
44  ****************************************************************************/
45 
46 #ifndef HAVE_TEMPNAM
47 
52 char *tempnam(const char *dir, const char *pfx) {
54  static unsigned int curtmp;
55 
56  char *name;
57  pid_t pid = getpid();
58 
59 /* HURD does not have a hard limit, but we do */
60 #ifndef MAXPATHLEN
61 #define MAXPATHLEN 4096
62 #endif
63 
64  if (!pfx)
65  pfx = "cftmp.";
66 
67  /* This is a pretty simple method - put the pid as a hex digit and
68  * just keep incrementing the last digit. Check to see if the file
69  * already exists - if so, we'll just keep looking - eventually we should
70  * find one that is free.
71  */
72  if (dir != NULL) {
73  if (!(name = (char *)malloc(MAXPATHLEN)))
74  return(NULL);
75  do {
76  snprintf(name, MAXPATHLEN, "%s/%s%x.%u", dir, pfx, (unsigned int)pid, curtmp);
77  curtmp++;
78  } while (access(name, F_OK) != -1);
79  return(name);
80  }
81  return(NULL);
82 }
83 #endif
84 
108 FILE *tempnam_secure(const char *dir, const char *pfx, char **filename) {
109  char *tempname = NULL;
110  int fd;
111  int i;
112  FILE *file = NULL;
113  const int maxretry = 10;
114 
115  /* Limit number of retries to MAXRETRY */
116  for (i = 0; i < maxretry; i++) {
117  tempname = tempnam(dir, pfx);
118  if (!tempname)
119  return NULL;
120 
121  fd = open(tempname, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
122  if (fd != -1)
123  break;
124  if (errno == EEXIST)
125  LOG(llevError, "Created file detected in tempnam_secure. Someone hoping for a race condition?\n");
126  free(tempname);
127  }
128  /* Check that we successfully got an fd. */
129  if (fd == -1)
130  return NULL;
131 
132  file = fdopen(fd, "w+");
133  if (!file) {
134  LOG(llevError, "fdopen() failed in tempnam_secure()!\n");
135  free(tempname);
136  return NULL;
137  }
138 
139  *filename = tempname;
140  return file;
141 }
142 
154 void remove_directory(const char *path) {
155  DIR *dirp;
156  char buf[MAX_BUF];
157  struct stat statbuf;
158  int status;
159 
160  if ((dirp = opendir(path)) != NULL) {
161  struct dirent *de;
162 
163  for (de = readdir(dirp); de; de = readdir(dirp)) {
164  /* Don't remove '.' or '..' In theory we should do a better
165  * check for .., but the directories we are removing are fairly
166  * limited and should not have dot files in them.
167  */
168  if (de->d_name[0] == '.')
169  continue;
170 
171  /* Linux actually has a type field in the dirent structure,
172  * but that is not portable - stat should be portable
173  */
174  status = stat(de->d_name, &statbuf);
175  if ((status != -1) && (S_ISDIR(statbuf.st_mode))) {
176  snprintf(buf, sizeof(buf), "%s/%s", path, de->d_name);
177  remove_directory(buf);
178  continue;
179  }
180  snprintf(buf, sizeof(buf), "%s/%s", path, de->d_name);
181  if (unlink(buf)) {
182  LOG(llevError, "Unable to remove %s\n", path);
183  }
184  }
185  closedir(dirp);
186  }
187  if (rmdir(path)) {
188  LOG(llevError, "Unable to remove directory %s\n", path);
189  }
190 }
191 
192 /*****************************************************************************
193  * String related function
194  ****************************************************************************/
195 
196 #ifndef HAVE_STRDUP
197 
200 char *strdup(const char *str) {
201  char *c = (char *)malloc(strlen(str)+1);
202  if (c != NULL)
203  strcpy(c, str);
204  return c;
205 }
206 #endif
207 
208 #ifndef HAVE_STRNCASECMP
209 
224 int strncasecmp(const char *s1, const char *s2, int n) {
225  register int c1, c2;
226 
227  while (*s1 && *s2 && n) {
228  c1 = tolower(*s1);
229  c2 = tolower(*s2);
230  if (c1 != c2)
231  return (c1-c2);
232  s1++;
233  s2++;
234  n--;
235  }
236  if (!n)
237  return (0);
238  return (int)(*s1-*s2);
239 }
240 #endif
241 
242 #ifndef HAVE_STRCASECMP
243 
256 int strcasecmp(const char *s1, const char *s2) {
257  register int c1, c2;
258 
259  while (*s1 && *s2) {
260  c1 = tolower(*s1);
261  c2 = tolower(*s2);
262  if (c1 != c2)
263  return (c1-c2);
264  s1++;
265  s2++;
266  }
267  if (*s1 == '\0' && *s2 == '\0')
268  return 0;
269  return (int)(*s1-*s2);
270 }
271 #endif
272 
273 #ifndef HAVE_STRCASESTR
274 
284 char *strcasestr(const char *s, const char *find) {
285  char c, sc;
286  size_t len;
287 
288  if ((c = *find++) != 0) {
289  c = tolower(c);
290  len = strlen(find);
291  do {
292  do {
293  if ((sc = *s++) == 0)
294  return NULL;
295  } while (tolower(sc) != c);
296  } while (strncasecmp(s, find, len) != 0);
297  s--;
298  }
299  return s;
300 }
301 #endif
302 
312 void make_path_to_file(const char *filename) {
313  char buf[MAX_BUF], *cp = buf;
314  struct stat statbuf;
315 
316  if (!filename || !*filename)
317  return;
318 
319  safe_strncpy(buf, filename, sizeof(buf));
320  while ((cp = strchr(cp+1, (int)'/'))) {
321  *cp = '\0';
322  if (stat(buf, &statbuf) || !S_ISDIR(statbuf.st_mode)) {
323  LOG(llevDebug, "Was not dir: %s\n", buf);
324  if (mkdir(buf, SAVE_DIR_MODE)) {
325  LOG(llevError, "Cannot mkdir %s: %s\n", buf, strerror(errno));
326  return;
327  }
328  }
329  *cp = '/';
330  }
331 }
332 
346 void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen) {
347 #ifdef HAVE_STRLCAT
348  assert(strlen(orig) < maxlen);
349  *curlen = strlcat(dest, orig, maxlen);
350 #else
351  if (*curlen == (maxlen-1))
352  return;
353  strncpy(dest+*curlen, orig, maxlen-*curlen-1);
354  dest[maxlen-1] = 0;
355  *curlen += strlen(orig);
356  if (*curlen > (maxlen-1))
357  *curlen = maxlen-1;
358 #endif
359 }
360 
361 #ifndef HAVE_STRLCPY
362 
365 size_t strlcpy(char *dst, const char *src, size_t size) {
366  strncpy(dst, src, size - 1);
367  dst[size - 1] = '\0';
368  return strlen(src);
369 }
370 #endif
Error, serious thing.
Definition: logger.h:11
void make_path_to_file(const char *filename)
Checks if any directories in the given path doesn&#39;t exist, and creates if necessary.
Definition: porting.c:312
void remove_directory(const char *path)
This function removes everything in the directory, and the directory itself.
Definition: porting.c:154
DIR * opendir(const char *)
Opens a directory for reading.
Definition: win32.c:37
#define F_OK
Definition: win32.h:65
#define MAXPATHLEN
#define mkdir(__a, __b)
Definition: win32.h:57
Definition: win32.h:110
Global type definitions and header inclusions.
#define safe_strncpy
Definition: compat.h:23
Definition: win32.h:120
#define snprintf
Definition: win32.h:46
FILE * tempnam_secure(const char *dir, const char *pfx, char **filename)
A replacement for the tempnam_local() function since that one is not very secure. ...
Definition: porting.c:108
#define getpid()
Definition: win32.h:58
char d_name[_MAX_FNAME+1]
Definition: win32.h:114
char * strcasestr(const char *s, const char *find)
Finds a substring in a string, in a case-insensitive manner.
Definition: porting.c:284
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
int strncasecmp(const char *s1, const char *s2, int n)
Case-insensitive comparaison of strings.
Definition: porting.c:224
#define tolower(C)
Simple macro to convert a letter to lowercase.
Definition: c_new.c:29
char * tempnam(const char *dir, const char *pfx)
Portable implementation of tempnam(3).
Definition: porting.c:52
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Simple function we use below to keep adding to the same string but also make sure we don&#39;t overwrite ...
Definition: porting.c:346
Only for debugging purposes.
Definition: logger.h:13
#define unlink(__a)
Definition: win32.h:56
struct dirent * readdir(DIR *)
Returns the next file/directory for specified directory handle, obtained through a call to opendir()...
Definition: win32.c:75
int strcasecmp(const char *s1, const char *s2)
Case-insensitive comparaison of strings.
Definition: porting.c:256
int closedir(DIR *)
Dispose of a directory handle.
Definition: win32.c:108
char * strdup(const char *str)
Portable implementation of strdup(3).
Definition: porting.c:200
#define S_ISDIR(x)
Definition: win32.h:69
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
#define SAVE_DIR_MODE
Definition: config.h:617
#define S_IRUSR
Definition: win32.h:91
#define S_IWUSR
Definition: win32.h:82
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.c:365