summaryrefslogtreecommitdiffstats
path: root/src/port/dirent.c
blob: 10ea4bdd42aa1fb90be2d328c356d1b7c917634f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*-------------------------------------------------------------------------
 *
 * dirent.c
 *	  opendir/readdir/closedir for win32/msvc
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/port/dirent.c
 *
 *-------------------------------------------------------------------------
 */

#ifndef FRONTEND
#include "postgres.h"
#else
#include "postgres_fe.h"
#endif

#include <dirent.h>


struct DIR
{
	char	   *dirname;
	struct dirent ret;			/* Used to return to caller */
	HANDLE		handle;
};

DIR *
opendir(const char *dirname)
{
	DWORD		attr;
	DIR		   *d;

	/* Make sure it is a directory */
	attr = GetFileAttributes(dirname);
	if (attr == INVALID_FILE_ATTRIBUTES)
	{
		errno = ENOENT;
		return NULL;
	}
	if ((attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
	{
		errno = ENOTDIR;
		return NULL;
	}

	d = malloc(sizeof(DIR));
	if (!d)
	{
		errno = ENOMEM;
		return NULL;
	}
	d->dirname = malloc(strlen(dirname) + 4);
	if (!d->dirname)
	{
		errno = ENOMEM;
		free(d);
		return NULL;
	}
	strcpy(d->dirname, dirname);
	if (d->dirname[strlen(d->dirname) - 1] != '/' &&
		d->dirname[strlen(d->dirname) - 1] != '\\')
		strcat(d->dirname, "\\");	/* Append backslash if not already there */
	strcat(d->dirname, "*");	/* Search for entries named anything */
	d->handle = INVALID_HANDLE_VALUE;
	d->ret.d_ino = 0;			/* no inodes on win32 */
	d->ret.d_reclen = 0;		/* not used on win32 */
	d->ret.d_type = DT_UNKNOWN;

	return d;
}

struct dirent *
readdir(DIR *d)
{
	WIN32_FIND_DATA fd;

	if (d->handle == INVALID_HANDLE_VALUE)
	{
		d->handle = FindFirstFile(d->dirname, &fd);
		if (d->handle == INVALID_HANDLE_VALUE)
		{
			/* If there are no files, force errno=0 (unlike mingw) */
			if (GetLastError() == ERROR_FILE_NOT_FOUND)
				errno = 0;
			else
				_dosmaperr(GetLastError());
			return NULL;
		}
	}
	else
	{
		if (!FindNextFile(d->handle, &fd))
		{
			/* If there are no more files, force errno=0 (like mingw) */
			if (GetLastError() == ERROR_NO_MORE_FILES)
				errno = 0;
			else
				_dosmaperr(GetLastError());
			return NULL;
		}
	}
	strcpy(d->ret.d_name, fd.cFileName);	/* Both strings are MAX_PATH long */
	d->ret.d_namlen = strlen(d->ret.d_name);

	/*
	 * For reparse points dwReserved0 field will contain the ReparseTag.  We
	 * check this first, because reparse points are also reported as
	 * directories.
	 */
	if ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 &&
		(fd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT))
		d->ret.d_type = DT_LNK;
	else if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
		d->ret.d_type = DT_DIR;
	else
		d->ret.d_type = DT_REG;

	return &d->ret;
}

int
closedir(DIR *d)
{
	int			ret = 0;

	if (d->handle != INVALID_HANDLE_VALUE)
		ret = !FindClose(d->handle);
	free(d->dirname);
	free(d);

	return ret;
}