summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
Diffstat (limited to 'win32')
-rw-r--r--win32/include/dirent.h43
-rw-r--r--win32/win32.c130
2 files changed, 101 insertions, 72 deletions
diff --git a/win32/include/dirent.h b/win32/include/dirent.h
index d2ef6d54b7..d6eb7ea0d9 100644
--- a/win32/include/dirent.h
+++ b/win32/include/dirent.h
@@ -1,41 +1,44 @@
-// dirent.h
+/* dirent.h */
-// djl
-// Provide UNIX compatibility
+/* djl
+ * Provide UNIX compatibility
+ */
#ifndef _INC_DIRENT
#define _INC_DIRENT
-//
-// NT versions of readdir(), etc
-// From the MSDOS implementation
-//
+/*
+ * NT versions of readdir(), etc
+ * From the MSDOS implementation
+ */
-// Directory entry size
+/* Directory entry size */
#ifdef DIRSIZ
#undef DIRSIZ
#endif
#define DIRSIZ(rp) (sizeof(struct direct))
-// needed to compile directory stuff
+/* needed to compile directory stuff */
#define DIRENT direct
-// structure of a directory entry
+/* structure of a directory entry */
typedef struct direct
{
- long d_ino; // inode number (not used by MS-DOS)
- int d_namlen; // Name length
- char d_name[257]; // file name
+ long d_ino; /* inode number (not used by MS-DOS) */
+ long d_namlen; /* name length */
+ char *d_name; /* file name */
} _DIRECT;
-// structure for dir operations
+/* structure for dir operations */
typedef struct _dir_struc
{
- char *start; // Starting position
- char *curr; // Current position
- long size; // Size of string table
- long nfiles; // number if filenames in table
- struct direct dirstr; // Directory structure to return
+ char *start; /* starting position */
+ char *curr; /* current position */
+ long size; /* allocated size of string table */
+ long nfiles; /* number of filenames in table */
+ struct direct dirstr; /* directory structure to return */
+ void* handle; /* system handle */
+ char *end; /* position after last filename */
} DIR;
#if 0 /* these have moved to win32iop.h */
@@ -47,4 +50,4 @@ void win32_rewinddir(DIR *dirp);
int win32_closedir(DIR *dirp);
#endif
-#endif //_INC_DIRENT
+#endif /* _INC_DIRENT */
diff --git a/win32/win32.c b/win32/win32.c
index a2a6502d7e..71a959ae81 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -672,7 +672,7 @@ DllExport DIR *
win32_opendir(char *filename)
{
dTHXo;
- DIR *p;
+ DIR *dirp;
long len;
long idx;
char scanname[MAX_PATH+3];
@@ -682,7 +682,7 @@ win32_opendir(char *filename)
HANDLE fh;
char buffer[MAX_PATH*2];
WCHAR wbuffer[MAX_PATH];
- char* ptr;
+ char* ptr;
len = strlen(filename);
if (len > MAX_PATH)
@@ -693,9 +693,7 @@ win32_opendir(char *filename)
return NULL;
/* Get us a DIR structure */
- Newz(1303, p, 1, DIR);
- if (p == NULL)
- return NULL;
+ Newz(1303, dirp, 1, DIR);
/* Create the search pattern */
strcpy(scanname, filename);
@@ -719,11 +717,25 @@ win32_opendir(char *filename)
else {
fh = FindFirstFileA(scanname, &aFindData);
}
+ dirp->handle = fh;
if (fh == INVALID_HANDLE_VALUE) {
+ DWORD err = GetLastError();
/* FindFirstFile() fails on empty drives! */
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- return p;
- Safefree( p);
+ switch (err) {
+ case ERROR_FILE_NOT_FOUND:
+ return dirp;
+ case ERROR_NO_MORE_FILES:
+ case ERROR_PATH_NOT_FOUND:
+ errno = ENOENT;
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ errno = ENOMEM;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ Safefree(dirp);
return NULL;
}
@@ -738,39 +750,16 @@ win32_opendir(char *filename)
ptr = aFindData.cFileName;
}
idx = strlen(ptr)+1;
- New(1304, p->start, idx, char);
- if (p->start == NULL)
- Perl_croak_nocontext("opendir: malloc failed!\n");
- strcpy(p->start, ptr);
- p->nfiles++;
-
- /* loop finding all the files that match the wildcard
- * (which should be all of them in this directory!).
- * the variable idx should point one past the null terminator
- * of the previous string found.
- */
- while (USING_WIDE()
- ? FindNextFileW(fh, &wFindData)
- : FindNextFileA(fh, &aFindData)) {
- if (USING_WIDE()) {
- W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
- }
- /* ptr is set above to the correct area */
- len = strlen(ptr);
- /* bump the string table size by enough for the
- * new name and it's null terminator
- */
- Renew(p->start, idx+len+1, char);
- if (p->start == NULL)
- Perl_croak_nocontext("opendir: malloc failed!\n");
- strcpy(&p->start[idx], ptr);
- p->nfiles++;
- idx += len+1;
- }
- FindClose(fh);
- p->size = idx;
- p->curr = p->start;
- return p;
+ if (idx < 256)
+ dirp->size = 128;
+ else
+ dirp->size = idx;
+ New(1304, dirp->start, dirp->size, char);
+ strcpy(dirp->start, ptr);
+ dirp->nfiles++;
+ dirp->end = dirp->curr = dirp->start;
+ dirp->end += idx;
+ return dirp;
}
@@ -780,24 +769,59 @@ win32_opendir(char *filename)
DllExport struct direct *
win32_readdir(DIR *dirp)
{
- int len;
- static int dummy = 0;
+ long len;
if (dirp->curr) {
/* first set up the structure to return */
len = strlen(dirp->curr);
- strcpy(dirp->dirstr.d_name, dirp->curr);
+ dirp->dirstr.d_name = dirp->curr;
dirp->dirstr.d_namlen = len;
/* Fake an inode */
- dirp->dirstr.d_ino = dummy++;
+ dirp->dirstr.d_ino = (long)dirp->curr;
- /* Now set up for the nDllExport call to readdir */
+ /* Now set up for the next call to readdir */
dirp->curr += len + 1;
- if (dirp->curr >= (dirp->start + dirp->size)) {
- dirp->curr = NULL;
+ if (dirp->curr >= dirp->end) {
+ dTHXo;
+ char* ptr;
+ BOOL res;
+ WIN32_FIND_DATAW wFindData;
+ WIN32_FIND_DATAA aFindData;
+ char buffer[MAX_PATH*2];
+
+ /* finding the next file that matches the wildcard
+ * (which should be all of them in this directory!).
+ * the variable idx should point one past the null terminator
+ * of the previous string found.
+ */
+ if (USING_WIDE()) {
+ res = FindNextFileW(dirp->handle, &wFindData);
+ if (res) {
+ W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
+ ptr = buffer;
+ }
+ }
+ else {
+ res = FindNextFileA(dirp->handle, &aFindData);
+ if (res)
+ ptr = aFindData.cFileName;
+ }
+ if (res) {
+ len = strlen(ptr)+1;
+ /* bump the string table size by enough for the
+ * new name and it's null terminator */
+ while (dirp->end + len > dirp->start + dirp->size) {
+ dirp->size *= 2;
+ Renew(dirp->start, dirp->size, char);
+ }
+ strcpy(dirp->end, ptr);
+ dirp->end += idx;
+ dirp->nfiles++;
+ }
+ else
+ dirp->curr = NULL;
}
-
return &(dirp->dirstr);
}
else
@@ -808,17 +832,17 @@ win32_readdir(DIR *dirp)
DllExport long
win32_telldir(DIR *dirp)
{
- return (long) dirp->curr;
+ return (dirp->curr - dirp->start);
}
/* Seekdir moves the string pointer to a previously saved position
- *(Saved by telldir).
+ * (returned by telldir).
*/
DllExport void
win32_seekdir(DIR *dirp, long loc)
{
- dirp->curr = (char *)loc;
+ dirp->curr = dirp->start + loc;
}
/* Rewinddir resets the string pointer to the start */
@@ -833,6 +857,8 @@ DllExport int
win32_closedir(DIR *dirp)
{
dTHXo;
+ if (dirp->handle != INVALID_HANDLE_VALUE)
+ FindClose(p->handle);
Safefree(dirp->start);
Safefree(dirp);
return 1;