Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

713 lines
17 KiB

  1. /*
  2. opendir -- open a directory stream
  3. last edit: 16-Jun-1987 D A Gwyn
  4. */
  5. #include <sys/errno.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include "paxdir.h"
  9. #ifdef BSD_SYSV
  10. /*
  11. <sys/_dir.h> -- definitions for 4.2,4.3BSD directories
  12. last edit: 25-Apr-1987 D A Gwyn
  13. A directory consists of some number of blocks of DIRBLKSIZ bytes each,
  14. where DIRBLKSIZ is chosen such that it can be transferred to disk in a
  15. single atomic operation (e.g., 512 bytes on most machines).
  16. Each DIRBLKSIZ-byte block contains some number of directory entry
  17. structures, which are of variable length. Each directory entry has the
  18. beginning of a (struct direct) at the front of it, containing its
  19. filesystem-unique ident number, the length of the entry, and the length
  20. of the name contained in the entry. These are followed by the NUL-
  21. terminated name padded to a (long) boundary with 0 bytes. The maximum
  22. length of a name in a directory is MAXNAMELEN.
  23. The macro DIRSIZ(dp) gives the amount of space required to represent a
  24. directory entry. Free space in a directory is represented by entries
  25. that have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes in a
  26. directory block are claimed by the directory entries; this usually
  27. results in the last entry in a directory having a large dp->d_reclen.
  28. When entries are deleted from a directory, the space is returned to the
  29. previous entry in the same directory block by increasing its
  30. dp->d_reclen. If the first entry of a directory block is free, then
  31. its dp->d_fileno is set to 0; entries other than the first in a
  32. directory do not normally have dp->d_fileno set to 0.
  33. prerequisite: <sys/types.h>
  34. */
  35. #if defined(accel) || defined(sun) || defined(vax)
  36. #define DIRBLKSIZ 512 /* size of directory block */
  37. #else
  38. #ifdef alliant
  39. #define DIRBLKSIZ 4096 /* size of directory block */
  40. #else
  41. #ifdef gould
  42. #define DIRBLKSIZ 1024 /* size of directory block */
  43. #else
  44. #ifdef ns32000 /* Dynix System V */
  45. #define DIRBLKSIZ 2600 /* size of directory block */
  46. #else /* be conservative; multiple blocks are okay
  47. * but fractions are not */
  48. #define DIRBLKSIZ 4096 /* size of directory block */
  49. #endif
  50. #endif
  51. #endif
  52. #endif
  53. #define MAXNAMELEN 255 /* maximum filename length */
  54. /* NOTE: not MAXNAMLEN, which has been preempted by SVR3 <dirent.h> */
  55. struct direct { /* data from read()/_getdirentries() */
  56. unsigned long d_fileno; /* unique ident of entry */
  57. unsigned short d_reclen; /* length of this record */
  58. unsigned short d_namlen; /* length of string in d_name */
  59. char d_name[MAXNAMELEN + 1]; /* NUL-terminated filename */
  60. };
  61. /*
  62. The DIRSIZ macro gives the minimum record length which will hold the
  63. directory entry. This requires the amount of space in a (struct
  64. direct) without the d_name field, plus enough space for the name with a
  65. terminating NUL character, rounded up to a (long) boundary.
  66. (Note that Berkeley didn't properly compensate for struct padding,
  67. but we nevertheless have to use the same size as the actual system.)
  68. */
  69. #define DIRSIZ( dp ) ((sizeof(struct direct) - (MAXNAMELEN+1) \
  70. + sizeof(long) + (dp)->d_namlen) \
  71. / sizeof(long) * sizeof(long))
  72. #else
  73. #ifndef _POSIX_SOURCE
  74. #include <sys/dirent.h>
  75. #endif
  76. #ifdef SYSV3
  77. #undef MAXNAMLEN /* avoid conflict with SVR3 */
  78. #endif
  79. /* Good thing we don't need to use the DIRSIZ() macro! */
  80. #ifdef d_ino /* 4.3BSD/NFS using d_fileno */
  81. #undef d_ino /* (not absolutely necessary) */
  82. #else
  83. #define d_fileno d_ino /* (struct direct) member */
  84. #endif
  85. #endif
  86. #ifdef UNK
  87. #ifndef UFS
  88. #include "***** ERROR ***** UNK applies only to UFS"
  89. /* One could do something similar for getdirentries(), but I didn't bother. */
  90. #endif
  91. #include <signal.h>
  92. #endif
  93. #if defined(UFS) + defined(BFS) + defined(NFS) != 1 /* sanity check */
  94. #include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined"
  95. #endif
  96. #ifdef UFS
  97. #define RecLen( dp ) (sizeof(struct direct)) /* fixed-length entries */
  98. #else /* BFS || NFS */
  99. #define RecLen( dp ) ((dp)->d_reclen) /* variable-length entries */
  100. #endif
  101. #ifdef NFS
  102. #ifdef BSD_SYSV
  103. #define getdirentries _getdirentries /* package hides this system call */
  104. #endif
  105. extern int getdirentries();
  106. static long dummy; /* getdirentries() needs basep */
  107. #define GetBlock( fd, buf, n ) getdirentries( fd, buf, (unsigned)n, &dummy )
  108. #else /* UFS || BFS */
  109. #ifdef BSD_SYSV
  110. #define read _read /* avoid emulation overhead */
  111. #endif
  112. extern int read();
  113. #define GetBlock( fd, buf, n ) read( fd, buf, (unsigned)n )
  114. #endif
  115. #ifdef UNK
  116. extern int _getdents(); /* actual system call */
  117. #endif
  118. extern char *strncpy();
  119. extern int fstat();
  120. extern OFFSET lseek();
  121. extern int errno;
  122. #ifndef DIRBLKSIZ
  123. #define DIRBLKSIZ 4096 /* directory file read buffer size */
  124. #endif
  125. #ifndef NULL
  126. #define NULL 0
  127. #endif
  128. #ifndef SEEK_CUR
  129. #define SEEK_CUR 1
  130. #endif
  131. #ifndef S_ISDIR /* macro to test for directory file */
  132. #define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR)
  133. #endif
  134. #ifndef SEEK_CUR
  135. #define SEEK_CUR 1
  136. #endif
  137. #ifdef BSD_SYSV
  138. #define open _open /* avoid emulation overhead */
  139. #endif
  140. extern int getdents(); /* SVR3 system call, or emulation */
  141. typedef char *pointer; /* (void *) if you have it */
  142. extern void free();
  143. extern pointer malloc();
  144. extern int
  145. open(), close(), fstat();
  146. extern int errno;
  147. extern OFFSET lseek();
  148. #ifndef SEEK_SET
  149. #define SEEK_SET 0
  150. #endif
  151. typedef int bool; /* Boolean data type */
  152. #define false 0
  153. #define true 1
  154. #ifndef NULL
  155. #define NULL 0
  156. #endif
  157. #ifndef O_RDONLY
  158. #define O_RDONLY 0
  159. #endif
  160. #ifndef S_ISDIR /* macro to test for directory file */
  161. #define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR)
  162. #endif
  163. #ifdef __STDC__
  164. DIR *opendir(char *dirname)
  165. #else
  166. DIR *opendir(dirname)
  167. char *dirname; /* name of directory */
  168. #endif
  169. {
  170. register DIR *dirp; /* -> malloc'ed storage */
  171. register int fd; /* file descriptor for read */
  172. #ifdef DF_TRACE_DEBUG
  173. printf("DF_TRACE_DEBUG: + sizeof() in paxdir.c\n");
  174. #endif
  175. struct stat sbuf; /* result of fstat() */
  176. if ((fd = open(dirname, O_RDONLY)) < 0)
  177. return ((DIR *)NULL); /* errno set by open() */
  178. if (fstat(fd, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
  179. close(fd);
  180. errno = ENOTDIR;
  181. return ((DIR *)NULL); /* not a directory */
  182. }
  183. if ((dirp = (DIR *) malloc(sizeof(DIR))) == (DIR *)NULL
  184. || (dirp->dd_buf = (char *) malloc((unsigned) DIRBUF)) == (char *)NULL
  185. ) {
  186. register int serrno = errno;
  187. /* errno set to ENOMEM by sbrk() */
  188. if (dirp != (DIR *)NULL)
  189. free((pointer) dirp);
  190. close(fd);
  191. errno = serrno;
  192. return ((DIR *)NULL); /* not enough memory */
  193. }
  194. dirp->dd_fd = fd;
  195. dirp->dd_loc = dirp->dd_size = 0; /* refill needed */
  196. return dirp;
  197. }
  198. /*
  199. * closedir -- close a directory stream
  200. *
  201. * last edit: 11-Nov-1988 D A Gwyn
  202. */
  203. #ifdef __STDC__
  204. int closedir(register DIR *dirp)
  205. #else
  206. int closedir(dirp)
  207. register DIR *dirp; /* stream from opendir() */
  208. #endif
  209. {
  210. register int fd;
  211. if ( dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL ) {
  212. errno = EFAULT;
  213. return -1; /* invalid pointer */
  214. }
  215. fd = dirp->dd_fd; /* bug fix thanks to R. Salz */
  216. free( (pointer)dirp->dd_buf );
  217. free( (pointer)dirp );
  218. return close( fd );
  219. }
  220. /*
  221. readdir -- read next entry from a directory stream
  222. last edit: 25-Apr-1987 D A Gwyn
  223. */
  224. #ifdef __STDC__
  225. struct dirent *readdir(register DIR *dirp)
  226. #else
  227. struct dirent *readdir(dirp)
  228. register DIR *dirp; /* stream from opendir() */
  229. #endif
  230. {
  231. register struct dirent *dp; /* -> directory data */
  232. #ifdef DF_TRACE_DEBUG
  233. printf("DF_TRACE_DEBUG: struct dirent *readdir() in paxdir.c\n");
  234. #endif
  235. if (dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL) {
  236. errno = EFAULT;
  237. return (struct dirent *)NULL; /* invalid pointer */
  238. }
  239. do {
  240. if (dirp->dd_loc >= dirp->dd_size) /* empty or obsolete */
  241. dirp->dd_loc = dirp->dd_size = 0;
  242. if (dirp->dd_size == 0 /* need to refill buffer */
  243. && (dirp->dd_size =
  244. getdents(dirp->dd_fd, dirp->dd_buf, (unsigned) DIRBUF)
  245. ) <= 0
  246. )
  247. return ((struct dirent *)NULL); /* EOF or error */
  248. dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc];
  249. dirp->dd_loc += dp->d_reclen;
  250. }
  251. while (dp->d_ino == 0L); /* don't rely on getdents() */
  252. return dp;
  253. }
  254. /*
  255. seekdir -- reposition a directory stream
  256. last edit: 24-May-1987 D A Gwyn
  257. An unsuccessful seekdir() will in general alter the current
  258. directory position; beware.
  259. NOTE: 4.nBSD directory compaction makes seekdir() & telldir()
  260. practically impossible to do right. Avoid using them!
  261. */
  262. #ifdef __STDC__
  263. void seekdir(register DIR *dirp, register OFFSET loc)
  264. #else
  265. void seekdir(dirp, loc)
  266. register DIR *dirp; /* stream from opendir() */
  267. register OFFSET loc; /* position from telldir() */
  268. #endif
  269. {
  270. register bool rewind; /* "start over when stymied" flag */
  271. if (dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL) {
  272. errno = EFAULT;
  273. return; /* invalid pointer */
  274. }
  275. /*
  276. * A (struct dirent)'s d_off is an invented quantity on 4.nBSD
  277. * NFS-supporting systems, so it is not safe to lseek() to it.
  278. */
  279. /* Monotonicity of d_off is heavily exploited in the following. */
  280. /*
  281. * This algorithm is tuned for modest directory sizes. For huge
  282. * directories, it might be more efficient to read blocks until the first
  283. * d_off is too large, then back up one block, or even to use binary
  284. * search on the directory blocks. I doubt that the extra code for that
  285. * would be worthwhile.
  286. */
  287. if (dirp->dd_loc >= dirp->dd_size /* invalid index */
  288. || ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off > loc
  289. /* too far along in buffer */
  290. )
  291. dirp->dd_loc = 0; /* reset to beginning of buffer */
  292. /* else save time by starting at current dirp->dd_loc */
  293. for (rewind = true;;) {
  294. register struct dirent *dp;
  295. /* See whether the matching entry is in the current buffer. */
  296. if ((dirp->dd_loc < dirp->dd_size /* valid index */
  297. || readdir(dirp) != (struct dirent *)NULL /* next buffer read */
  298. && (dirp->dd_loc = 0, true) /* beginning of buffer set */
  299. )
  300. && (dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off
  301. <= loc /* match possible in this buffer */
  302. ) {
  303. #ifdef DF_TRACE_DEBUG
  304. printf("DF_TRACE_DEBUG: || readdir() in paxdir.c\n");
  305. #endif
  306. for ( /* dp initialized above */ ;
  307. (char *) dp < &dirp->dd_buf[dirp->dd_size];
  308. dp = (struct dirent *) ((char *) dp + dp->d_reclen)
  309. )
  310. if (dp->d_off == loc) { /* found it! */
  311. dirp->dd_loc =
  312. (char *) dp - dirp->dd_buf;
  313. return;
  314. }
  315. rewind = false; /* no point in backing up later */
  316. dirp->dd_loc = dirp->dd_size; /* set end of buffer */
  317. } else
  318. #ifdef DF_TRACE_DEBUG
  319. printf("DF_TRACE_DEBUG: dp = () in paxdir.c\n");
  320. #endif
  321. /* whole buffer past matching entry */ if (!rewind) { /* no point in searching
  322. * further */
  323. errno = EINVAL;
  324. return; /* no entry at specified loc */
  325. } else { /* rewind directory and start over */
  326. rewind = false; /* but only once! */
  327. dirp->dd_loc = dirp->dd_size = 0;
  328. if (lseek(dirp->dd_fd, (OFFSET) 0, SEEK_SET)
  329. != 0
  330. )
  331. return; /* errno already set (EBADF) */
  332. if (loc == 0)
  333. return; /* save time */
  334. }
  335. }
  336. }
  337. /* telldir - report directory stream position
  338. *
  339. * DESCRIPTION
  340. *
  341. * Returns the offset of the next directory entry in the
  342. * directory associated with dirp.
  343. *
  344. * NOTE: 4.nBSD directory compaction makes seekdir() & telldir()
  345. * practically impossible to do right. Avoid using them!
  346. *
  347. * PARAMETERS
  348. *
  349. * DIR *dirp - stream from opendir()
  350. *
  351. * RETURNS
  352. *
  353. * Return offset of next entry
  354. */
  355. #ifdef __STDC__
  356. OFFSET telldir(DIR *dirp)
  357. #else
  358. OFFSET telldir(dirp)
  359. DIR *dirp; /* stream from opendir() */
  360. #endif
  361. {
  362. if (dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL) {
  363. errno = EFAULT;
  364. return -1; /* invalid pointer */
  365. }
  366. if (dirp->dd_loc < dirp->dd_size) /* valid index */
  367. return ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off;
  368. else /* beginning of next directory block */
  369. return lseek(dirp->dd_fd, (OFFSET) 0, SEEK_CUR);
  370. }
  371. #ifdef UFS
  372. /*
  373. The following routine is necessary to handle DIRSIZ-long entry names.
  374. Thanks to Richard Todd for pointing this out.
  375. */
  376. /* return # chars in embedded name */
  377. #ifdef __STDC__
  378. static int NameLen(char *name)
  379. #else
  380. static int NameLen(name)
  381. char *name; /* -> name embedded in struct direct */
  382. #endif
  383. {
  384. register char *s; /* -> name[.] */
  385. register char *stop = &name[DIRSIZ]; /* -> past end of name field */
  386. for (s = &name[1]; /* (empty names are impossible) */
  387. *s != '\0' /* not NUL terminator */
  388. && ++s < stop; /* < DIRSIZ characters scanned */
  389. );
  390. return s - name; /* # valid characters in name */
  391. }
  392. #else /* BFS || NFS */
  393. extern int strlen();
  394. #define NameLen( name ) strlen( name ) /* names are always NUL-terminated */
  395. #endif
  396. #ifdef UNK
  397. static enum {
  398. maybe, no, yes
  399. } state = maybe;
  400. /* sig_catch - used to catch signals
  401. *
  402. * DESCRIPTION
  403. *
  404. * Used to catch signals.
  405. */
  406. /*ARGSUSED*/
  407. #ifdef __STDC__
  408. static void sig_catch(int sig)
  409. #else
  410. static void sig_catch(sig)
  411. int sig; /* must be SIGSYS */
  412. #endif
  413. {
  414. #ifdef DF_TRACE_DEBUG
  415. printf("DF_TRACE_DEBUG: static void sig_catch() in paxdir.c\n");
  416. #endif
  417. state = no; /* attempted _getdents() faulted */
  418. }
  419. #endif
  420. /* getdents - get directory entries
  421. *
  422. * DESCRIPTION
  423. *
  424. * Gets directory entries from the filesystem in an implemenation
  425. * defined way.
  426. *
  427. * PARAMETERS
  428. *
  429. * int fildes - directory file descriptor
  430. * char *buf - where to put the (struct dirent)s
  431. * unsigned nbyte - size of buf[]
  432. *
  433. * RETURNS
  434. *
  435. * Returns number of bytes read; 0 on EOF, -1 on error
  436. */
  437. #ifdef __STDC__
  438. int getdents(int fildes, char *buf, unsigned nbyte)
  439. #else
  440. int getdents(fildes, buf, nbyte)
  441. int fildes; /* directory file descriptor */
  442. char *buf; /* where to put the (struct dirent)s */
  443. unsigned nbyte; /* size of buf[] */
  444. #endif
  445. {
  446. int serrno; /* entry errno */
  447. OFFSET offset; /* initial directory file offset */
  448. #ifdef DF_TRACE_DEBUG
  449. printf("DF_TRACE_DEBUG: int getdents() in paxdir.c\n");
  450. #endif
  451. struct stat statb; /* fstat() info */
  452. union {
  453. /* directory file block buffer */
  454. #ifdef UFS
  455. char dblk[DIRBLKSIZ + 1];
  456. #else
  457. char dblk[DIRBLKSIZ];
  458. #endif
  459. struct direct dummy; /* just for alignment */
  460. } u; /* (avoids having to malloc()) */
  461. register struct direct *dp; /* -> u.dblk[.] */
  462. register struct dirent *bp; /* -> buf[.] */
  463. #ifdef UNK
  464. switch (state) {
  465. SIG_T (*shdlr)(); /* entry SIGSYS handler */
  466. register int retval; /* return from _getdents() if any */
  467. case yes: /* _getdents() is known to work */
  468. return _getdents(fildes, buf, nbyte);
  469. case maybe: /* first time only */
  470. shdlr = signal(SIGSYS, sig_catch);
  471. retval = _getdents(fildes, buf, nbyte); /* try it */
  472. signal(SIGSYS, shdlr);
  473. if (state == maybe) { /* SIGSYS did not occur */
  474. state = yes; /* so _getdents() must have worked */
  475. return retval;
  476. }
  477. /* else fall through into emulation */
  478. /* case no: /* fall through into emulation */
  479. }
  480. #endif
  481. if (buf == (char *)NULL
  482. #ifdef ATT_SPEC
  483. || (unsigned long) buf % sizeof(long) != 0 /* ugh */
  484. #endif
  485. ) {
  486. errno = EFAULT; /* invalid pointer */
  487. return -1;
  488. }
  489. if (fstat(fildes, &statb) != 0) {
  490. return -1; /* errno set by fstat() */
  491. }
  492. if (!S_ISDIR(statb.st_mode)) {
  493. errno = ENOTDIR; /* not a directory */
  494. return -1;
  495. }
  496. if ((offset = lseek(fildes, (OFFSET) 0, SEEK_CUR)) < 0) {
  497. return -1; /* errno set by lseek() */
  498. }
  499. #ifdef BFS /* no telling what remote hosts do */
  500. if ((unsigned long) offset % DIRBLKSIZ != 0) {
  501. errno = ENOENT; /* file pointer probably misaligned */
  502. return -1;
  503. }
  504. #endif
  505. serrno = errno; /* save entry errno */
  506. for (bp = (struct dirent *) buf; bp == (struct dirent *) buf;) {
  507. /* convert next directory block */
  508. int size;
  509. do {
  510. size = GetBlock(fildes, u.dblk, DIRBLKSIZ);
  511. } while (size == -1 && errno == EINTR);
  512. if (size <= 0) {
  513. return size; /* EOF or error (EBADF) */
  514. }
  515. for (dp = (struct direct *) u.dblk;
  516. (char *) dp < &u.dblk[size];
  517. dp = (struct direct *) ((char *) dp + RecLen(dp))
  518. ) {
  519. #ifndef UFS
  520. if (dp->d_reclen <= 0) {
  521. errno = EIO; /* corrupted directory */
  522. return -1;
  523. }
  524. #endif
  525. if (dp->d_fileno != 0) { /* non-empty; copy to user buffer */
  526. register int reclen =
  527. DIRENTSIZ(NameLen(dp->d_name));
  528. if ((char *) bp + reclen > &buf[nbyte]) {
  529. errno = EINVAL;
  530. return -1; /* buf too small */
  531. }
  532. bp->d_ino = dp->d_fileno;
  533. bp->d_off = offset + ((char *) dp - u.dblk);
  534. bp->d_reclen = reclen;
  535. {
  536. #ifdef UFS
  537. /* Is the following kludge ugly? You bet. */
  538. register char save = dp->d_name[DIRSIZ];
  539. /* save original data */
  540. dp->d_name[DIRSIZ] = '\0';
  541. /* ensure NUL termination */
  542. #endif
  543. /* adds NUL padding */
  544. strncpy(bp->d_name, dp->d_name, reclen - DIRENTBASESIZ);
  545. #ifdef UFS
  546. dp->d_name[DIRSIZ] = save;
  547. /* restore original data */
  548. #endif
  549. }
  550. bp = (struct dirent *) ((char *) bp + reclen);
  551. }
  552. }
  553. #ifndef BFS /* 4.2BSD messed up; fixed in 4.3BSD */
  554. if ((char *) dp > &u.dblk[size]) {
  555. errno = EIO; /* corrupted directory */
  556. return -1;
  557. }
  558. #endif
  559. }
  560. errno = serrno; /* restore entry errno */
  561. return (char *) bp - buf; /* return # bytes read */
  562. }