2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
27 #include "wine/port.h"
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
39 #include "wine/winbase16.h"
40 #include "kernel_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(file);
47 /***********************************************************************
48 * GetProfileInt (KERNEL.57)
50 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
52 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
56 /***********************************************************************
57 * GetProfileString (KERNEL.58)
59 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
60 LPSTR buffer, UINT16 len )
62 return GetPrivateProfileString16( section, entry, def_val,
63 buffer, len, "win.ini" );
67 /***********************************************************************
68 * WriteProfileString (KERNEL.59)
70 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
73 return WritePrivateProfileString16( section, entry, string, "win.ini" );
77 /* get the search path for the current module; helper for OpenFile16 */
78 static char *get_search_path(void)
81 char *ret, *p, module[OFS_MAXPATHNAME];
84 if (GetCurrentTask() && GetModuleFileName16( GetCurrentTask(), module, sizeof(module) ))
86 if (!(p = strrchr( module, '\\' ))) p = module;
90 len = (2 + /* search order: first current dir */
91 GetSystemDirectoryA( NULL, 0 ) + 1 + /* then system dir */
92 GetWindowsDirectoryA( NULL, 0 ) + 1 + /* then windows dir */
93 strlen( module ) + 1 + /* then module path */
94 GetEnvironmentVariableA( "PATH", NULL, 0 ) + 1); /* then look in PATH */
95 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL;
98 GetSystemDirectoryA( p, ret + len - p );
101 GetWindowsDirectoryA( p, ret + len - p );
110 GetEnvironmentVariableA( "PATH", p, ret + len - p );
114 /***********************************************************************
115 * OpenFile (KERNEL.74)
116 * OpenFileEx (KERNEL.360)
118 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
123 WORD filedatetime[2];
124 const char *p, *filename;
126 if (!ofs) return HFILE_ERROR;
128 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",debugstr_a(name),
129 ((mode & 0x3 )==OF_READ)?"OF_READ":
130 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
131 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
132 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
133 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
134 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
135 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
136 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
137 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
138 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
139 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
140 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
141 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
142 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
143 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
144 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
145 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
150 OpenFile( name, ofs, mode );
154 if (mode & OF_CREATE)
156 handle = (HANDLE)OpenFile( name, ofs, mode );
157 if (handle == (HANDLE)HFILE_ERROR) goto error;
161 ofs->cBytes = sizeof(OFSTRUCT);
163 if (mode & OF_REOPEN) name = ofs->szPathName;
165 if (!name) return HFILE_ERROR;
167 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
168 Are there any cases where getting the path here is wrong?
169 Uwe Bonnes 1997 Apr 2 */
170 if (!GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL )) goto error;
172 /* If OF_SEARCH is set, ignore the given path */
175 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
177 /* First try the file name as is */
178 if (GetFileAttributesA( filename ) != INVALID_FILE_ATTRIBUTES) filename = NULL;
181 /* Now remove the path */
182 if (filename[0] && (filename[1] == ':')) filename += 2;
183 if ((p = strrchr( filename, '\\' ))) filename = p + 1;
184 if ((p = strrchr( filename, '/' ))) filename = p + 1;
187 SetLastError( ERROR_FILE_NOT_FOUND );
193 /* Now look for the file */
198 char *path = get_search_path();
200 if (!path) goto error;
201 found = SearchPathA( path, filename, NULL, sizeof(ofs->szPathName),
202 ofs->szPathName, NULL );
203 HeapFree( GetProcessHeap(), 0, path );
204 if (!found) goto error;
207 TRACE("found %s\n", debugstr_a(ofs->szPathName) );
209 if (mode & OF_DELETE)
211 if (!DeleteFileA( ofs->szPathName )) goto error;
212 TRACE("(%s): OF_DELETE return = OK\n", name);
216 handle = (HANDLE)_lopen( ofs->szPathName, mode );
217 if (handle == INVALID_HANDLE_VALUE) goto error;
219 GetFileTime( handle, NULL, NULL, &filetime );
220 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
221 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
223 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
225 CloseHandle( handle );
226 WARN("(%s): OF_VERIFY failed\n", name );
227 /* FIXME: what error here? */
228 SetLastError( ERROR_FILE_NOT_FOUND );
232 ofs->Reserved1 = filedatetime[0];
233 ofs->Reserved2 = filedatetime[1];
236 TRACE("(%s): OK, return = %p\n", name, handle );
237 hFileRet = Win32HandleToDosFileHandle( handle );
238 if (hFileRet == HFILE_ERROR16) goto error;
239 if (mode & OF_EXIST) _lclose16( hFileRet ); /* Return the handle, but close it first */
242 error: /* We get here if there was an error opening the file */
243 ofs->nErrCode = GetLastError();
244 WARN("(%s): return = HFILE_ERROR error= %d\n", name,ofs->nErrCode );
245 return HFILE_ERROR16;
249 /***********************************************************************
250 * _lclose (KERNEL.81)
252 HFILE16 WINAPI _lclose16( HFILE16 hFile )
254 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
256 SetLastError( ERROR_INVALID_HANDLE );
257 return HFILE_ERROR16;
259 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
260 CloseHandle( dos_handles[hFile] );
261 dos_handles[hFile] = 0;
265 /***********************************************************************
266 * _lcreat (KERNEL.83)
268 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
270 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
273 /***********************************************************************
274 * _llseek (KERNEL.84)
277 * Seeking before the start of the file should be allowed for _llseek16,
278 * but cause subsequent I/O operations to fail (cf. interrupt list)
281 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
283 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
287 /***********************************************************************
290 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
292 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
296 /***********************************************************************
297 * _lread16 (KERNEL.82)
299 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
301 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
305 /***********************************************************************
306 * _lwrite (KERNEL.86)
308 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
310 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
313 /***********************************************************************
314 * _hread (KERNEL.349)
316 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
320 TRACE("%d %08x %d\n", hFile, (DWORD)buffer, count );
322 /* Some programs pass a count larger than the allocated buffer */
323 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
324 if (count > maxlen) count = maxlen;
325 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
329 /***********************************************************************
332 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
334 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
338 /***********************************************************************
339 * _hwrite (KERNEL.350)
341 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
343 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
347 /***********************************************************************
348 * GetTempDrive (KERNEL.92)
349 * A closer look at krnl386.exe shows what the SDK doesn't mention:
353 * AH: ':' - yes, some kernel code even does stosw with
357 UINT WINAPI GetTempDrive( BYTE ignored )
362 if (GetTempPathW( 8, buffer )) ret = (BYTE)toupperW(buffer[0]);
364 return MAKELONG( ret | (':' << 8), 1 );
368 /***********************************************************************
369 * GetTempFileName (KERNEL.97)
371 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
374 char temppath[MAX_PATH];
375 char *prefix16 = NULL;
378 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
380 GetCurrentDirectoryA(sizeof(temppath), temppath);
381 drive |= temppath[0];
384 if (drive & TF_FORCEDRIVE)
388 d[0] = drive & ~TF_FORCEDRIVE;
391 if (GetDriveTypeA(d) == DRIVE_NO_ROOT_DIR)
393 drive &= ~TF_FORCEDRIVE;
394 WARN("invalid drive %d specified\n", drive );
398 if (drive & TF_FORCEDRIVE)
399 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
401 GetTempPathA( MAX_PATH, temppath );
405 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
407 strcpy(prefix16 + 1, prefix);
410 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
412 HeapFree(GetProcessHeap(), 0, prefix16);
417 /***********************************************************************
418 * GetPrivateProfileInt (KERNEL.127)
420 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
421 INT16 def_val, LPCSTR filename )
423 /* we used to have some elaborate return value limitation (<= -32768 etc.)
424 * here, but Win98SE doesn't care about this at all, so I deleted it.
425 * AFAIR versions prior to Win9x had these limits, though. */
426 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
430 /***********************************************************************
431 * GetPrivateProfileString (KERNEL.128)
433 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
434 LPCSTR def_val, LPSTR buffer,
435 UINT16 len, LPCSTR filename )
439 if (buffer && len) buffer[0] = 0;
444 /* We have to return the list of keys in the section but without the values
445 * so we need to massage the results of GetPrivateProfileSectionA.
447 UINT ret, oldlen = len, size = min( len, 1024 );
452 if (!(data = HeapAlloc(GetProcessHeap(), 0, size ))) return 0;
453 ret = GetPrivateProfileSectionA( section, data, size, filename );
456 HeapFree( GetProcessHeap(), 0, data );
459 if (ret != size - 2) break;
460 /* overflow, try again */
462 HeapFree( GetProcessHeap(), 0, data );
468 char *p = strchr( src, '=' );
470 if (!p) p = src + strlen(src);
473 memcpy( buffer, src, p - src );
476 len -= (p - src) + 1;
477 src += strlen(src) + 1;
481 memcpy( buffer, src, len );
486 HeapFree( GetProcessHeap(), 0, data );
501 return GetPrivateProfileStringA( section, entry, def_val, buffer, len, filename );
505 /***********************************************************************
506 * WritePrivateProfileString (KERNEL.129)
508 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
509 LPCSTR string, LPCSTR filename )
511 return WritePrivateProfileStringA(section,entry,string,filename);
515 /***********************************************************************
516 * GetWindowsDirectory (KERNEL.134)
518 UINT16 WINAPI GetWindowsDirectory16( LPSTR path, UINT16 count )
520 return GetWindowsDirectoryA( path, count );
524 /***********************************************************************
525 * GetSystemDirectory (KERNEL.135)
527 UINT16 WINAPI GetSystemDirectory16( LPSTR path, UINT16 count )
529 return GetSystemDirectoryA( path, count );
533 /***********************************************************************
534 * GetDriveType (KERNEL.136)
535 * Get the type of a drive in Win16.
538 * The type of the Drive. For a list see GetDriveTypeW from kernel32.
541 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
542 * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
543 * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
544 * do any pseudo-clever changes.
546 UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of drive */
551 root[0] = 'A' + drive;
554 type = GetDriveTypeW( root );
555 if (type == DRIVE_CDROM) type = DRIVE_REMOTE;
556 else if (type == DRIVE_NO_ROOT_DIR) type = DRIVE_UNKNOWN;
561 /***********************************************************************
562 * GetProfileSectionNames (KERNEL.142)
564 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
567 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
571 /***********************************************************************
572 * GetPrivateProfileSectionNames (KERNEL.143)
574 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
577 return GetPrivateProfileSectionNamesA(buffer,size,filename);
581 /***********************************************************************
582 * CreateDirectory (KERNEL.144)
584 BOOL16 WINAPI CreateDirectory16( LPCSTR path, LPVOID dummy )
586 return CreateDirectoryA( path, NULL );
590 /***********************************************************************
591 * RemoveDirectory (KERNEL.145)
593 BOOL16 WINAPI RemoveDirectory16( LPCSTR path )
595 return RemoveDirectoryA( path );
599 /***********************************************************************
600 * DeleteFile (KERNEL.146)
602 BOOL16 WINAPI DeleteFile16( LPCSTR path )
604 return DeleteFileA( path );
608 /***********************************************************************
609 * SetHandleCount (KERNEL.199)
611 UINT16 WINAPI SetHandleCount16( UINT16 count )
613 return SetHandleCount( count );
617 /***********************************************************************
618 * GetShortPathName (KERNEL.274)
620 WORD WINAPI GetShortPathName16( LPCSTR longpath, LPSTR shortpath, WORD len )
622 return GetShortPathNameA( longpath, shortpath, len );
626 /***********************************************************************
627 * WriteOutProfiles (KERNEL.315)
629 void WINAPI WriteOutProfiles16(void)
631 WritePrivateProfileSectionW( NULL, NULL, NULL );
635 /***********************************************************************
636 * WritePrivateProfileStruct (KERNEL.406)
638 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
639 LPVOID buf, UINT16 bufsize, LPCSTR filename)
641 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
645 /***********************************************************************
646 * GetPrivateProfileStruct (KERNEL.407)
648 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
649 LPVOID buf, UINT16 len, LPCSTR filename)
651 return GetPrivateProfileStructA( section, key, buf, len, filename );
655 /***********************************************************************
656 * GetCurrentDirectory (KERNEL.411)
658 UINT16 WINAPI GetCurrentDirectory16( UINT16 buflen, LPSTR buf )
660 return GetCurrentDirectoryA( buflen, buf );
664 /***********************************************************************
665 * SetCurrentDirectory (KERNEL.412)
667 BOOL16 WINAPI SetCurrentDirectory16( LPCSTR dir )
669 char fulldir[MAX_PATH];
671 if (!GetFullPathNameA( dir, MAX_PATH, fulldir, NULL )) return FALSE;
673 if (!SetCurrentDirectoryA( dir )) return FALSE;
675 if (fulldir[0] && fulldir[1] == ':')
677 TDB *pTask = GlobalLock16( GetCurrentTask() );
678 char env_var[4] = "=A:";
680 env_var[1] = fulldir[0];
681 SetEnvironmentVariableA( env_var, fulldir );
683 /* update the directory in the TDB */
686 pTask->curdrive = 0x80 | (fulldir[0] - 'A');
687 GetShortPathNameA( fulldir + 2, pTask->curdir, sizeof(pTask->curdir) );
694 /*************************************************************************
695 * FindFirstFile (KERNEL.413)
697 HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data )
702 if (!(h16 = GlobalAlloc16( GMEM_MOVEABLE, sizeof(handle) ))) return INVALID_HANDLE_VALUE16;
703 ptr = GlobalLock16( h16 );
704 *ptr = handle = FindFirstFileA( path, data );
705 GlobalUnlock16( h16 );
707 if (handle == INVALID_HANDLE_VALUE)
710 h16 = INVALID_HANDLE_VALUE16;
716 /*************************************************************************
717 * FindNextFile (KERNEL.414)
719 BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data )
724 if ((handle == INVALID_HANDLE_VALUE16) || !(ptr = GlobalLock16( handle )))
726 SetLastError( ERROR_INVALID_HANDLE );
729 ret = FindNextFileA( *ptr, data );
730 GlobalUnlock16( handle );
735 /*************************************************************************
736 * FindClose (KERNEL.415)
738 BOOL16 WINAPI FindClose16( HANDLE16 handle )
742 if ((handle == INVALID_HANDLE_VALUE16) || !(ptr = GlobalLock16( handle )))
744 SetLastError( ERROR_INVALID_HANDLE );
748 GlobalUnlock16( handle );
749 GlobalFree16( handle );
754 /***********************************************************************
755 * WritePrivateProfileSection (KERNEL.416)
757 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
758 LPCSTR string, LPCSTR filename )
760 return WritePrivateProfileSectionA( section, string, filename );
764 /***********************************************************************
765 * WriteProfileSection (KERNEL.417)
767 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
769 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
773 /***********************************************************************
774 * GetPrivateProfileSection (KERNEL.418)
776 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
777 UINT16 len, LPCSTR filename )
779 return GetPrivateProfileSectionA( section, buffer, len, filename );
783 /***********************************************************************
784 * GetProfileSection (KERNEL.419)
786 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
788 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
792 /**************************************************************************
793 * GetFileAttributes (KERNEL.420)
795 DWORD WINAPI GetFileAttributes16( LPCSTR name )
797 return GetFileAttributesA( name );
801 /**************************************************************************
802 * SetFileAttributes (KERNEL.421)
804 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
806 return SetFileAttributesA( lpFileName, attributes );
810 /***********************************************************************
811 * GetDiskFreeSpace (KERNEL.422)
813 BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors,
814 LPDWORD sector_bytes, LPDWORD free_clusters,
815 LPDWORD total_clusters )
817 return GetDiskFreeSpaceA( root, cluster_sectors, sector_bytes,
818 free_clusters, total_clusters );
821 /***********************************************************************
822 * FileCDR (KERNEL.130)
824 FARPROC16 WINAPI FileCDR16(FARPROC16 x)
826 FIXME("(%p): stub\n", x);
827 return (FARPROC16)TRUE;