PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/php/ext/fileinfo/libmagic/magic.c

https://gitlab.com/envieidoc/advancedtomato2
C | 478 lines | 356 code | 61 blank | 61 comment | 107 complexity | c50275abd8dadcfacb54120a7eb6fd08 MD5 | raw file
  1. /*
  2. * Copyright (c) Christos Zoulas 2003.
  3. * All Rights Reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice immediately at the beginning of the file, without modification,
  10. * this list of conditions, and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  19. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. #include "file.h"
  28. #ifndef lint
  29. FILE_RCSID("@(#)$File: magic.c,v 1.78 2013/01/07 18:20:19 christos Exp $")
  30. #endif /* lint */
  31. #include "magic.h"
  32. #include <stdlib.h>
  33. #ifdef PHP_WIN32
  34. #include "win32/unistd.h"
  35. #else
  36. #include <unistd.h>
  37. #endif
  38. #include <string.h>
  39. #ifdef PHP_WIN32
  40. # include "config.w32.h"
  41. #else
  42. # include "php_config.h"
  43. #endif
  44. #ifdef PHP_WIN32
  45. #include <shlwapi.h>
  46. #endif
  47. #include <limits.h> /* for PIPE_BUF */
  48. #if defined(HAVE_UTIMES)
  49. # include <sys/time.h>
  50. #elif defined(HAVE_UTIME)
  51. # if defined(HAVE_SYS_UTIME_H)
  52. # include <sys/utime.h>
  53. # elif defined(HAVE_UTIME_H)
  54. # include <utime.h>
  55. # endif
  56. #endif
  57. #ifdef HAVE_UNISTD_H
  58. #include <unistd.h> /* for read() */
  59. #endif
  60. #ifndef PIPE_BUF
  61. /* Get the PIPE_BUF from pathconf */
  62. #ifdef _PC_PIPE_BUF
  63. #define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
  64. #else
  65. #define PIPE_BUF 512
  66. #endif
  67. #endif
  68. #ifdef PHP_WIN32
  69. # undef S_IFLNK
  70. # undef S_IFIFO
  71. #endif
  72. private void close_and_restore(const struct magic_set *, const char *, int,
  73. const struct stat *);
  74. private int unreadable_info(struct magic_set *, mode_t, const char *);
  75. #if 0
  76. private const char* get_default_magic(void);
  77. #endif
  78. private const char *file_or_stream(struct magic_set *, const char *, php_stream *);
  79. #ifndef STDIN_FILENO
  80. #define STDIN_FILENO 0
  81. #endif
  82. /* XXX this functionality is excluded in php, enable it in apprentice.c:340 */
  83. #if 0
  84. private const char *
  85. get_default_magic(void)
  86. {
  87. static const char hmagic[] = "/.magic/magic.mgc";
  88. static char *default_magic;
  89. char *home, *hmagicpath;
  90. #ifndef PHP_WIN32
  91. struct stat st;
  92. if (default_magic) {
  93. free(default_magic);
  94. default_magic = NULL;
  95. }
  96. if ((home = getenv("HOME")) == NULL)
  97. return MAGIC;
  98. if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0)
  99. return MAGIC;
  100. if (stat(hmagicpath, &st) == -1) {
  101. free(hmagicpath);
  102. if (asprintf(&hmagicpath, "%s/.magic", home) < 0)
  103. return MAGIC;
  104. if (stat(hmagicpath, &st) == -1)
  105. goto out;
  106. if (S_ISDIR(st.st_mode)) {
  107. free(hmagicpath);
  108. if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0)
  109. return MAGIC;
  110. if (access(hmagicpath, R_OK) == -1)
  111. goto out;
  112. }
  113. }
  114. if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0)
  115. goto out;
  116. free(hmagicpath);
  117. return default_magic;
  118. out:
  119. default_magic = NULL;
  120. free(hmagicpath);
  121. return MAGIC;
  122. #else
  123. char *hmagicp = hmagicpath;
  124. char *tmppath = NULL;
  125. LPTSTR dllpath;
  126. #define APPENDPATH() \
  127. do { \
  128. if (tmppath && access(tmppath, R_OK) != -1) { \
  129. if (hmagicpath == NULL) \
  130. hmagicpath = tmppath; \
  131. else { \
  132. if (asprintf(&hmagicp, "%s%c%s", hmagicpath, \
  133. PATHSEP, tmppath) >= 0) { \
  134. free(hmagicpath); \
  135. hmagicpath = hmagicp; \
  136. } \
  137. free(tmppath); \
  138. } \
  139. tmppath = NULL; \
  140. } \
  141. } while (/*CONSTCOND*/0)
  142. if (default_magic) {
  143. free(default_magic);
  144. default_magic = NULL;
  145. }
  146. /* First, try to get user-specific magic file */
  147. if ((home = getenv("LOCALAPPDATA")) == NULL) {
  148. if ((home = getenv("USERPROFILE")) != NULL)
  149. if (asprintf(&tmppath,
  150. "%s/Local Settings/Application Data%s", home,
  151. hmagic) < 0)
  152. tmppath = NULL;
  153. } else {
  154. if (asprintf(&tmppath, "%s%s", home, hmagic) < 0)
  155. tmppath = NULL;
  156. }
  157. APPENDPATH();
  158. /* Second, try to get a magic file from Common Files */
  159. if ((home = getenv("COMMONPROGRAMFILES")) != NULL) {
  160. if (asprintf(&tmppath, "%s%s", home, hmagic) >= 0)
  161. APPENDPATH();
  162. }
  163. /* Third, try to get magic file relative to dll location */
  164. dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1));
  165. dllpath[MAX_PATH] = 0; /* just in case long path gets truncated and not null terminated */
  166. if (GetModuleFileNameA(NULL, dllpath, MAX_PATH)){
  167. PathRemoveFileSpecA(dllpath);
  168. if (strlen(dllpath) > 3 &&
  169. stricmp(&dllpath[strlen(dllpath) - 3], "bin") == 0) {
  170. if (asprintf(&tmppath,
  171. "%s/../share/misc/magic.mgc", dllpath) >= 0)
  172. APPENDPATH();
  173. } else {
  174. if (asprintf(&tmppath,
  175. "%s/share/misc/magic.mgc", dllpath) >= 0)
  176. APPENDPATH();
  177. else if (asprintf(&tmppath,
  178. "%s/magic.mgc", dllpath) >= 0)
  179. APPENDPATH();
  180. }
  181. }
  182. /* Don't put MAGIC constant - it likely points to a file within MSys
  183. tree */
  184. default_magic = hmagicpath;
  185. return default_magic;
  186. #endif
  187. }
  188. public const char *
  189. magic_getpath(const char *magicfile, int action)
  190. {
  191. if (magicfile != NULL)
  192. return magicfile;
  193. magicfile = getenv("MAGIC");
  194. if (magicfile != NULL)
  195. return magicfile;
  196. return action == FILE_LOAD ? get_default_magic() : MAGIC;
  197. }
  198. #endif
  199. public struct magic_set *
  200. magic_open(int flags)
  201. {
  202. return file_ms_alloc(flags);
  203. }
  204. private int
  205. unreadable_info(struct magic_set *ms, mode_t md, const char *file)
  206. {
  207. /* We cannot open it, but we were able to stat it. */
  208. if (access(file, W_OK) == 0)
  209. if (file_printf(ms, "writable, ") == -1)
  210. return -1;
  211. if (access(file, X_OK) == 0)
  212. if (file_printf(ms, "executable, ") == -1)
  213. return -1;
  214. if (S_ISREG(md))
  215. if (file_printf(ms, "regular file, ") == -1)
  216. return -1;
  217. if (file_printf(ms, "no read permission") == -1)
  218. return -1;
  219. return 0;
  220. }
  221. public void
  222. magic_close(struct magic_set *ms)
  223. {
  224. if (ms == NULL)
  225. return;
  226. file_ms_free(ms);
  227. }
  228. /*
  229. * load a magic file
  230. */
  231. public int
  232. magic_load(struct magic_set *ms, const char *magicfile)
  233. {
  234. if (ms == NULL)
  235. return -1;
  236. return file_apprentice(ms, magicfile, FILE_LOAD);
  237. }
  238. public int
  239. magic_compile(struct magic_set *ms, const char *magicfile)
  240. {
  241. if (ms == NULL)
  242. return -1;
  243. return file_apprentice(ms, magicfile, FILE_COMPILE);
  244. }
  245. public int
  246. magic_list(struct magic_set *ms, const char *magicfile)
  247. {
  248. if (ms == NULL)
  249. return -1;
  250. return file_apprentice(ms, magicfile, FILE_LIST);
  251. }
  252. private void
  253. close_and_restore(const struct magic_set *ms, const char *name, int fd,
  254. const struct stat *sb)
  255. {
  256. if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
  257. /*
  258. * Try to restore access, modification times if read it.
  259. * This is really *bad* because it will modify the status
  260. * time of the file... And of course this will affect
  261. * backup programs
  262. */
  263. #ifdef HAVE_UTIMES
  264. struct timeval utsbuf[2];
  265. (void)memset(utsbuf, 0, sizeof(utsbuf));
  266. utsbuf[0].tv_sec = sb->st_atime;
  267. utsbuf[1].tv_sec = sb->st_mtime;
  268. (void) utimes(name, utsbuf); /* don't care if loses */
  269. #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
  270. struct utimbuf utbuf;
  271. (void)memset(&utbuf, 0, sizeof(utbuf));
  272. utbuf.actime = sb->st_atime;
  273. utbuf.modtime = sb->st_mtime;
  274. (void) utime(name, &utbuf); /* don't care if loses */
  275. #endif
  276. }
  277. }
  278. /*
  279. * find type of descriptor
  280. */
  281. public const char *
  282. magic_descriptor(struct magic_set *ms, int fd)
  283. {
  284. if (ms == NULL)
  285. return NULL;
  286. return file_or_stream(ms, NULL, NULL);
  287. }
  288. /*
  289. * find type of named file
  290. */
  291. public const char *
  292. magic_file(struct magic_set *ms, const char *inname)
  293. {
  294. if (ms == NULL)
  295. return NULL;
  296. return file_or_stream(ms, inname, NULL);
  297. }
  298. public const char *
  299. magic_stream(struct magic_set *ms, php_stream *stream)
  300. {
  301. if (ms == NULL)
  302. return NULL;
  303. return file_or_stream(ms, NULL, stream);
  304. }
  305. private const char *
  306. file_or_stream(struct magic_set *ms, const char *inname, php_stream *stream)
  307. {
  308. int rv = -1;
  309. unsigned char *buf;
  310. struct stat sb;
  311. ssize_t nbytes = 0; /* number of bytes read from a datafile */
  312. int no_in_stream = 0;
  313. TSRMLS_FETCH();
  314. if (!inname && !stream) {
  315. return NULL;
  316. }
  317. /*
  318. * one extra for terminating '\0', and
  319. * some overlapping space for matches near EOF
  320. */
  321. #define SLOP (1 + sizeof(union VALUETYPE))
  322. buf = emalloc(HOWMANY + SLOP);
  323. if (file_reset(ms) == -1)
  324. goto done;
  325. switch (file_fsmagic(ms, inname, &sb, stream)) {
  326. case -1: /* error */
  327. goto done;
  328. case 0: /* nothing found */
  329. break;
  330. default: /* matched it and printed type */
  331. rv = 0;
  332. goto done;
  333. }
  334. errno = 0;
  335. if (!stream && inname) {
  336. no_in_stream = 1;
  337. #if PHP_API_VERSION < 20100412
  338. stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
  339. #else
  340. stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS, NULL);
  341. #endif
  342. }
  343. if (!stream) {
  344. if (unreadable_info(ms, sb.st_mode, inname) == -1)
  345. goto done;
  346. rv = 0;
  347. goto done;
  348. }
  349. #ifdef O_NONBLOCK
  350. /* we should be already be in non blocking mode for network socket */
  351. #endif
  352. /*
  353. * try looking at the first HOWMANY bytes
  354. */
  355. if ((nbytes = php_stream_read(stream, (char *)buf, HOWMANY)) < 0) {
  356. file_error(ms, errno, "cannot read `%s'", inname);
  357. goto done;
  358. }
  359. (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
  360. if (file_buffer(ms, stream, inname, buf, (size_t)nbytes) == -1)
  361. goto done;
  362. rv = 0;
  363. done:
  364. efree(buf);
  365. if (no_in_stream && stream) {
  366. php_stream_close(stream);
  367. }
  368. close_and_restore(ms, inname, 0, &sb);
  369. return rv == 0 ? file_getbuffer(ms) : NULL;
  370. }
  371. public const char *
  372. magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
  373. {
  374. if (ms == NULL)
  375. return NULL;
  376. if (file_reset(ms) == -1)
  377. return NULL;
  378. /*
  379. * The main work is done here!
  380. * We have the file name and/or the data buffer to be identified.
  381. */
  382. if (file_buffer(ms, NULL, NULL, buf, nb) == -1) {
  383. return NULL;
  384. }
  385. return file_getbuffer(ms);
  386. }
  387. public const char *
  388. magic_error(struct magic_set *ms)
  389. {
  390. if (ms == NULL)
  391. return "Magic database is not open";
  392. return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL;
  393. }
  394. public int
  395. magic_errno(struct magic_set *ms)
  396. {
  397. if (ms == NULL)
  398. return EINVAL;
  399. return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0;
  400. }
  401. public int
  402. magic_setflags(struct magic_set *ms, int flags)
  403. {
  404. if (ms == NULL)
  405. return -1;
  406. #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
  407. if (flags & MAGIC_PRESERVE_ATIME)
  408. return -1;
  409. #endif
  410. ms->flags = flags;
  411. return 0;
  412. }
  413. public int
  414. magic_version(void)
  415. {
  416. return MAGIC_VERSION;
  417. }