PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/ext_zend_compat/php-src/TSRM/tsrm_virtual_cwd.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 792 lines | 722 code | 48 blank | 22 comment | 115 complexity | 543f77d85e72f487ad210d8ba689e00c MD5 | raw file
  1. #include "hphp/runtime/ext_zend_compat/php-src/TSRM/tsrm_virtual_cwd.h"
  2. #include "hphp/runtime/ext/std/ext_std_file.h"
  3. #define CWD_STATE_COPY(d, s) \
  4. (d)->cwd_length = (s)->cwd_length; \
  5. (d)->cwd = (char *) malloc((s)->cwd_length+1); \
  6. memcpy((d)->cwd, (s)->cwd, (s)->cwd_length+1);
  7. #define CWD_STATE_FREE(s) \
  8. free((s)->cwd);
  9. #ifdef ZTS
  10. ts_rsrc_id cwd_globals_id;
  11. #else
  12. virtual_cwd_globals cwd_globals;
  13. #endif
  14. CWD_API char *tsrm_realpath(const char *path, char *real_path TSRMLS_DC) {
  15. HPHP::Variant rp = HPHP::HHVM_FN(realpath)(path);
  16. if (rp.isBoolean()) {
  17. assert(!rp.toBoolean());
  18. return nullptr;
  19. }
  20. HPHP::StringData *ret = rp.getStringData();
  21. if (real_path) {
  22. int copy_len = ret->size();
  23. memcpy(real_path, ret->data(), copy_len);
  24. real_path[copy_len] = '\0';
  25. return real_path;
  26. } else {
  27. return strndup(ret->data(), ret->size());
  28. }
  29. }
  30. #ifdef PHP_WIN32
  31. static inline unsigned long realpath_cache_key(const char *path, int path_len TSRMLS_DC) /* {{{ */
  32. {
  33. register unsigned long h;
  34. char *bucket_key_start = tsrm_win32_get_path_sid_key(path TSRMLS_CC);
  35. char *bucket_key = (char *)bucket_key_start;
  36. const char *e = bucket_key + strlen(bucket_key);
  37. if (!bucket_key) {
  38. return 0;
  39. }
  40. for (h = 2166136261U; bucket_key < e;) {
  41. h *= 16777619;
  42. h ^= *bucket_key++;
  43. }
  44. HeapFree(GetProcessHeap(), 0, (LPVOID)bucket_key_start);
  45. return h;
  46. }
  47. /* }}} */
  48. #else
  49. static inline unsigned long realpath_cache_key(const char *path, int path_len) /* {{{ */
  50. {
  51. register unsigned long h;
  52. const char *e = path + path_len;
  53. for (h = 2166136261U; path < e;) {
  54. h *= 16777619;
  55. h ^= *path++;
  56. }
  57. return h;
  58. }
  59. /* }}} */
  60. #endif /* defined(PHP_WIN32) */
  61. static inline void realpath_cache_add(const char *path, int path_len, const char *realpath, int realpath_len, int is_dir, time_t t TSRMLS_DC) /* {{{ */
  62. {
  63. long size = sizeof(realpath_cache_bucket) + path_len + 1;
  64. int same = 1;
  65. if (realpath_len != path_len ||
  66. memcmp(path, realpath, path_len) != 0) {
  67. size += realpath_len + 1;
  68. same = 0;
  69. }
  70. if (CWDG(realpath_cache_size) + size <= CWDG(realpath_cache_size_limit)) {
  71. realpath_cache_bucket *bucket = (realpath_cache_bucket*) malloc(size);
  72. unsigned long n;
  73. if (bucket == NULL) {
  74. return;
  75. }
  76. #ifdef PHP_WIN32
  77. bucket->key = realpath_cache_key(path, path_len TSRMLS_CC);
  78. #else
  79. bucket->key = realpath_cache_key(path, path_len);
  80. #endif
  81. bucket->path = (char*)bucket + sizeof(realpath_cache_bucket);
  82. memcpy(bucket->path, path, path_len+1);
  83. bucket->path_len = path_len;
  84. if (same) {
  85. bucket->realpath = bucket->path;
  86. } else {
  87. bucket->realpath = bucket->path + (path_len + 1);
  88. memcpy(bucket->realpath, realpath, realpath_len+1);
  89. }
  90. bucket->realpath_len = realpath_len;
  91. bucket->is_dir = is_dir;
  92. #ifdef PHP_WIN32
  93. bucket->is_rvalid = 0;
  94. bucket->is_readable = 0;
  95. bucket->is_wvalid = 0;
  96. bucket->is_writable = 0;
  97. #endif
  98. bucket->expires = t + CWDG(realpath_cache_ttl);
  99. n = bucket->key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
  100. bucket->next = CWDG(realpath_cache)[n];
  101. CWDG(realpath_cache)[n] = bucket;
  102. CWDG(realpath_cache_size) += size;
  103. }
  104. }
  105. /* }}} */
  106. static inline realpath_cache_bucket* realpath_cache_find(const char *path, int path_len, time_t t TSRMLS_DC) /* {{{ */
  107. {
  108. #ifdef PHP_WIN32
  109. unsigned long key = realpath_cache_key(path, path_len TSRMLS_CC);
  110. #else
  111. unsigned long key = realpath_cache_key(path, path_len);
  112. #endif
  113. unsigned long n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
  114. realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
  115. while (*bucket != NULL) {
  116. if (CWDG(realpath_cache_ttl) && (*bucket)->expires < t) {
  117. realpath_cache_bucket *r = *bucket;
  118. *bucket = (*bucket)->next;
  119. /* if the pointers match then only subtract the length of the path */
  120. if(r->path == r->realpath) {
  121. CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1;
  122. } else {
  123. CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1;
  124. }
  125. free(r);
  126. } else if (key == (*bucket)->key && path_len == (*bucket)->path_len &&
  127. memcmp(path, (*bucket)->path, path_len) == 0) {
  128. return *bucket;
  129. } else {
  130. bucket = &(*bucket)->next;
  131. }
  132. }
  133. return NULL;
  134. }
  135. /* }}} */
  136. CWD_API realpath_cache_bucket* realpath_cache_lookup(const char *path, int path_len, time_t t TSRMLS_DC) /* {{{ */
  137. {
  138. return realpath_cache_find(path, path_len, t TSRMLS_CC);
  139. }
  140. /* }}} */
  141. CWD_API int realpath_cache_size(TSRMLS_D)
  142. {
  143. return CWDG(realpath_cache_size);
  144. }
  145. CWD_API int realpath_cache_max_buckets(TSRMLS_D)
  146. {
  147. return (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
  148. }
  149. CWD_API realpath_cache_bucket** realpath_cache_get_buckets(TSRMLS_D)
  150. {
  151. return CWDG(realpath_cache);
  152. }
  153. #undef LINK_MAX
  154. #define LINK_MAX 32
  155. static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, int use_realpath, int is_dir, int *link_is_dir TSRMLS_DC) /* {{{ */
  156. {
  157. int i, j, save;
  158. int directory = 0;
  159. #ifdef TSRM_WIN32
  160. WIN32_FIND_DATA data;
  161. HANDLE hFind;
  162. TSRM_ALLOCA_FLAG(use_heap_large)
  163. #else
  164. struct stat st;
  165. #endif
  166. realpath_cache_bucket *bucket;
  167. char *tmp;
  168. TSRM_ALLOCA_FLAG(use_heap)
  169. while (1) {
  170. if (len <= start) {
  171. if (link_is_dir) {
  172. *link_is_dir = 1;
  173. }
  174. return start;
  175. }
  176. i = len;
  177. while (i > start && !IS_SLASH(path[i-1])) {
  178. i--;
  179. }
  180. if (i == len ||
  181. (i == len - 1 && path[i] == '.')) {
  182. /* remove double slashes and '.' */
  183. len = i - 1;
  184. is_dir = 1;
  185. continue;
  186. } else if (i == len - 2 && path[i] == '.' && path[i+1] == '.') {
  187. /* remove '..' and previous directory */
  188. is_dir = 1;
  189. if (link_is_dir) {
  190. *link_is_dir = 1;
  191. }
  192. if (i - 1 <= start) {
  193. return start ? start : len;
  194. }
  195. j = tsrm_realpath_r(path, start, i-1, ll, t, use_realpath, 1, NULL TSRMLS_CC);
  196. if (j > start) {
  197. j--;
  198. while (j > start && !IS_SLASH(path[j])) {
  199. j--;
  200. }
  201. if (!start) {
  202. /* leading '..' must not be removed in case of relative path */
  203. if (j == 0 && path[0] == '.' && path[1] == '.' &&
  204. IS_SLASH(path[2])) {
  205. path[3] = '.';
  206. path[4] = '.';
  207. path[5] = DEFAULT_SLASH;
  208. j = 5;
  209. } else if (j > 0 &&
  210. path[j+1] == '.' && path[j+2] == '.' &&
  211. IS_SLASH(path[j+3])) {
  212. j += 4;
  213. path[j++] = '.';
  214. path[j++] = '.';
  215. path[j] = DEFAULT_SLASH;
  216. }
  217. }
  218. } else if (!start && !j) {
  219. /* leading '..' must not be removed in case of relative path */
  220. path[0] = '.';
  221. path[1] = '.';
  222. path[2] = DEFAULT_SLASH;
  223. j = 2;
  224. }
  225. return j;
  226. }
  227. path[len] = 0;
  228. save = (use_realpath != CWD_EXPAND);
  229. if (start && save && CWDG(realpath_cache_size_limit)) {
  230. /* cache lookup for absolute path */
  231. if (!*t) {
  232. *t = time(0);
  233. }
  234. if ((bucket = realpath_cache_find(path, len, *t TSRMLS_CC)) != NULL) {
  235. if (is_dir && !bucket->is_dir) {
  236. /* not a directory */
  237. return -1;
  238. } else {
  239. if (link_is_dir) {
  240. *link_is_dir = bucket->is_dir;
  241. }
  242. memcpy(path, bucket->realpath, bucket->realpath_len + 1);
  243. return bucket->realpath_len;
  244. }
  245. }
  246. }
  247. #ifdef TSRM_WIN32
  248. if (save && (hFind = FindFirstFile(path, &data)) == INVALID_HANDLE_VALUE) {
  249. if (use_realpath == CWD_REALPATH) {
  250. /* file not found */
  251. return -1;
  252. }
  253. /* continue resolution anyway but don't save result in the cache */
  254. save = 0;
  255. }
  256. if (save) {
  257. FindClose(hFind);
  258. }
  259. tmp = tsrm_do_alloca(len+1, use_heap);
  260. memcpy(tmp, path, len+1);
  261. if(save &&
  262. !(IS_UNC_PATH(path, len) && len >= 3 && path[2] != '?') &&
  263. (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
  264. /* File is a reparse point. Get the target */
  265. HANDLE hLink = NULL;
  266. REPARSE_DATA_BUFFER * pbuffer;
  267. unsigned int retlength = 0;
  268. int bufindex = 0, isabsolute = 0;
  269. wchar_t * reparsetarget;
  270. BOOL isVolume = FALSE;
  271. char printname[MAX_PATH];
  272. char substitutename[MAX_PATH];
  273. int printname_len, substitutename_len;
  274. int substitutename_off = 0;
  275. if(++(*ll) > LINK_MAX) {
  276. return -1;
  277. }
  278. hLink = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
  279. if(hLink == INVALID_HANDLE_VALUE) {
  280. return -1;
  281. }
  282. pbuffer = (REPARSE_DATA_BUFFER *)tsrm_do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
  283. if (pbuffer == NULL) {
  284. return -1;
  285. }
  286. if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
  287. tsrm_free_alloca(pbuffer, use_heap_large);
  288. CloseHandle(hLink);
  289. return -1;
  290. }
  291. CloseHandle(hLink);
  292. if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
  293. reparsetarget = pbuffer->SymbolicLinkReparseBuffer.ReparseTarget;
  294. printname_len = pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR);
  295. isabsolute = (pbuffer->SymbolicLinkReparseBuffer.Flags == 0) ? 1 : 0;
  296. if (!WideCharToMultiByte(CP_THREAD_ACP, 0,
  297. reparsetarget + pbuffer->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR),
  298. printname_len + 1,
  299. printname, MAX_PATH, NULL, NULL
  300. )) {
  301. tsrm_free_alloca(pbuffer, use_heap_large);
  302. return -1;
  303. };
  304. printname_len = pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR);
  305. printname[printname_len] = 0;
  306. substitutename_len = pbuffer->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
  307. if (!WideCharToMultiByte(CP_THREAD_ACP, 0,
  308. reparsetarget + pbuffer->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
  309. substitutename_len + 1,
  310. substitutename, MAX_PATH, NULL, NULL
  311. )) {
  312. tsrm_free_alloca(pbuffer, use_heap_large);
  313. return -1;
  314. };
  315. substitutename[substitutename_len] = 0;
  316. }
  317. else if(pbuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  318. isabsolute = 1;
  319. reparsetarget = pbuffer->MountPointReparseBuffer.ReparseTarget;
  320. printname_len = pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR);
  321. if (!WideCharToMultiByte(CP_THREAD_ACP, 0,
  322. reparsetarget + pbuffer->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR),
  323. printname_len + 1,
  324. printname, MAX_PATH, NULL, NULL
  325. )) {
  326. tsrm_free_alloca(pbuffer, use_heap_large);
  327. return -1;
  328. };
  329. printname[pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR)] = 0;
  330. substitutename_len = pbuffer->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
  331. if (!WideCharToMultiByte(CP_THREAD_ACP, 0,
  332. reparsetarget + pbuffer->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
  333. substitutename_len + 1,
  334. substitutename, MAX_PATH, NULL, NULL
  335. )) {
  336. tsrm_free_alloca(pbuffer, use_heap_large);
  337. return -1;
  338. };
  339. substitutename[substitutename_len] = 0;
  340. }
  341. else if (pbuffer->ReparseTag == IO_REPARSE_TAG_DEDUP) {
  342. isabsolute = 1;
  343. memcpy(substitutename, path, len + 1);
  344. substitutename_len = len;
  345. } else {
  346. tsrm_free_alloca(pbuffer, use_heap_large);
  347. return -1;
  348. }
  349. if(isabsolute && substitutename_len > 4) {
  350. /* Do not resolve volumes (for now). A mounted point can
  351. target a volume without a drive, it is not certain that
  352. all IO functions we use in php and its deps support
  353. path with volume GUID instead of the DOS way, like:
  354. d:\test\mnt\foo
  355. \\?\Volume{62d1c3f8-83b9-11de-b108-806e6f6e6963}\foo
  356. */
  357. if (strncmp(substitutename, "\\??\\Volume{",11) == 0
  358. || strncmp(substitutename, "\\\\?\\Volume{",11) == 0
  359. || strncmp(substitutename, "\\??\\UNC\\", 8) == 0
  360. ) {
  361. isVolume = TRUE;
  362. substitutename_off = 0;
  363. } else
  364. /* do not use the \??\ and \\?\ prefix*/
  365. if (strncmp(substitutename, "\\??\\", 4) == 0
  366. || strncmp(substitutename, "\\\\?\\", 4) == 0) {
  367. substitutename_off = 4;
  368. }
  369. }
  370. if (!isVolume) {
  371. char * tmp2 = substitutename + substitutename_off;
  372. for(bufindex = 0; bufindex < (substitutename_len - substitutename_off); bufindex++) {
  373. *(path + bufindex) = *(tmp2 + bufindex);
  374. }
  375. *(path + bufindex) = 0;
  376. j = bufindex;
  377. } else {
  378. j = len;
  379. }
  380. #if VIRTUAL_CWD_DEBUG
  381. fprintf(stderr, "reparse: print: %s ", printname);
  382. fprintf(stderr, "sub: %s ", substitutename);
  383. fprintf(stderr, "resolved: %s ", path);
  384. #endif
  385. tsrm_free_alloca(pbuffer, use_heap_large);
  386. if(isabsolute == 1) {
  387. if (!((j == 3) && (path[1] == ':') && (path[2] == '\\'))) {
  388. /* use_realpath is 0 in the call below coz path is absolute*/
  389. j = tsrm_realpath_r(path, 0, j, ll, t, 0, is_dir, &directory TSRMLS_CC);
  390. if(j < 0) {
  391. tsrm_free_alloca(tmp, use_heap);
  392. return -1;
  393. }
  394. }
  395. }
  396. else {
  397. if(i + j >= MAXPATHLEN - 1) {
  398. tsrm_free_alloca(tmp, use_heap);
  399. return -1;
  400. }
  401. memmove(path+i, path, j+1);
  402. memcpy(path, tmp, i-1);
  403. path[i-1] = DEFAULT_SLASH;
  404. j = tsrm_realpath_r(path, start, i + j, ll, t, use_realpath, is_dir, &directory TSRMLS_CC);
  405. if(j < 0) {
  406. tsrm_free_alloca(tmp, use_heap);
  407. return -1;
  408. }
  409. }
  410. directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  411. if(link_is_dir) {
  412. *link_is_dir = directory;
  413. }
  414. }
  415. else {
  416. if (save) {
  417. directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  418. if (is_dir && !directory) {
  419. /* not a directory */
  420. return -1;
  421. }
  422. }
  423. #elif defined(NETWARE)
  424. save = 0;
  425. tmp = tsrm_do_alloca(len+1, use_heap);
  426. memcpy(tmp, path, len+1);
  427. #else
  428. if (save && php_sys_lstat(path, &st) < 0) {
  429. if (use_realpath == CWD_REALPATH) {
  430. /* file not found */
  431. return -1;
  432. }
  433. /* continue resolution anyway but don't save result in the cache */
  434. save = 0;
  435. }
  436. tmp = (char*) tsrm_do_alloca(len+1, use_heap);
  437. memcpy(tmp, path, len+1);
  438. if (save && S_ISLNK(st.st_mode)) {
  439. if (++(*ll) > LINK_MAX || (j = php_sys_readlink(tmp, path, MAXPATHLEN)) < 0) {
  440. /* too many links or broken symlinks */
  441. tsrm_free_alloca(tmp, use_heap);
  442. return -1;
  443. }
  444. path[j] = 0;
  445. if (IS_ABSOLUTE_PATH(path, j)) {
  446. j = tsrm_realpath_r(path, 1, j, ll, t, use_realpath, is_dir, &directory TSRMLS_CC);
  447. if (j < 0) {
  448. tsrm_free_alloca(tmp, use_heap);
  449. return -1;
  450. }
  451. } else {
  452. if (i + j >= MAXPATHLEN-1) {
  453. tsrm_free_alloca(tmp, use_heap);
  454. return -1; /* buffer overflow */
  455. }
  456. memmove(path+i, path, j+1);
  457. memcpy(path, tmp, i-1);
  458. path[i-1] = DEFAULT_SLASH;
  459. j = tsrm_realpath_r(path, start, i + j, ll, t, use_realpath, is_dir, &directory TSRMLS_CC);
  460. if (j < 0) {
  461. tsrm_free_alloca(tmp, use_heap);
  462. return -1;
  463. }
  464. }
  465. if (link_is_dir) {
  466. *link_is_dir = directory;
  467. }
  468. } else {
  469. if (save) {
  470. directory = S_ISDIR(st.st_mode);
  471. if (link_is_dir) {
  472. *link_is_dir = directory;
  473. }
  474. if (is_dir && !directory) {
  475. /* not a directory */
  476. tsrm_free_alloca(tmp, use_heap);
  477. return -1;
  478. }
  479. }
  480. #endif
  481. if (i - 1 <= start) {
  482. j = start;
  483. } else {
  484. /* some leading directories may be unaccessable */
  485. j = tsrm_realpath_r(path, start, i-1, ll, t, save ? CWD_FILEPATH : use_realpath, 1, NULL TSRMLS_CC);
  486. if (j > start) {
  487. path[j++] = DEFAULT_SLASH;
  488. }
  489. }
  490. #ifdef TSRM_WIN32
  491. if (j < 0 || j + len - i >= MAXPATHLEN-1) {
  492. tsrm_free_alloca(tmp, use_heap);
  493. return -1;
  494. }
  495. if (save) {
  496. i = strlen(data.cFileName);
  497. memcpy(path+j, data.cFileName, i+1);
  498. j += i;
  499. } else {
  500. /* use the original file or directory name as it wasn't found */
  501. memcpy(path+j, tmp+i, len-i+1);
  502. j += (len-i);
  503. }
  504. }
  505. #else
  506. if (j < 0 || j + len - i >= MAXPATHLEN-1) {
  507. tsrm_free_alloca(tmp, use_heap);
  508. return -1;
  509. }
  510. memcpy(path+j, tmp+i, len-i+1);
  511. j += (len-i);
  512. }
  513. #endif
  514. if (save && start && CWDG(realpath_cache_size_limit)) {
  515. /* save absolute path in the cache */
  516. realpath_cache_add(tmp, len, path, j, directory, *t TSRMLS_CC);
  517. }
  518. tsrm_free_alloca(tmp, use_heap);
  519. return j;
  520. }
  521. }
  522. /* }}} */
  523. /* Resolve path relatively to state and put the real path into state */
  524. /* returns 0 for ok, 1 for error */
  525. CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath TSRMLS_DC) /* {{{ */
  526. {
  527. int path_length = strlen(path);
  528. char resolved_path[MAXPATHLEN];
  529. int start = 1;
  530. int ll = 0;
  531. time_t t;
  532. int ret;
  533. int add_slash;
  534. void *tmp;
  535. if (path_length == 0 || path_length >= MAXPATHLEN-1) {
  536. #ifdef TSRM_WIN32
  537. # if _MSC_VER < 1300
  538. errno = EINVAL;
  539. # else
  540. _set_errno(EINVAL);
  541. # endif
  542. #else
  543. errno = EINVAL;
  544. #endif
  545. return 1;
  546. }
  547. #if VIRTUAL_CWD_DEBUG
  548. fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
  549. #endif
  550. /* cwd_length can be 0 when getcwd() fails.
  551. * This can happen under solaris when a dir does not have read permissions
  552. * but *does* have execute permissions */
  553. if (!IS_ABSOLUTE_PATH(path, path_length)) {
  554. if (state->cwd_length == 0) {
  555. /* resolve relative path */
  556. start = 0;
  557. memcpy(resolved_path , path, path_length + 1);
  558. } else {
  559. int state_cwd_length = state->cwd_length;
  560. #ifdef TSRM_WIN32
  561. if (IS_SLASH(path[0])) {
  562. if (state->cwd[1] == ':') {
  563. /* Copy only the drive name */
  564. state_cwd_length = 2;
  565. } else if (IS_UNC_PATH(state->cwd, state->cwd_length)) {
  566. /* Copy only the share name */
  567. state_cwd_length = 2;
  568. while (IS_SLASH(state->cwd[state_cwd_length])) {
  569. state_cwd_length++;
  570. }
  571. while (state->cwd[state_cwd_length] &&
  572. !IS_SLASH(state->cwd[state_cwd_length])) {
  573. state_cwd_length++;
  574. }
  575. while (IS_SLASH(state->cwd[state_cwd_length])) {
  576. state_cwd_length++;
  577. }
  578. while (state->cwd[state_cwd_length] &&
  579. !IS_SLASH(state->cwd[state_cwd_length])) {
  580. state_cwd_length++;
  581. }
  582. }
  583. }
  584. #endif
  585. if (path_length + state_cwd_length + 1 >= MAXPATHLEN-1) {
  586. return 1;
  587. }
  588. memcpy(resolved_path, state->cwd, state_cwd_length);
  589. if (resolved_path[state_cwd_length-1] == DEFAULT_SLASH) {
  590. memcpy(resolved_path + state_cwd_length, path, path_length + 1);
  591. path_length += state_cwd_length;
  592. } else {
  593. resolved_path[state_cwd_length] = DEFAULT_SLASH;
  594. memcpy(resolved_path + state_cwd_length + 1, path, path_length + 1);
  595. path_length += state_cwd_length + 1;
  596. }
  597. }
  598. } else {
  599. #ifdef TSRM_WIN32
  600. if (path_length > 2 && path[1] == ':' && !IS_SLASH(path[2])) {
  601. resolved_path[0] = path[0];
  602. resolved_path[1] = ':';
  603. resolved_path[2] = DEFAULT_SLASH;
  604. memcpy(resolved_path + 3, path + 2, path_length - 1);
  605. path_length++;
  606. } else
  607. #endif
  608. memcpy(resolved_path, path, path_length + 1);
  609. }
  610. #ifdef TSRM_WIN32
  611. if (memchr(resolved_path, '*', path_length) ||
  612. memchr(resolved_path, '?', path_length)) {
  613. return 1;
  614. }
  615. #endif
  616. #ifdef TSRM_WIN32
  617. if (IS_UNC_PATH(resolved_path, path_length)) {
  618. /* skip UNC name */
  619. resolved_path[0] = DEFAULT_SLASH;
  620. resolved_path[1] = DEFAULT_SLASH;
  621. start = 2;
  622. while (!IS_SLASH(resolved_path[start])) {
  623. if (resolved_path[start] == 0) {
  624. goto verify;
  625. }
  626. resolved_path[start] = toupper(resolved_path[start]);
  627. start++;
  628. }
  629. resolved_path[start++] = DEFAULT_SLASH;
  630. while (!IS_SLASH(resolved_path[start])) {
  631. if (resolved_path[start] == 0) {
  632. goto verify;
  633. }
  634. resolved_path[start] = toupper(resolved_path[start]);
  635. start++;
  636. }
  637. resolved_path[start++] = DEFAULT_SLASH;
  638. } else if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {
  639. /* skip DRIVE name */
  640. resolved_path[0] = toupper(resolved_path[0]);
  641. resolved_path[2] = DEFAULT_SLASH;
  642. start = 3;
  643. }
  644. #elif defined(NETWARE)
  645. if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {
  646. /* skip VOLUME name */
  647. start = 0;
  648. while (start != ':') {
  649. if (resolved_path[start] == 0) return -1;
  650. start++;
  651. }
  652. start++;
  653. if (!IS_SLASH(resolved_path[start])) return -1;
  654. resolved_path[start++] = DEFAULT_SLASH;
  655. }
  656. #endif
  657. add_slash = (use_realpath != CWD_REALPATH) && path_length > 0 && IS_SLASH(resolved_path[path_length-1]);
  658. t = CWDG(realpath_cache_ttl) ? 0 : -1;
  659. path_length = tsrm_realpath_r(resolved_path, start, path_length, &ll, &t, use_realpath, 0, NULL TSRMLS_CC);
  660. if (path_length < 0) {
  661. errno = ENOENT;
  662. return 1;
  663. }
  664. if (!start && !path_length) {
  665. resolved_path[path_length++] = '.';
  666. }
  667. if (add_slash && path_length && !IS_SLASH(resolved_path[path_length-1])) {
  668. if (path_length >= MAXPATHLEN-1) {
  669. return -1;
  670. }
  671. resolved_path[path_length++] = DEFAULT_SLASH;
  672. }
  673. resolved_path[path_length] = 0;
  674. #ifdef TSRM_WIN32
  675. verify:
  676. #endif
  677. if (verify_path) {
  678. cwd_state old_state;
  679. CWD_STATE_COPY(&old_state, state);
  680. state->cwd_length = path_length;
  681. tmp = realloc(state->cwd, state->cwd_length+1);
  682. if (tmp == NULL) {
  683. #if VIRTUAL_CWD_DEBUG
  684. fprintf (stderr, "Out of memory\n");
  685. #endif
  686. return 1;
  687. }
  688. state->cwd = (char *) tmp;
  689. memcpy(state->cwd, resolved_path, state->cwd_length+1);
  690. if (verify_path(state)) {
  691. CWD_STATE_FREE(state);
  692. *state = old_state;
  693. ret = 1;
  694. } else {
  695. CWD_STATE_FREE(&old_state);
  696. ret = 0;
  697. }
  698. } else {
  699. state->cwd_length = path_length;
  700. tmp = realloc(state->cwd, state->cwd_length+1);
  701. if (tmp == NULL) {
  702. #if VIRTUAL_CWD_DEBUG
  703. fprintf (stderr, "Out of memory\n");
  704. #endif
  705. return 1;
  706. }
  707. state->cwd = (char *) tmp;
  708. memcpy(state->cwd, resolved_path, state->cwd_length+1);
  709. ret = 0;
  710. }
  711. #if VIRTUAL_CWD_DEBUG
  712. fprintf (stderr, "virtual_file_ex() = %s\n",state->cwd);
  713. #endif
  714. return (ret);
  715. }
  716. /* }}} */