Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
blob: 77b90e7e3026da5af69e3e589fef78868e0d1153 (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
/*-------------------------------------------------------------------------
 *
 * dirent.c
 *	  opendir/readdir/closedir for win32/msvc
 *
 * Portions Copyright (c) 1996-2021, 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);
	/* The only identified types are: directory, regular file or symbolic link */
	if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
		d->ret.d_type = DT_DIR;
	/* For reparse points dwReserved0 field will contain the ReparseTag */
	else if ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 &&
			 (fd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT))
		d->ret.d_type = DT_LNK;
	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;
}