getcwd.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. {
  2. $Id$
  3. }
  4. {*
  5. * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
  6. *
  7. * @APPLE_LICENSE_HEADER_START@
  8. *
  9. * The contents of this file constitute Original Code as defined in and
  10. * are subject to the Apple Public Source License Version 1.1 (the
  11. * "License"). You may not use this file except in compliance with the
  12. * License. Please obtain a copy of the License at
  13. * http://www.apple.com/publicsource and read it before using this file.
  14. *
  15. * This Original Code and all software distributed under the License are
  16. * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  17. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  18. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
  20. * License for the specific language governing rights and limitations
  21. * under the License.
  22. *
  23. * @APPLE_LICENSE_HEADER_END@
  24. *
  25. *
  26. * Copyright (c) 1989, 1991, 1993
  27. * The Regents of the University of California. All rights reserved.
  28. *
  29. * Redistribution and use in source and binary forms, with or without
  30. * modification, are permitted provided that the following conditions
  31. * are met:
  32. * 1. Redistributions of source code must retain the above copyright
  33. * notice, this list of conditions and the following disclaimer.
  34. * 2. Redistributions in binary form must reproduce the above copyright
  35. * notice, this list of conditions and the following disclaimer in the
  36. * documentation and/or other materials provided with the distribution.
  37. * 3. All advertising materials mentioning features or use of this software
  38. * must display the following acknowledgement:
  39. * This product includes software developed by the University of
  40. * California, Berkeley and its contributors.
  41. * 4. Neither the name of the University nor the names of its contributors
  42. * may be used to endorse or promote products derived from this software
  43. * without specific prior written permission.
  44. *
  45. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  46. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  47. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  48. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  49. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  50. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  51. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  52. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  53. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  54. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  55. * SUCH DAMAGE.
  56. *}
  57. const
  58. MAXPATHLEN = 1024;
  59. MAXNAMLEN = 255;
  60. function getcwd_physical(pt: pchar; size: size_t): pchar;
  61. var
  62. dp: pdirent;
  63. dir: pdir;
  64. dev: dev_t;
  65. ino: ino_t;
  66. first: longint;
  67. bpt, bup: pchar;
  68. s: stat;
  69. root_dev: dev_t;
  70. root_ino: ino_t;
  71. ptsize, upsize: size_t;
  72. save_errno: longint;
  73. ept, eup, up: pchar;
  74. len, off: size_t;
  75. err, notfound: boolean;
  76. {*
  77. * If no buffer specified by the user, allocate one as necessary.
  78. * If a buffer is specified, the size has to be non-zero. The path
  79. * is built from the end of the buffer backwards.
  80. *}
  81. begin
  82. err := false;
  83. notfound := false;
  84. if (pt <> nil) then
  85. begin
  86. ptsize := 0;
  87. if (size = 0) then
  88. begin
  89. errno := ESysEINVAL;
  90. getcwd_physical := nil;
  91. exit;
  92. end;
  93. ept := pt + size;
  94. end
  95. else
  96. begin
  97. ptsize := 1024;
  98. getmem(pt,ptsize);
  99. ept := pt + ptsize;
  100. end;
  101. bpt := ept - 1;
  102. bpt^ := #0;
  103. {*
  104. * Allocate bytes (1024 - malloc space) for the string of "../"'s.
  105. * Should always be enough (it's 340 levels). If it's not, allocate
  106. * as necessary. Special case the first stat, it's ".", not "..".
  107. *}
  108. upsize := 1024;
  109. getmem(up,1024);
  110. eup := up + MAXPATHLEN;
  111. bup := up;
  112. up[0] := '.';
  113. up[1] := #0;
  114. { Save root values, so know when to stop. }
  115. if (Fpstat('/', s) = 0) THEN
  116. begin
  117. root_dev := s.st_dev;
  118. root_ino := s.st_ino;
  119. errno := 0; { XXX readdir has no error return. }
  120. first := 1;
  121. repeat
  122. { Stat the current level. }
  123. if (fplstat(up, s) <> 0) then
  124. err := true
  125. else
  126. begin
  127. { Save current node values. }
  128. ino := s.st_ino;
  129. dev := s.st_dev;
  130. { Check for reaching root. }
  131. if ((root_dev = dev) and (root_ino = ino)) then
  132. begin
  133. dec(bpt);
  134. bpt^ := '/';
  135. {*
  136. * It's unclear that it's a requirement to copy the
  137. * path to the beginning of the buffer, but it's always
  138. * been that way and stuff would probably break'.
  139. *}
  140. move(bpt^, pt^, ept - bpt);
  141. freemem(up);
  142. getcwd_physical := pt;
  143. exit;
  144. end;
  145. {
  146. * Build pointer to the parent directory, allocating memory
  147. * as necessary. Max length is 3 for "../", the largest
  148. * possible component name, plus a trailing NULL.
  149. *}
  150. if (bup + 3 + MAXNAMLEN + 1 >= eup) then
  151. begin
  152. upsize := upsize*2;
  153. reallocmem(up,upsize);
  154. bup := up;
  155. eup := up + upsize;
  156. end;
  157. bup^ := '.';
  158. inc(bup);
  159. bup^ := '.';
  160. inc(bup);
  161. bup^ := #0;
  162. {* Open and stat parent directory. *}
  163. dir := Fpopendir(up);
  164. if (pdir <> nil) then
  165. begin
  166. if (fpfstat(dir^.dd_fd,s) <> 0) then
  167. err := true;
  168. end
  169. else
  170. err := true;
  171. if not err then
  172. begin
  173. { Add trailing slash for next directory. }
  174. bup^ := '/';
  175. inc(bup);
  176. {*
  177. * If it's a mount point, have to stat each element because
  178. * the inode number in the directory is for the entry in the
  179. * parent directory, not the inode number of the mounted file.
  180. *'}
  181. save_errno := 0;
  182. if (s.st_dev = dev) then
  183. begin
  184. repeat
  185. dp := Fpreaddir(dir);
  186. notfound := dp = nil;
  187. until notfound or
  188. (dp^.d_fileno = ino);
  189. end
  190. else
  191. begin
  192. repeat
  193. dp := Fpreaddir(dir);
  194. if (dp = nil) then
  195. notfound := true
  196. else
  197. begin
  198. if (dp^.d_name[0] = '.') and
  199. ((dp^.d_name[1] = #0) or
  200. ((dp^.d_name[1] = '.') and
  201. (dp^.d_name[2] = #0))) then
  202. continue;
  203. move(dp^.d_name, bup^, dp^.d_namlen + 1);
  204. { Save the first error for later. }
  205. if (fplstat(up,s) <> 0) then
  206. begin
  207. if (save_errno = 0) then
  208. save_errno := errno;
  209. errno := 0;
  210. continue;
  211. end;
  212. end;
  213. until notfound or
  214. ((s.st_dev = dev) and
  215. (s.st_ino = ino));
  216. end;
  217. {*
  218. * Check for length of the current name, preceding slash,
  219. * leading slash.
  220. *}
  221. if not (notfound) then
  222. begin
  223. // was: (first ? 1 : 2), first can only be 1 or 0
  224. if (bpt - pt <= dp^.d_namlen + ((first xor 1) + 1)) then
  225. begin
  226. if ( ptsize <> 0) then
  227. begin
  228. errno := ESysERANGE;
  229. err := true;
  230. end
  231. else
  232. begin
  233. off := bpt - pt;
  234. len := ept - bpt;
  235. ptsize := ptsize *2;
  236. reallocmem(pt,ptsize);
  237. bpt := pt + off;
  238. ept := pt + ptsize;
  239. move(bpt^, (ept - len)^, len);
  240. bpt := ept - len;
  241. end;
  242. end;
  243. if (first = 0) then
  244. begin
  245. dec(bpt);
  246. bpt^ := '/';
  247. end;
  248. dec(bpt,dp^.d_namlen);
  249. move(dp^.d_name, bpt^, dp^.d_namlen);
  250. Fpclosedir(dir);
  251. { Truncate any file name. }
  252. bup^ := #0;
  253. first := 0;
  254. end;
  255. end;
  256. end;
  257. until err or notfound;
  258. if (notfound) then
  259. begin
  260. {*
  261. * If readdir set errno, use it, not any saved error; otherwise,
  262. * didn't find the current directory in its parent directory, set
  263. * errno to ENOENT.'
  264. *}
  265. if (errno = 0) then
  266. if save_errno <> 0 then
  267. errno := save_errno
  268. else
  269. errno := ESysENOENT;
  270. end;
  271. end;
  272. if (err) then
  273. begin
  274. if (ptsize <> 0) then
  275. freemem(pt);
  276. freemem(up);
  277. getcwd_physical := nil;
  278. end;
  279. end;
  280. function getcwd(pt: pchar; size: size_t): pchar;
  281. var
  282. pwd: pchar;
  283. pwdlen: size_t;
  284. dev: dev_t;
  285. ino: ino_t;
  286. s: stat;
  287. begin
  288. (*
  289. { Check $PWD -- if it's right, it's fast. }
  290. if ((pwd = getenv("PWD")) != NULL && pwd[0] == '/' && stat(pwd, &s) != -1) {
  291. dev = s.st_dev;
  292. ino = s.st_ino;
  293. if (stat(".", &s) != -1 && dev == s.st_dev && ino == s.st_ino) {
  294. pwdlen = strlen(pwd);
  295. if (pt) {
  296. if (!size) {
  297. errno = EINVAL;
  298. return (NULL);
  299. }
  300. if (pwdlen + 1 > size) {
  301. errno = ERANGE;
  302. return (NULL);
  303. }
  304. } else if ((pt = malloc(pwdlen + 1)) == NULL) {
  305. errno = ENOMEM;
  306. return (NULL);
  307. }
  308. memmove(pt, pwd, pwdlen);
  309. pt[pwdlen] = '\0';
  310. return (pt);
  311. }
  312. }
  313. *)
  314. getcwd := (getcwd_physical(pt, size));
  315. end;
  316. {
  317. $Log$
  318. Revision 1.1 2003-05-26 21:29:16 jonas
  319. - disabled nanosleep for darwin for now
  320. + getcwd for darwin
  321. }