| /* |
| * 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> |
| |
| #include "ntddk.h" |
| #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) |
| { |
| DWORD dw; |
| |
| /* 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; |
| |
| RtlTimeToSecondsSince1970( &fd->ftCreationTime, &dw ); |
| ft->time_create = dw; |
| RtlTimeToSecondsSince1970( &fd->ftLastAccessTime, &dw ); |
| ft->time_access = dw; |
| RtlTimeToSecondsSince1970( &fd->ftLastWriteTime, &dw ); |
| ft->time_write = dw; |
| 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) |
| { |
| char buffer[3] = "A:"; |
| buffer[0] += newdrive - 1; |
| if (!SetCurrentDirectoryA( buffer )) |
| { |
| __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; |
| |
| if (!drive || drive == CRTDLL__getdrive()) |
| return CRTDLL__getcwd(buf,size); /* current */ |
| else |
| { |
| char dir[_MAX_PATH]; |
| char drivespec[4] = {'A', ':', '\\', 0}; |
| int dir_len; |
| |
| drivespec[0] += drive - 1; |
| 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) |
| { |
| char buffer[MAX_PATH]; |
| if (!GetCurrentDirectoryA( sizeof(buffer), buffer )) return 0; |
| if (buffer[1] != ':') return 0; |
| return toupper(buffer[0]) - 'A' + 1; |
| } |
| |
| |
| /********************************************************************* |
| * _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; |
| } |