2000-11-08 23:42:53 +01:00
|
|
|
/*
|
|
|
|
* CRTDLL drive/directory functions
|
|
|
|
*
|
|
|
|
* Copyright 1996,1998 Marcus Meissner
|
|
|
|
* Copyright 1996 Jukka Iivonen
|
|
|
|
* Copyright 1997,2000 Uwe Bonnes
|
|
|
|
* Copyright 2000 Jon Griffiths
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Implementation Notes:
|
|
|
|
* MT Safe.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "crtdll.h"
|
|
|
|
#include <errno.h>
|
|
|
|
|
2000-11-16 05:14:19 +01:00
|
|
|
#include "ntddk.h"
|
2000-11-08 23:42:53 +01:00
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
DEFAULT_DEBUG_CHANNEL(crtdll);
|
|
|
|
|
|
|
|
/* INTERNAL: Translate find_t to PWIN32_FIND_DATAA */
|
|
|
|
static void __CRTDLL__fttofd(LPWIN32_FIND_DATAA fd, find_t* ft);
|
|
|
|
static void __CRTDLL__fttofd(LPWIN32_FIND_DATAA fd, find_t* ft)
|
|
|
|
{
|
2000-11-16 05:14:19 +01:00
|
|
|
DWORD dw;
|
2000-11-08 23:42:53 +01:00
|
|
|
|
|
|
|
/* Tested with crtdll.dll Version 2.50.4170 (NT) from win98 SE:
|
|
|
|
* attrib 0x80 (FILE_ATTRIBUTE_NORMAL)is returned as 0.
|
|
|
|
*/
|
|
|
|
if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
|
|
|
|
ft->attrib = 0;
|
|
|
|
else
|
|
|
|
ft->attrib = fd->dwFileAttributes;
|
|
|
|
|
2000-11-16 05:14:19 +01:00
|
|
|
RtlTimeToSecondsSince1970( &fd->ftCreationTime, &dw );
|
|
|
|
ft->time_create = dw;
|
|
|
|
RtlTimeToSecondsSince1970( &fd->ftLastAccessTime, &dw );
|
|
|
|
ft->time_access = dw;
|
|
|
|
RtlTimeToSecondsSince1970( &fd->ftLastWriteTime, &dw );
|
|
|
|
ft->time_write = dw;
|
2000-11-08 23:42:53 +01:00
|
|
|
ft->size = fd->nFileSizeLow;
|
|
|
|
strcpy(ft->name, fd->cFileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _chdir (CRTDLL.51)
|
|
|
|
*
|
|
|
|
* Change the current directory.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* newdir [in] Directory to change to
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Sucess: 0
|
|
|
|
*
|
|
|
|
* Failure: -1
|
|
|
|
*/
|
|
|
|
INT __cdecl CRTDLL__chdir(LPCSTR newdir)
|
|
|
|
{
|
|
|
|
if (!SetCurrentDirectoryA(newdir))
|
|
|
|
{
|
|
|
|
__CRTDLL__set_errno(newdir?GetLastError():0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _chdrive (CRTDLL.52)
|
|
|
|
*
|
|
|
|
* Change the current drive.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* newdrive [in] new drive to change to, A: =1, B: =2, etc
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Sucess: 0
|
|
|
|
*
|
|
|
|
* Failure: 1
|
|
|
|
*/
|
|
|
|
BOOL __cdecl CRTDLL__chdrive(INT newdrive)
|
|
|
|
{
|
2000-11-16 05:14:19 +01:00
|
|
|
char buffer[3] = "A:";
|
|
|
|
buffer[0] += newdrive - 1;
|
|
|
|
if (!SetCurrentDirectoryA( buffer ))
|
2000-11-08 23:42:53 +01:00
|
|
|
{
|
|
|
|
__CRTDLL__set_errno(GetLastError());
|
|
|
|
if (newdrive <= 0)
|
|
|
|
CRTDLL_errno = EACCES;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _findclose (CRTDLL.098)
|
|
|
|
*
|
|
|
|
* Free the resources from a search handle created from _findfirst.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* hand [in]: Search handle to close
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: 0
|
|
|
|
*
|
|
|
|
* Failure: -1
|
|
|
|
*/
|
|
|
|
INT __cdecl CRTDLL__findclose(DWORD hand)
|
|
|
|
{
|
|
|
|
TRACE(":handle %ld\n",hand);
|
|
|
|
if (!FindClose((HANDLE)hand))
|
|
|
|
{
|
|
|
|
__CRTDLL__set_errno(GetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _findfirst (CRTDLL.099)
|
|
|
|
*
|
|
|
|
* Create and return a search handle for iterating through a file and
|
|
|
|
* directory list.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* fspec [in] File specification string for search, e.g "C:\*.BAT"
|
|
|
|
*
|
|
|
|
* ft [out] A pointer to a find_t structure to populate.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: A handle for the search, suitable for passing to _findnext
|
|
|
|
* or _findclose. Populates the members of ft with the details
|
|
|
|
* of the first matching file.
|
|
|
|
*
|
|
|
|
* Failure: -1.
|
|
|
|
*/
|
|
|
|
DWORD __cdecl CRTDLL__findfirst(LPCSTR fspec, find_t* ft)
|
|
|
|
{
|
|
|
|
WIN32_FIND_DATAA find_data;
|
|
|
|
HANDLE hfind;
|
|
|
|
|
|
|
|
hfind = FindFirstFileA(fspec, &find_data);
|
|
|
|
if (hfind == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
__CRTDLL__set_errno(GetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
__CRTDLL__fttofd(&find_data,ft);
|
|
|
|
TRACE(":got handle %d\n",hfind);
|
|
|
|
return hfind;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _findnext (CRTDLL.100)
|
|
|
|
*
|
|
|
|
* Return the next matching file/directory from a search hadle.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* hand [in] Search handle from a pervious call to _findfirst
|
|
|
|
*
|
|
|
|
* ft [out] A pointer to a find_t structure to populate.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: 0. Populates the members of ft with the details
|
|
|
|
* of the first matching file
|
|
|
|
*
|
|
|
|
* Failure: -1
|
|
|
|
*/
|
|
|
|
INT __cdecl CRTDLL__findnext(DWORD hand, find_t * ft)
|
|
|
|
{
|
|
|
|
WIN32_FIND_DATAA find_data;
|
|
|
|
|
|
|
|
if (!FindNextFileA(hand, &find_data))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_DRIVE);
|
|
|
|
__CRTDLL__set_errno(GetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
__CRTDLL__fttofd(&find_data,ft);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _getcwd (CRTDLL.120)
|
|
|
|
*
|
|
|
|
* Get the current directory.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* buf [out] A buffer to place the current directory name in
|
|
|
|
*
|
|
|
|
* size [in] The size of buf.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: buf, or if buf is NULL, an allocated buffer
|
|
|
|
*
|
|
|
|
* Failure: NULL
|
|
|
|
*/
|
|
|
|
CHAR* __cdecl CRTDLL__getcwd(LPSTR buf, INT size)
|
|
|
|
{
|
|
|
|
char dir[_MAX_PATH];
|
|
|
|
int dir_len = GetCurrentDirectoryA(_MAX_PATH,dir);
|
|
|
|
|
|
|
|
if (dir_len < 1)
|
|
|
|
return NULL; /* FIXME: Real return value untested */
|
|
|
|
|
|
|
|
if (!buf)
|
|
|
|
{
|
|
|
|
if (size < 0)
|
|
|
|
return CRTDLL__strdup(dir);
|
|
|
|
return __CRTDLL__strndup(dir,size);
|
|
|
|
}
|
|
|
|
if (dir_len >= size)
|
|
|
|
{
|
|
|
|
CRTDLL_errno = ERANGE;
|
|
|
|
return NULL; /* buf too small */
|
|
|
|
}
|
|
|
|
strcpy(buf,dir);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _getdcwd (CRTDLL.121)
|
|
|
|
*
|
|
|
|
* Get the current directory on a drive. A: =1, B: =2, etc.
|
|
|
|
* Passing drive 0 means the current drive.
|
|
|
|
*/
|
|
|
|
CHAR* __cdecl CRTDLL__getdcwd(INT drive,LPSTR buf, INT size)
|
|
|
|
{
|
|
|
|
static CHAR* dummy;
|
|
|
|
|
2000-11-16 05:14:19 +01:00
|
|
|
if (!drive || drive == CRTDLL__getdrive())
|
2000-11-08 23:42:53 +01:00
|
|
|
return CRTDLL__getcwd(buf,size); /* current */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char dir[_MAX_PATH];
|
|
|
|
char drivespec[4] = {'A', ':', '\\', 0};
|
|
|
|
int dir_len;
|
|
|
|
|
2000-11-16 05:14:19 +01:00
|
|
|
drivespec[0] += drive - 1;
|
2000-11-08 23:42:53 +01:00
|
|
|
if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
|
|
|
|
{
|
|
|
|
CRTDLL_errno = EACCES;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
dir_len = GetFullPathNameA(drivespec,_MAX_PATH,dir,&dummy);
|
|
|
|
if (dir_len >= size || dir_len < 1)
|
|
|
|
{
|
|
|
|
CRTDLL_errno = ERANGE;
|
|
|
|
return NULL; /* buf too small */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!buf)
|
|
|
|
return CRTDLL__strdup(dir); /* allocate */
|
|
|
|
|
|
|
|
strcpy(buf,dir);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _getdiskfree (CRTDLL.122)
|
|
|
|
*
|
|
|
|
* Get free disk space on given drive or the current drive.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
UINT __cdecl CRTDLL__getdiskfree(UINT disk, diskfree_t* d)
|
|
|
|
{
|
|
|
|
char drivespec[4] = {'@', ':', '\\', 0};
|
|
|
|
DWORD ret[4];
|
|
|
|
UINT err;
|
|
|
|
|
|
|
|
if (disk > 26)
|
|
|
|
return ERROR_INVALID_PARAMETER; /* CRTDLL doesn't set errno here */
|
|
|
|
|
|
|
|
drivespec[0] += disk; /* make a drive letter */
|
|
|
|
|
|
|
|
if (GetDiskFreeSpaceA(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
|
|
|
|
{
|
|
|
|
d->cluster_sectors = (unsigned)ret[0];
|
|
|
|
d->sector_bytes = (unsigned)ret[1];
|
|
|
|
d->available = (unsigned)ret[2];
|
|
|
|
d->num_clusters = (unsigned)ret[3];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
err = GetLastError();
|
|
|
|
__CRTDLL__set_errno(err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _getdrive (CRTDLL.124)
|
|
|
|
*
|
|
|
|
* Return current drive, A: =1, B: =2, etc
|
|
|
|
*/
|
|
|
|
INT __cdecl CRTDLL__getdrive(VOID)
|
|
|
|
{
|
2000-11-16 05:14:19 +01:00
|
|
|
char buffer[MAX_PATH];
|
|
|
|
if (!GetCurrentDirectoryA( sizeof(buffer), buffer )) return 0;
|
|
|
|
if (buffer[1] != ':') return 0;
|
|
|
|
return toupper(buffer[0]) - 'A' + 1;
|
2000-11-08 23:42:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _mkdir (CRTDLL.234)
|
|
|
|
*
|
|
|
|
* Create a directory.
|
|
|
|
*/
|
|
|
|
INT __cdecl CRTDLL__mkdir(LPCSTR newdir)
|
|
|
|
{
|
|
|
|
if (CreateDirectoryA(newdir,NULL))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
__CRTDLL__set_errno(GetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* _rmdir (CRTDLL.255)
|
|
|
|
*
|
|
|
|
* Delete a directory
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
INT __cdecl CRTDLL__rmdir(LPSTR dir)
|
|
|
|
{
|
|
|
|
if (RemoveDirectoryA(dir))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
__CRTDLL__set_errno(GetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|