Merge branch 'sk/mingw-dirent'
* sk/mingw-dirent: Win32 dirent: improve dirent implementation Win32 dirent: clarify #include directives Win32 dirent: change FILENAME_MAX to MAX_PATH Win32 dirent: remove unused dirent.d_reclen member Win32 dirent: remove unused dirent.d_ino member
This commit is contained in:
		| @ -1,96 +1,91 @@ | ||||
| #include "../git-compat-util.h" | ||||
| #include "dirent.h" | ||||
| #include "../../git-compat-util.h" | ||||
|  | ||||
| struct DIR { | ||||
| 	struct dirent dd_dir; /* includes d_type */ | ||||
| 	HANDLE dd_handle;     /* FindFirstFile handle */ | ||||
| 	int dd_stat;          /* 0-based index */ | ||||
| 	char dd_name[1];      /* extend struct */ | ||||
| }; | ||||
|  | ||||
| static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) | ||||
| { | ||||
| 	/* copy file name from WIN32_FIND_DATA to dirent */ | ||||
| 	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name)); | ||||
|  | ||||
| 	/* Set file type, based on WIN32_FIND_DATA */ | ||||
| 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | ||||
| 		ent->d_type = DT_DIR; | ||||
| 	else | ||||
| 		ent->d_type = DT_REG; | ||||
| } | ||||
|  | ||||
| DIR *opendir(const char *name) | ||||
| { | ||||
| 	DWORD attrs = GetFileAttributesA(name); | ||||
| 	char pattern[MAX_PATH]; | ||||
| 	WIN32_FIND_DATAA fdata; | ||||
| 	HANDLE h; | ||||
| 	int len; | ||||
| 	DIR *p; | ||||
| 	DIR *dir; | ||||
|  | ||||
| 	/* check for valid path */ | ||||
| 	if (attrs == INVALID_FILE_ATTRIBUTES) { | ||||
| 		errno = ENOENT; | ||||
| 	/* check that name is not NULL */ | ||||
| 	if (!name) { | ||||
| 		errno = EINVAL; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* check if it's a directory */ | ||||
| 	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) { | ||||
| 		errno = ENOTDIR; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* check that the pattern won't be too long for FindFirstFileA */ | ||||
| 	len = strlen(name); | ||||
| 	if (is_dir_sep(name[len - 1])) | ||||
| 		len--; | ||||
| 	if (len + 2 >= MAX_PATH) { | ||||
| 		errno = ENAMETOOLONG; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	/* copy name to temp buffer */ | ||||
| 	memcpy(pattern, name, len + 1); | ||||
|  | ||||
| 	p = malloc(sizeof(DIR) + len + 2); | ||||
| 	if (!p) | ||||
| 	/* append optional '/' and wildcard '*' */ | ||||
| 	if (len && !is_dir_sep(pattern[len - 1])) | ||||
| 		pattern[len++] = '/'; | ||||
| 	pattern[len++] = '*'; | ||||
| 	pattern[len] = 0; | ||||
|  | ||||
| 	/* open find handle */ | ||||
| 	h = FindFirstFileA(pattern, &fdata); | ||||
| 	if (h == INVALID_HANDLE_VALUE) { | ||||
| 		DWORD err = GetLastError(); | ||||
| 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	memset(p, 0, sizeof(DIR) + len + 2); | ||||
| 	strcpy(p->dd_name, name); | ||||
| 	p->dd_name[len] = '/'; | ||||
| 	p->dd_name[len+1] = '*'; | ||||
|  | ||||
| 	p->dd_handle = INVALID_HANDLE_VALUE; | ||||
| 	return p; | ||||
| 	/* initialize DIR structure and copy first dir entry */ | ||||
| 	dir = xmalloc(sizeof(DIR)); | ||||
| 	dir->dd_handle = h; | ||||
| 	dir->dd_stat = 0; | ||||
| 	finddata2dirent(&dir->dd_dir, &fdata); | ||||
| 	return dir; | ||||
| } | ||||
|  | ||||
| struct dirent *readdir(DIR *dir) | ||||
| { | ||||
| 	WIN32_FIND_DATAA buf; | ||||
| 	HANDLE handle; | ||||
|  | ||||
| 	if (!dir || !dir->dd_handle) { | ||||
| 	if (!dir) { | ||||
| 		errno = EBADF; /* No set_errno for mingw */ | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) { | ||||
| 		DWORD lasterr; | ||||
| 		handle = FindFirstFileA(dir->dd_name, &buf); | ||||
| 		lasterr = GetLastError(); | ||||
| 		dir->dd_handle = handle; | ||||
| 		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { | ||||
| 			errno = err_win_to_posix(lasterr); | ||||
| 	/* if first entry, dirent has already been set up by opendir */ | ||||
| 	if (dir->dd_stat) { | ||||
| 		/* get next entry and convert from WIN32_FIND_DATA to dirent */ | ||||
| 		WIN32_FIND_DATAA fdata; | ||||
| 		if (FindNextFileA(dir->dd_handle, &fdata)) { | ||||
| 			finddata2dirent(&dir->dd_dir, &fdata); | ||||
| 		} else { | ||||
| 			DWORD lasterr = GetLastError(); | ||||
| 			/* POSIX says you shouldn't set errno when readdir can't | ||||
| 			   find any more files; so, if another error we leave it set. */ | ||||
| 			if (lasterr != ERROR_NO_MORE_FILES) | ||||
| 				errno = err_win_to_posix(lasterr); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) { | ||||
| 		return NULL; | ||||
| 	} else if (!FindNextFileA(dir->dd_handle, &buf)) { | ||||
| 		DWORD lasterr = GetLastError(); | ||||
| 		FindClose(dir->dd_handle); | ||||
| 		dir->dd_handle = INVALID_HANDLE_VALUE; | ||||
| 		/* POSIX says you shouldn't set errno when readdir can't | ||||
| 		   find any more files; so, if another error we leave it set. */ | ||||
| 		if (lasterr != ERROR_NO_MORE_FILES) | ||||
| 			errno = err_win_to_posix(lasterr); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* We get here if `buf' contains valid data.  */ | ||||
| 	strcpy(dir->dd_dir.d_name, buf.cFileName); | ||||
| 	++dir->dd_stat; | ||||
|  | ||||
| 	/* Set file type, based on WIN32_FIND_DATA */ | ||||
| 	dir->dd_dir.d_type = 0; | ||||
| 	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | ||||
| 		dir->dd_dir.d_type |= DT_DIR; | ||||
| 	else | ||||
| 		dir->dd_dir.d_type |= DT_REG; | ||||
|  | ||||
| 	return &dir->dd_dir; | ||||
| } | ||||
|  | ||||
| @ -101,8 +96,7 @@ int closedir(DIR *dir) | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (dir->dd_handle != INVALID_HANDLE_VALUE) | ||||
| 		FindClose(dir->dd_handle); | ||||
| 	FindClose(dir->dd_handle); | ||||
| 	free(dir); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -9,12 +9,8 @@ typedef struct DIR DIR; | ||||
| #define DT_LNK     3 | ||||
|  | ||||
| struct dirent { | ||||
| 	long d_ino;                      /* Always zero. */ | ||||
| 	char d_name[FILENAME_MAX];       /* File name. */ | ||||
| 	union { | ||||
| 		unsigned short d_reclen; /* Always zero. */ | ||||
| 		unsigned char  d_type;   /* Reimplementation adds this */ | ||||
| 	}; | ||||
| 	unsigned char d_type;      /* file type to prevent lstat after readdir */ | ||||
| 	char d_name[MAX_PATH];     /* file name */ | ||||
| }; | ||||
|  | ||||
| DIR *opendir(const char *dirname); | ||||
|  | ||||
| @ -354,6 +354,7 @@ ifeq ($(uname_S),Windows) | ||||
| 	NO_POSIX_GOODIES = UnfortunatelyYes | ||||
| 	NATIVE_CRLF = YesPlease | ||||
| 	DEFAULT_HELP_FORMAT = html | ||||
| 	NO_D_INO_IN_DIRENT = YesPlease | ||||
|  | ||||
| 	CC = compat/vcbuild/scripts/clink.pl | ||||
| 	AR = compat/vcbuild/scripts/lib.pl | ||||
| @ -503,6 +504,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) | ||||
| 	NO_INET_NTOP = YesPlease | ||||
| 	NO_POSIX_GOODIES = UnfortunatelyYes | ||||
| 	DEFAULT_HELP_FORMAT = html | ||||
| 	NO_D_INO_IN_DIRENT = YesPlease | ||||
| 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -D_USE_32BIT_TIME_T -DNOGDI -Icompat -Icompat/win32 | ||||
| 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" | ||||
| 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Junio C Hamano
					Junio C Hamano