1 /*-------------------------------------------------------------------------
2  *
3  * dirent.c
4  *	  opendir/readdir/closedir for win32/msvc
5  *
6  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/port/dirent.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #ifndef FRONTEND
17 #include "postgres.h"
18 #else
19 #include "postgres_fe.h"
20 #endif
21 
22 #include <dirent.h>
23 
24 
25 struct DIR
26 {
27 	char	   *dirname;
28 	struct dirent ret;			/* Used to return to caller */
29 	HANDLE		handle;
30 };
31 
32 DIR *
opendir(const char * dirname)33 opendir(const char *dirname)
34 {
35 	DWORD		attr;
36 	DIR		   *d;
37 
38 	/* Make sure it is a directory */
39 	attr = GetFileAttributes(dirname);
40 	if (attr == INVALID_FILE_ATTRIBUTES)
41 	{
42 		errno = ENOENT;
43 		return NULL;
44 	}
45 	if ((attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
46 	{
47 		errno = ENOTDIR;
48 		return NULL;
49 	}
50 
51 	d = malloc(sizeof(DIR));
52 	if (!d)
53 	{
54 		errno = ENOMEM;
55 		return NULL;
56 	}
57 	d->dirname = malloc(strlen(dirname) + 4);
58 	if (!d->dirname)
59 	{
60 		errno = ENOMEM;
61 		free(d);
62 		return NULL;
63 	}
64 	strcpy(d->dirname, dirname);
65 	if (d->dirname[strlen(d->dirname) - 1] != '/' &&
66 		d->dirname[strlen(d->dirname) - 1] != '\\')
67 		strcat(d->dirname, "\\");	/* Append backslash if not already there */
68 	strcat(d->dirname, "*");	/* Search for entries named anything */
69 	d->handle = INVALID_HANDLE_VALUE;
70 	d->ret.d_ino = 0;			/* no inodes on win32 */
71 	d->ret.d_reclen = 0;		/* not used on win32 */
72 	d->ret.d_type = DT_UNKNOWN;
73 
74 	return d;
75 }
76 
77 struct dirent *
readdir(DIR * d)78 readdir(DIR *d)
79 {
80 	WIN32_FIND_DATA fd;
81 
82 	if (d->handle == INVALID_HANDLE_VALUE)
83 	{
84 		d->handle = FindFirstFile(d->dirname, &fd);
85 		if (d->handle == INVALID_HANDLE_VALUE)
86 		{
87 			/* If there are no files, force errno=0 (unlike mingw) */
88 			if (GetLastError() == ERROR_FILE_NOT_FOUND)
89 				errno = 0;
90 			else
91 				_dosmaperr(GetLastError());
92 			return NULL;
93 		}
94 	}
95 	else
96 	{
97 		if (!FindNextFile(d->handle, &fd))
98 		{
99 			/* If there are no more files, force errno=0 (like mingw) */
100 			if (GetLastError() == ERROR_NO_MORE_FILES)
101 				errno = 0;
102 			else
103 				_dosmaperr(GetLastError());
104 			return NULL;
105 		}
106 	}
107 	strcpy(d->ret.d_name, fd.cFileName);	/* Both strings are MAX_PATH long */
108 	d->ret.d_namlen = strlen(d->ret.d_name);
109 	/* The only identified types are: directory, regular file or symbolic link */
110 	if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
111 		d->ret.d_type = DT_DIR;
112 	/* For reparse points dwReserved0 field will contain the ReparseTag */
113 	else if ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 &&
114 			 (fd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT))
115 		d->ret.d_type = DT_LNK;
116 	else
117 		d->ret.d_type = DT_REG;
118 
119 	return &d->ret;
120 }
121 
122 int
closedir(DIR * d)123 closedir(DIR *d)
124 {
125 	int			ret = 0;
126 
127 	if (d->handle != INVALID_HANDLE_VALUE)
128 		ret = !FindClose(d->handle);
129 	free(d->dirname);
130 	free(d);
131 
132 	return ret;
133 }
134