+ const char *name, *slash;
+ int depth = 0;
+
+ /* all absolute and null symlinks are unsafe */
+ if (!dest || !*dest || *dest == '/')
+ return 1;
+
+ /* find out what our safety margin is */
+ for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
+ /* ".." segment starts the count over. "." segment is ignored. */
+ if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
+ if (name[1] == '.')
+ depth = 0;
+ } else
+ depth++;
+ while (slash[1] == '/') slash++; /* just in case src isn't clean */
+ }
+ if (*name == '.' && name[1] == '.' && name[2] == '\0')
+ depth = 0;
+
+ for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
+ if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
+ if (name[1] == '.') {
+ /* if at any point we go outside the current directory
+ then stop - it is unsafe */
+ if (--depth < 0)
+ return 1;
+ }
+ } else
+ depth++;
+ while (slash[1] == '/') slash++;
+ }
+ if (*name == '.' && name[1] == '.' && name[2] == '\0')
+ depth--;
+
+ return depth < 0;
+}
+
+/* Return the date and time as a string. Some callers tweak returned buf. */
+char *timestring(time_t t)
+{
+ static char TimeBuf[200];
+ struct tm *tm = localtime(&t);
+ char *p;
+
+#ifdef HAVE_STRFTIME
+ strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm);
+#else
+ strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf);
+#endif
+
+ if ((p = strchr(TimeBuf, '\n')) != NULL)
+ *p = '\0';
+
+ return TimeBuf;
+}
+
+/**
+ * Sleep for a specified number of milliseconds.
+ *
+ * Always returns TRUE. (In the future it might return FALSE if
+ * interrupted.)
+ **/
+int msleep(int t)
+{
+ int tdiff = 0;
+ struct timeval tval, t1, t2;
+
+ gettimeofday(&t1, NULL);
+
+ while (tdiff < t) {
+ tval.tv_sec = (t-tdiff)/1000;
+ tval.tv_usec = 1000*((t-tdiff)%1000);
+
+ errno = 0;
+ select(0,NULL,NULL, NULL, &tval);
+
+ gettimeofday(&t2, NULL);
+ tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
+ (t2.tv_usec - t1.tv_usec)/1000;