1
0

dirio.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. dirio.c
  9. Abstract:
  10. This module implements directory enumeration functionality.
  11. Author:
  12. Evan Green 11-Mar-2013
  13. Environment:
  14. User Mode C Library
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "libcp.h"
  20. #include <assert.h>
  21. #include <dirent.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/stat.h>
  27. //
  28. // ---------------------------------------------------------------- Definitions
  29. //
  30. #define DIRECTORY_BUFFER_SIZE 4096
  31. //
  32. // Define the initial guess for the current working directory buffer length.
  33. //
  34. #define WORKING_DIRECTORY_BUFFER_SIZE 256
  35. //
  36. // ------------------------------------------------------ Data Type Definitions
  37. //
  38. /*++
  39. Structure Description:
  40. This structure stores information about about an open directory.
  41. Members:
  42. Descriptor - Stores the file descriptor number.
  43. Buffer - Stores a pointer to the buffer used to store several enumeration
  44. entries.
  45. ValidBufferSize - Stores the number of bytes in the buffer that actually
  46. contain valid data.
  47. CurrentPosition - Stores the offset within the buffer where the next entry
  48. will come from.
  49. AtEnd - Stores a boolean indicating if the end of the current buffer
  50. represents the end of the entire directory.
  51. Entry - Stores a pointer to the dirent structure expected at the final
  52. output.
  53. --*/
  54. typedef struct _DIR {
  55. HANDLE Descriptor;
  56. PVOID Buffer;
  57. ULONG ValidBufferSize;
  58. ULONG CurrentPosition;
  59. BOOL AtEnd;
  60. struct dirent Entry;
  61. } *PDIR;
  62. //
  63. // ----------------------------------------------- Internal Function Prototypes
  64. //
  65. PDIR
  66. ClpCreateDirectoryStructure (
  67. VOID
  68. );
  69. KSTATUS
  70. ClpDestroyDirectoryStructure (
  71. PDIR Directory
  72. );
  73. //
  74. // -------------------------------------------------------------------- Globals
  75. //
  76. CHAR ClDirectoryEntryTypeConversions[IoObjectTypeCount] = {
  77. DT_UNKNOWN,
  78. DT_DIR,
  79. DT_REG,
  80. DT_BLK,
  81. DT_CHR,
  82. DT_FIFO,
  83. DT_DIR,
  84. DT_SOCK,
  85. DT_CHR,
  86. DT_CHR,
  87. DT_REG,
  88. DT_LNK
  89. };
  90. //
  91. // ------------------------------------------------------------------ Functions
  92. //
  93. LIBC_API
  94. DIR *
  95. opendir (
  96. const char *DirectoryName
  97. )
  98. /*++
  99. Routine Description:
  100. This routine opens a directory for reading.
  101. Arguments:
  102. DirectoryName - Supplies a pointer to a null terminated string containing
  103. the name of the directory to open.
  104. Return Value:
  105. Returns a pointer to the directory on success.
  106. NULL on failure.
  107. --*/
  108. {
  109. PDIR Directory;
  110. ULONG FilePathLength;
  111. ULONG Flags;
  112. KSTATUS Status;
  113. Directory = ClpCreateDirectoryStructure();
  114. if (Directory == NULL) {
  115. Status = STATUS_INSUFFICIENT_RESOURCES;
  116. goto opendirEnd;
  117. }
  118. FilePathLength = RtlStringLength((PSTR)DirectoryName);
  119. Flags = SYS_OPEN_FLAG_DIRECTORY | SYS_OPEN_FLAG_READ;
  120. Status = OsOpen(INVALID_HANDLE,
  121. (PSTR)DirectoryName,
  122. FilePathLength + 1,
  123. Flags,
  124. FILE_PERMISSION_NONE,
  125. &(Directory->Descriptor));
  126. if (!KSUCCESS(Status)) {
  127. goto opendirEnd;
  128. }
  129. opendirEnd:
  130. if (!KSUCCESS(Status)) {
  131. if (Directory != NULL) {
  132. ClpDestroyDirectoryStructure(Directory);
  133. Directory = NULL;
  134. }
  135. errno = ClConvertKstatusToErrorNumber(Status);
  136. }
  137. return Directory;
  138. }
  139. LIBC_API
  140. DIR *
  141. fdopendir (
  142. int FileDescriptor
  143. )
  144. /*++
  145. Routine Description:
  146. This routine opens a directory based on an already open file descriptor to
  147. a directory.
  148. Arguments:
  149. FileDescriptor - Supplies a pointer to the open handle to the directory.
  150. Return Value:
  151. 0 on success.
  152. -1 on failure, and more details will be provided in errno.
  153. --*/
  154. {
  155. PDIR Directory;
  156. KSTATUS Status;
  157. Directory = ClpCreateDirectoryStructure();
  158. if (Directory == NULL) {
  159. Status = STATUS_INSUFFICIENT_RESOURCES;
  160. goto fdopendirEnd;
  161. }
  162. Status = OsFileControl((HANDLE)(UINTN)FileDescriptor,
  163. FileControlCommandSetDirectoryFlag,
  164. NULL);
  165. if (!KSUCCESS(Status)) {
  166. goto fdopendirEnd;
  167. }
  168. Directory->Descriptor = (HANDLE)(UINTN)FileDescriptor;
  169. Status = STATUS_SUCCESS;
  170. fdopendirEnd:
  171. if (!KSUCCESS(Status)) {
  172. if (Directory != NULL) {
  173. ClpDestroyDirectoryStructure(Directory);
  174. Directory = NULL;
  175. }
  176. errno = ClConvertKstatusToErrorNumber(Status);
  177. }
  178. return Directory;
  179. }
  180. LIBC_API
  181. int
  182. closedir (
  183. DIR *Directory
  184. )
  185. /*++
  186. Routine Description:
  187. This routine closes an open directory.
  188. Arguments:
  189. Directory - Supplies a pointer to the structure returned by the open
  190. directory function.
  191. Return Value:
  192. 0 on success.
  193. -1 on failure, and more details will be provided in errno.
  194. --*/
  195. {
  196. KSTATUS Status;
  197. if (Directory == NULL) {
  198. Status = STATUS_SUCCESS;
  199. goto closedirEnd;
  200. }
  201. Status = ClpDestroyDirectoryStructure(Directory);
  202. closedirEnd:
  203. if (!KSUCCESS(Status)) {
  204. errno = ClConvertKstatusToErrorNumber(Status);
  205. return -1;
  206. }
  207. return 0;
  208. }
  209. LIBC_API
  210. int
  211. readdir_r (
  212. DIR *Directory,
  213. struct dirent *Buffer,
  214. struct dirent **Result
  215. )
  216. /*++
  217. Routine Description:
  218. This routine reads from a directory in a reentrant manner.
  219. Arguments:
  220. Directory - Supplies a pointer to the structure returned by the open
  221. directory function.
  222. Buffer - Supplies the buffer where the next directory entry will be
  223. returned.
  224. Result - Supplies a pointer that will either be set to the Buffer pointer
  225. if there are more entries, or NULL if there are no more entries in the
  226. directory.
  227. Return Value:
  228. 0 on success.
  229. Returns an error number on failure.
  230. --*/
  231. {
  232. UINTN BytesRead;
  233. PDIRECTORY_ENTRY Entry;
  234. INT Error;
  235. UINTN NextEntryOffset;
  236. KSTATUS Status;
  237. *Result = NULL;
  238. if (Directory == NULL) {
  239. Status = STATUS_INVALID_HANDLE;
  240. goto readdir_rEnd;
  241. }
  242. //
  243. // If more data needs to be read, perform the underlying read.
  244. //
  245. if (Directory->CurrentPosition + sizeof(DIRECTORY_ENTRY) >
  246. Directory->ValidBufferSize) {
  247. //
  248. // If this is the end, return a null entry and success.
  249. //
  250. if (Directory->AtEnd != FALSE) {
  251. Status = STATUS_SUCCESS;
  252. goto readdir_rEnd;
  253. }
  254. Status = OsPerformIo(Directory->Descriptor,
  255. IO_OFFSET_NONE,
  256. DIRECTORY_BUFFER_SIZE,
  257. 0,
  258. SYS_WAIT_TIME_INDEFINITE,
  259. Directory->Buffer,
  260. &BytesRead);
  261. if (!KSUCCESS(Status)) {
  262. goto readdir_rEnd;
  263. }
  264. if (BytesRead == 0) {
  265. Directory->AtEnd = TRUE;
  266. goto readdir_rEnd;
  267. }
  268. Directory->ValidBufferSize = (ULONG)BytesRead;
  269. Directory->CurrentPosition = 0;
  270. //
  271. // Make sure there is enough space for a new directory entry.
  272. //
  273. if (Directory->CurrentPosition + sizeof(DIRECTORY_ENTRY) >
  274. Directory->ValidBufferSize) {
  275. Status = STATUS_BUFFER_OVERRUN;
  276. goto readdir_rEnd;
  277. }
  278. }
  279. //
  280. // Grab the next directory entry.
  281. //
  282. Entry = (PDIRECTORY_ENTRY)(Directory->Buffer + Directory->CurrentPosition);
  283. NextEntryOffset = Directory->CurrentPosition + Entry->Size;
  284. if (NextEntryOffset > Directory->ValidBufferSize) {
  285. Status = STATUS_BUFFER_OVERRUN;
  286. goto readdir_rEnd;
  287. }
  288. if (Entry->Size - sizeof(DIRECTORY_ENTRY) > NAME_MAX) {
  289. Status = STATUS_BUFFER_OVERRUN;
  290. goto readdir_rEnd;
  291. }
  292. Buffer->d_ino = Entry->FileId;
  293. Buffer->d_off = Entry->NextOffset;
  294. Buffer->d_reclen = Entry->Size;
  295. //
  296. // Please update the array (and this assert) if a new I/O object type is
  297. // added.
  298. //
  299. assert(IoObjectSymbolicLink + 1 == IoObjectTypeCount);
  300. Buffer->d_type = ClDirectoryEntryTypeConversions[Entry->Type];
  301. RtlStringCopy((PSTR)&(Buffer->d_name), (PSTR)(Entry + 1), NAME_MAX);
  302. assert(strchr(Buffer->d_name, '/') == NULL);
  303. //
  304. // Move on to the next entry.
  305. //
  306. Directory->CurrentPosition = NextEntryOffset;
  307. Status = STATUS_SUCCESS;
  308. *Result = Buffer;
  309. readdir_rEnd:
  310. if (!KSUCCESS(Status)) {
  311. Error = ClConvertKstatusToErrorNumber(Status);
  312. } else {
  313. Error = 0;
  314. }
  315. return Error;
  316. }
  317. LIBC_API
  318. struct dirent *
  319. readdir (
  320. DIR *Directory
  321. )
  322. /*++
  323. Routine Description:
  324. This routine reads the next directory entry from the open directory
  325. stream.
  326. Arguments:
  327. Directory - Supplies a pointer to the structure returned by the open
  328. directory function.
  329. Return Value:
  330. Returns a pointer to the next directory entry on success.
  331. NULL on failure or when the end of the directory is reached. On failure,
  332. errno is set. If the end of the directory is reached, errno is not
  333. changed.
  334. --*/
  335. {
  336. int Error;
  337. struct dirent *NextEntry;
  338. Error = readdir_r(Directory, &(Directory->Entry), &NextEntry);
  339. if (Error != 0) {
  340. errno = Error;
  341. }
  342. return NextEntry;
  343. }
  344. LIBC_API
  345. void
  346. seekdir (
  347. DIR *Directory,
  348. long Location
  349. )
  350. /*++
  351. Routine Description:
  352. This routine seeks directory to the given location. The location must have
  353. been returned from a previous call to telldir, otherwise the results are
  354. undefined.
  355. Arguments:
  356. Directory - Supplies a pointer to the structure returned by the open
  357. directory function.
  358. Location - Supplies the location within the directory to seek to as given
  359. by the telldir function.
  360. Return Value:
  361. None. No errors are defined.
  362. --*/
  363. {
  364. OsSeek(Directory->Descriptor,
  365. SeekCommandFromBeginning,
  366. Location,
  367. NULL);
  368. Directory->ValidBufferSize = 0;
  369. Directory->CurrentPosition = 0;
  370. Directory->AtEnd = FALSE;
  371. return;
  372. }
  373. LIBC_API
  374. long
  375. telldir (
  376. DIR *Directory
  377. )
  378. /*++
  379. Routine Description:
  380. This routine returns the current position within a directory. This position
  381. can be seeked to later (in fact, the return value from this function is the
  382. only valid parameter to pass to seekdir).
  383. Arguments:
  384. Directory - Supplies a pointer to the structure returned by the open
  385. directory function.
  386. Return Value:
  387. Returns the current location of the specified directory stream.
  388. --*/
  389. {
  390. IO_OFFSET Offset;
  391. KSTATUS Status;
  392. Status = OsSeek(Directory->Descriptor,
  393. SeekCommandNop,
  394. 0,
  395. &Offset);
  396. if (!KSUCCESS(Status)) {
  397. return 0;
  398. }
  399. return (long)Offset;
  400. }
  401. LIBC_API
  402. void
  403. rewinddir (
  404. DIR *Directory
  405. )
  406. /*++
  407. Routine Description:
  408. This routine rewinds a directory back to the beginning.
  409. Arguments:
  410. Directory - Supplies a pointer to the structure returned by the open
  411. directory function.
  412. Return Value:
  413. None.
  414. --*/
  415. {
  416. seekdir(Directory, 0);
  417. return;
  418. }
  419. LIBC_API
  420. int
  421. dirfd (
  422. DIR *Directory
  423. )
  424. /*++
  425. Routine Description:
  426. This routine returns the file descriptor backing the given directory.
  427. Arguments:
  428. Directory - Supplies a pointer to the structure returned by the open
  429. directory function.
  430. Return Value:
  431. None.
  432. --*/
  433. {
  434. if ((Directory == NULL) || (Directory->Descriptor == INVALID_HANDLE)) {
  435. errno = EINVAL;
  436. return -1;
  437. }
  438. return (int)(UINTN)(Directory->Descriptor);
  439. }
  440. LIBC_API
  441. int
  442. rmdir (
  443. const char *Path
  444. )
  445. /*++
  446. Routine Description:
  447. This routine attempts to unlink a directory. The directory must be empty or
  448. the operation will fail.
  449. Arguments:
  450. Path - Supplies a pointer to a null terminated string containing the path
  451. of the directory to remove.
  452. Return Value:
  453. 0 on success.
  454. -1 on failure, and errno will be set to provide more details. In failure
  455. cases, the directory will not be removed.
  456. --*/
  457. {
  458. return unlinkat(AT_FDCWD, Path, AT_REMOVEDIR);
  459. }
  460. LIBC_API
  461. char *
  462. getcwd (
  463. char *Buffer,
  464. size_t BufferSize
  465. )
  466. /*++
  467. Routine Description:
  468. This routine returns a pointer to a null terminated string containing the
  469. path to the current working directory.
  470. Arguments:
  471. Buffer - Supplies a pointer to a buffer where the string should be returned.
  472. If NULL is supplied, then malloc will be used to allocate a buffer of
  473. the appropriate size, and it is therefore the caller's responsibility
  474. to free this memory.
  475. BufferSize - Supplies the size of the buffer, in bytes.
  476. Return Value:
  477. Returns a pointer to a string containing the current working directory on
  478. success.
  479. NULL on failure. Errno will contain more information.
  480. --*/
  481. {
  482. PSTR Directory;
  483. UINTN DirectorySize;
  484. KSTATUS Status;
  485. Status = OsGetCurrentDirectory(FALSE, &Directory, &DirectorySize);
  486. if (!KSUCCESS(Status)) {
  487. errno = ClConvertKstatusToErrorNumber(Status);
  488. return NULL;
  489. }
  490. //
  491. // If a buffer was supplied, try to use it.
  492. //
  493. if (Buffer != NULL) {
  494. //
  495. // The size argument is required if a buffer was supplied.
  496. //
  497. if (BufferSize == 0) {
  498. errno = EINVAL;
  499. Buffer = NULL;
  500. //
  501. // If a size was supplied but is too small, notify the caller.
  502. //
  503. } else if (BufferSize < DirectorySize) {
  504. errno = ERANGE;
  505. Buffer = NULL;
  506. //
  507. // Otherwise copy the current directory into the supplied buffer.
  508. //
  509. } else {
  510. memcpy(Buffer, Directory, DirectorySize);
  511. }
  512. //
  513. // If there is no provided buffer, then allocate a buffer of the
  514. // appropriate size and copy the directory into it. Ignore the supplied
  515. // buffer size.
  516. //
  517. } else {
  518. Buffer = malloc(DirectorySize);
  519. if (Buffer != NULL) {
  520. memcpy(Buffer, Directory, DirectorySize);
  521. } else {
  522. errno = ENOMEM;
  523. }
  524. }
  525. //
  526. // Free the allocated directory and return the user's buffer.
  527. //
  528. if (Directory != NULL) {
  529. OsHeapFree(Directory);
  530. Directory = NULL;
  531. }
  532. return Buffer;
  533. }
  534. LIBC_API
  535. int
  536. chdir (
  537. const char *Path
  538. )
  539. /*++
  540. Routine Description:
  541. This routine changes the current working directory (the starting point for
  542. all paths that don't begin with a path separator).
  543. Arguments:
  544. Path - Supplies a pointer to the null terminated string containing the
  545. path of the new working directory.
  546. Return Value:
  547. 0 on success.
  548. -1 on failure, and errno will be set to provide more details. On failure,
  549. the current working directory will not be changed.
  550. --*/
  551. {
  552. ULONG PathSize;
  553. KSTATUS Status;
  554. if (Path == NULL) {
  555. errno = EINVAL;
  556. return -1;
  557. }
  558. PathSize = strlen((PSTR)Path) + 1;
  559. Status = OsChangeDirectory(FALSE, (PSTR)Path, PathSize);
  560. if (!KSUCCESS(Status)) {
  561. errno = ClConvertKstatusToErrorNumber(Status);
  562. return -1;
  563. }
  564. return 0;
  565. }
  566. LIBC_API
  567. int
  568. fchdir (
  569. int FileDescriptor
  570. )
  571. /*++
  572. Routine Description:
  573. This routine changes the current working directory (the starting point for
  574. all paths that don't begin with a path separator) using an already open
  575. file descriptor to that directory.
  576. Arguments:
  577. FileDescriptor - Supplies the open file handle to the directory to change
  578. to.
  579. Return Value:
  580. 0 on success.
  581. -1 on failure, and errno will be set to provide more details. On failure,
  582. the current working directory will not be changed.
  583. --*/
  584. {
  585. KSTATUS Status;
  586. Status = OsChangeDirectoryHandle(FALSE, (HANDLE)(UINTN)FileDescriptor);
  587. if (!KSUCCESS(Status)) {
  588. errno = ClConvertKstatusToErrorNumber(Status);
  589. return -1;
  590. }
  591. return 0;
  592. }
  593. LIBC_API
  594. int
  595. chroot (
  596. const char *Path
  597. )
  598. /*++
  599. Routine Description:
  600. This routine changes the current root directory. The working directory is
  601. not changed. The caller must have sufficient privileges to change root
  602. directories.
  603. Arguments:
  604. Path - Supplies a pointer to the null terminated string containing the
  605. path of the new root directory.
  606. Return Value:
  607. 0 on success.
  608. -1 on failure, and errno will be set to provide more details. On failure,
  609. the current root directory will not be changed. Errno may be set to the
  610. following values, among others:
  611. EACCES if search permission is denied on a component of the path prefix.
  612. EPERM if the caller has insufficient privileges.
  613. --*/
  614. {
  615. ULONG PathSize;
  616. KSTATUS Status;
  617. //
  618. // This is a Minoca extension. If the caller passes NULL, then this routine
  619. // will try to escape the current root. This is only possible if the caller
  620. // has the permission to escape roots.
  621. //
  622. if (Path == NULL) {
  623. Status = OsChangeDirectory(TRUE, NULL, 0);
  624. } else {
  625. PathSize = strlen((PSTR)Path) + 1;
  626. Status = OsChangeDirectory(TRUE, (PSTR)Path, PathSize);
  627. }
  628. if (!KSUCCESS(Status)) {
  629. errno = ClConvertKstatusToErrorNumber(Status);
  630. return -1;
  631. }
  632. return 0;
  633. }
  634. LIBC_API
  635. int
  636. fchroot (
  637. int FileDescriptor
  638. )
  639. /*++
  640. Routine Description:
  641. This routine changes the current root directory using an already open file
  642. descriptor to that directory. The caller must have sufficient privileges
  643. to change root directories.
  644. Arguments:
  645. FileDescriptor - Supplies the open file handle to the directory to change
  646. to.
  647. Return Value:
  648. 0 on success.
  649. -1 on failure, and errno will be set to provide more details. On failure,
  650. the current root directory will not be changed.
  651. --*/
  652. {
  653. KSTATUS Status;
  654. Status = OsChangeDirectoryHandle(TRUE, (HANDLE)(UINTN)FileDescriptor);
  655. if (!KSUCCESS(Status)) {
  656. errno = ClConvertKstatusToErrorNumber(Status);
  657. return -1;
  658. }
  659. return 0;
  660. }
  661. //
  662. // --------------------------------------------------------- Internal Functions
  663. //
  664. PDIR
  665. ClpCreateDirectoryStructure (
  666. VOID
  667. )
  668. /*++
  669. Routine Description:
  670. This routine creates a directory structure.
  671. Arguments:
  672. None.
  673. Return Value:
  674. Returns a pointer to the directory structure on success.
  675. NULL on allocation failure.
  676. --*/
  677. {
  678. PDIR Directory;
  679. KSTATUS Status;
  680. Status = STATUS_INSUFFICIENT_RESOURCES;
  681. Directory = malloc(sizeof(DIR));
  682. if (Directory == NULL) {
  683. Status = STATUS_INSUFFICIENT_RESOURCES;
  684. goto CreateDirectoryStructureEnd;
  685. }
  686. RtlZeroMemory(Directory, sizeof(DIR));
  687. Directory->Descriptor = INVALID_HANDLE;
  688. Directory->Buffer = malloc(DIRECTORY_BUFFER_SIZE + 1);
  689. if (Directory->Buffer == NULL) {
  690. Status = STATUS_INSUFFICIENT_RESOURCES;
  691. goto CreateDirectoryStructureEnd;
  692. }
  693. Status = STATUS_SUCCESS;
  694. CreateDirectoryStructureEnd:
  695. if (!KSUCCESS(Status)) {
  696. if (Directory != NULL) {
  697. ClpDestroyDirectoryStructure(Directory);
  698. Directory = NULL;
  699. }
  700. }
  701. return Directory;
  702. }
  703. KSTATUS
  704. ClpDestroyDirectoryStructure (
  705. PDIR Directory
  706. )
  707. /*++
  708. Routine Description:
  709. This routine destroys a directory structure.
  710. Arguments:
  711. Directory - Supplies a pointer to the directory structure to destroy.
  712. Return Value:
  713. Returns the resulting status code from the close function.
  714. --*/
  715. {
  716. KSTATUS Status;
  717. Status = STATUS_INVALID_HANDLE;
  718. if (Directory->Descriptor != INVALID_HANDLE) {
  719. Status = OsClose(Directory->Descriptor);
  720. }
  721. if (Directory->Buffer != NULL) {
  722. free(Directory->Buffer);
  723. }
  724. free(Directory);
  725. return Status;
  726. }