/* filefind.c (rsxnt) -- Copyright (c) 1996-1997 Rainer Schnitker */

#include "rsxnt.h"
#include <string.h>

struct lfn_find
{
    unsigned long   lfn_handle;
    unsigned char   lfn_attr;
    unsigned char   magic[3];	    /* = "LFN" */
    char	    shortname[13];
    unsigned char  attr;
    unsigned short time;
    unsigned short date;
    unsigned short size_lo;	    /* split due to alignment problems */
    unsigned short size_hi;
    char name[257];
};

static void convert_dta(struct lfn_find *fp, WIN32_FIND_DATA *dta)
{
    FILETIME ftlocal;

    FileTimeToLocalFileTime(&dta->ftLastWriteTime, &ftlocal);
    FileTimeToDosDateTime(&ftlocal, &(fp->date), &(fp->time));

    fp->attr = dta->dwFileAttributes & 0x7f;
    * (DWORD *) &fp->size_lo = dta->nFileSizeLow;

    memcpy(fp->magic, "LFN", 3);
    lstrcpy(fp->shortname, dta->cAlternateFileName);
    lstrcpy(fp->name, dta->cFileName);
}

int __findfirst (const char *name, int attr, struct _find *fp2)
{
    EMXPROCESS *p = _rsxnt_get_process_ptr();
    struct lfn_find *fp = (struct lfn_find *) fp2;
    HANDLE fh;
    WIN32_FIND_DATA dta;
    char fname[512];

    _rsxnt_truncate_name (fname, name);

    if (p->bConsoleApp)
	OemToChar(fname, fname);

    fh = FindFirstFile((LPSTR) fname, &dta);
    if (fh == INVALID_HANDLE_VALUE)
	return _rsxnt_get_last_errno();

    if (attr == _A_VOLID) {
	TCHAR filesys[20];
	DWORD filelen, flags;

	memset (fp, sizeof(struct _find), 0);
	fp->attr = 40;

	if (GetVolumeInformation(name, (LPTSTR) fp->name, 256,
		NULL, &filelen, &flags, filesys, sizeof(filesys)) == FALSE)
	    return _rsxnt_get_last_errno();
	return 0;
    }
    else
	attr |= (FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|
		 FILE_ATTRIBUTE_READONLY);

    while (dta.dwFileAttributes && (attr & dta.dwFileAttributes) == 0) {
	if (FindNextFile(fh, &dta) == FALSE) {
	    FindClose(fh);
	    return _rsxnt_errno(ENOENT);
	}
    }

    /* only one search : close */
    if (strchr(name, '*') || strchr(name, '?')) {
	fp->lfn_handle = (unsigned long) fh;
	fp->lfn_attr = (unsigned char) attr;
    }
    else
	FindClose(fh);

    convert_dta(fp, &dta);

    if (p->bConsoleApp)
	CharToOem(fp->name, fp->name);

    return 0;
}

int __findnext (struct _find *fp2)
{
    EMXPROCESS *p = _rsxnt_get_process_ptr();
    struct lfn_find *fp = (struct lfn_find *) fp2;
    WIN32_FIND_DATA dta;
    int attr = fp->lfn_attr;

    do {
	if (FindNextFile((HANDLE)fp->lfn_handle, &dta) == FALSE) {
	    FindClose((HANDLE)fp->lfn_handle);
	    return _rsxnt_errno(ENOENT);
	}
    } while (dta.dwFileAttributes && (attr & dta.dwFileAttributes) == 0);

    convert_dta(fp, &dta);

    if (p->bConsoleApp)
	CharToOem(fp->name, fp->name);

    return 0;
}
