Split OpenFile implementation in separate 16- and 32-bit versions, and
[wine/multimedia.git] / dlls / kernel / file16.c
blob3baf1922477eed77665e421ec276c68ccdc72fa9
1 /*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <assert.h>
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "winerror.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "winternl.h"
40 #include "wine/winbase16.h"
41 #include "wine/server.h"
42 #include "kernel_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(file);
49 /***********************************************************************
50 * GetProfileInt (KERNEL.57)
52 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
54 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
58 /***********************************************************************
59 * GetProfileString (KERNEL.58)
61 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
62 LPSTR buffer, UINT16 len )
64 return GetPrivateProfileString16( section, entry, def_val,
65 buffer, len, "win.ini" );
69 /***********************************************************************
70 * WriteProfileString (KERNEL.59)
72 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
73 LPCSTR string )
75 return WritePrivateProfileString16( section, entry, string, "win.ini" );
79 /* get the search path for the current module; helper for OpenFile16 */
80 static char *get_search_path(void)
82 UINT len;
83 char *ret, *p, module[OFS_MAXPATHNAME];
85 module[0] = 0;
86 if (GetCurrentTask() && GetModuleFileName16( GetCurrentTask(), module, sizeof(module) ))
88 if (!(p = strrchr( module, '\\' ))) p = module;
89 *p = 0;
92 len = (2 + /* search order: first current dir */
93 GetSystemDirectoryA( NULL, 0 ) + 1 + /* then system dir */
94 GetWindowsDirectoryA( NULL, 0 ) + 1 + /* then windows dir */
95 strlen( module ) + 1 + /* then module path */
96 GetEnvironmentVariableA( "PATH", NULL, 0 ) + 1); /* then look in PATH */
97 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL;
98 strcpy( ret, ".;" );
99 p = ret + 2;
100 GetSystemDirectoryA( p, ret + len - p );
101 p += strlen( p );
102 *p++ = ';';
103 GetWindowsDirectoryA( p, ret + len - p );
104 p += strlen( p );
105 *p++ = ';';
106 if (module[0])
108 strcpy( p, module );
109 p += strlen( p );
110 *p++ = ';';
112 GetEnvironmentVariableA( "PATH", p, ret + len - p );
113 return ret;
116 /***********************************************************************
117 * OpenFile (KERNEL.74)
118 * OpenFileEx (KERNEL.360)
120 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
122 HFILE hFileRet;
123 HANDLE handle;
124 FILETIME filetime;
125 WORD filedatetime[2];
126 char *p, *filename;
128 if (!ofs) return HFILE_ERROR;
130 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",debugstr_a(name),
131 ((mode & 0x3 )==OF_READ)?"OF_READ":
132 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
133 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
134 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
135 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
136 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
137 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
138 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
139 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
140 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
141 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
142 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
143 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
144 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
145 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
146 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
147 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
150 ofs->cBytes = sizeof(OFSTRUCT);
151 ofs->nErrCode = 0;
152 if (mode & OF_REOPEN) name = ofs->szPathName;
154 if (!name) return HFILE_ERROR;
156 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
157 Are there any cases where getting the path here is wrong?
158 Uwe Bonnes 1997 Apr 2 */
159 if (!GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL )) goto error;
161 /* OF_PARSE simply fills the structure */
163 if (mode & OF_PARSE)
165 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' ) != DRIVE_REMOVABLE);
166 TRACE("(%s): OF_PARSE, res = '%s'\n", name, ofs->szPathName );
167 return 0;
170 /* OF_CREATE is completely different from all other options, so
171 handle it first */
173 if (mode & OF_CREATE)
175 DWORD access, sharing;
176 FILE_ConvertOFMode( mode, &access, &sharing );
177 if ((handle = CreateFileA( ofs->szPathName, GENERIC_READ | GENERIC_WRITE,
178 sharing, NULL, CREATE_ALWAYS,
179 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
180 goto error;
182 else
184 /* If OF_SEARCH is set, ignore the given path */
186 filename = ofs->szPathName;
187 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
189 /* First try the file name as is */
190 if (GetFileAttributesA( filename ) != INVALID_FILE_ATTRIBUTES) filename = NULL;
191 else
193 /* Now remove the path */
194 if (filename[0] && (filename[1] == ':')) filename += 2;
195 if ((p = strrchr( filename, '\\' ))) filename = p + 1;
196 if ((p = strrchr( filename, '/' ))) filename = p + 1;
197 if (!filename[0])
199 SetLastError( ERROR_FILE_NOT_FOUND );
200 goto error;
205 /* Now look for the file */
207 if (filename)
209 BOOL found;
210 char *path = get_search_path();
212 if (!path) goto error;
213 found = SearchPathA( path, filename, NULL, sizeof(ofs->szPathName),
214 ofs->szPathName, NULL );
215 HeapFree( GetProcessHeap(), 0, path );
216 if (!found) goto error;
219 TRACE("found %s\n", debugstr_a(ofs->szPathName) );
221 if (mode & OF_DELETE)
223 if (!DeleteFileA( ofs->szPathName )) goto error;
224 TRACE("(%s): OF_DELETE return = OK\n", name);
225 return 1;
228 handle = (HANDLE)_lopen( ofs->szPathName, mode );
229 if (handle == INVALID_HANDLE_VALUE) goto error;
231 GetFileTime( handle, NULL, NULL, &filetime );
232 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
233 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
235 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
237 CloseHandle( handle );
238 WARN("(%s): OF_VERIFY failed\n", name );
239 /* FIXME: what error here? */
240 SetLastError( ERROR_FILE_NOT_FOUND );
241 goto error;
244 ofs->Reserved1 = filedatetime[0];
245 ofs->Reserved2 = filedatetime[1];
248 TRACE("(%s): OK, return = %p\n", name, handle );
249 hFileRet = Win32HandleToDosFileHandle( handle );
250 if (hFileRet == HFILE_ERROR16) goto error;
251 if (mode & OF_EXIST) _lclose16( hFileRet ); /* Return the handle, but close it first */
252 return hFileRet;
254 error: /* We get here if there was an error opening the file */
255 ofs->nErrCode = GetLastError();
256 WARN("(%s): return = HFILE_ERROR error= %d\n", name,ofs->nErrCode );
257 return HFILE_ERROR16;
261 /***********************************************************************
262 * _lclose (KERNEL.81)
264 HFILE16 WINAPI _lclose16( HFILE16 hFile )
266 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
268 SetLastError( ERROR_INVALID_HANDLE );
269 return HFILE_ERROR16;
271 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
272 CloseHandle( dos_handles[hFile] );
273 dos_handles[hFile] = 0;
274 return 0;
277 /***********************************************************************
278 * _lcreat (KERNEL.83)
280 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
282 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
285 /***********************************************************************
286 * _llseek (KERNEL.84)
288 * FIXME:
289 * Seeking before the start of the file should be allowed for _llseek16,
290 * but cause subsequent I/O operations to fail (cf. interrupt list)
293 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
295 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
299 /***********************************************************************
300 * _lopen (KERNEL.85)
302 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
304 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
308 /***********************************************************************
309 * _lread16 (KERNEL.82)
311 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
313 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
317 /***********************************************************************
318 * _lwrite (KERNEL.86)
320 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
322 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
325 /***********************************************************************
326 * _hread (KERNEL.349)
328 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
330 LONG maxlen;
332 TRACE("%d %08lx %ld\n", hFile, (DWORD)buffer, count );
334 /* Some programs pass a count larger than the allocated buffer */
335 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
336 if (count > maxlen) count = maxlen;
337 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
341 /***********************************************************************
342 * _lread (KERNEL.82)
344 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
346 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
350 /***********************************************************************
351 * GetTempFileName (KERNEL.97)
353 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
354 LPSTR buffer )
356 char temppath[MAX_PATH];
357 char *prefix16 = NULL;
358 UINT16 ret;
360 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
362 GetCurrentDirectoryA(sizeof(temppath), temppath);
363 drive |= temppath[0];
366 if (drive & TF_FORCEDRIVE)
368 char d[3];
370 d[0] = drive & ~TF_FORCEDRIVE;
371 d[1] = ':';
372 d[2] = '\0';
373 if (GetDriveTypeA(d) == DRIVE_NO_ROOT_DIR)
375 drive &= ~TF_FORCEDRIVE;
376 WARN("invalid drive %d specified\n", drive );
380 if (drive & TF_FORCEDRIVE)
381 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
382 else
383 GetTempPathA( MAX_PATH, temppath );
385 if (prefix)
387 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
388 *prefix16 = '~';
389 strcpy(prefix16 + 1, prefix);
392 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
394 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
395 return ret;
399 /***********************************************************************
400 * GetPrivateProfileInt (KERNEL.127)
402 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
403 INT16 def_val, LPCSTR filename )
405 /* we used to have some elaborate return value limitation (<= -32768 etc.)
406 * here, but Win98SE doesn't care about this at all, so I deleted it.
407 * AFAIR versions prior to Win9x had these limits, though. */
408 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
412 /***********************************************************************
413 * WritePrivateProfileString (KERNEL.129)
415 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
416 LPCSTR string, LPCSTR filename )
418 return WritePrivateProfileStringA(section,entry,string,filename);
422 /***********************************************************************
423 * GetWindowsDirectory (KERNEL.134)
425 UINT16 WINAPI GetWindowsDirectory16( LPSTR path, UINT16 count )
427 return GetWindowsDirectoryA( path, count );
431 /***********************************************************************
432 * GetSystemDirectory (KERNEL.135)
434 UINT16 WINAPI GetSystemDirectory16( LPSTR path, UINT16 count )
436 return GetSystemDirectoryA( path, count );
440 /***********************************************************************
441 * GetDriveType (KERNEL.136)
442 * This function returns the type of a drive in Win16.
443 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
444 * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
445 * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
446 * do any pseudo-clever changes.
448 UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of drive */
450 UINT type;
451 WCHAR root[3];
453 root[0] = 'A' + drive;
454 root[1] = ':';
455 root[2] = 0;
456 type = GetDriveTypeW( root );
457 if (type == DRIVE_CDROM) type = DRIVE_REMOTE;
458 return type;
462 /***********************************************************************
463 * GetProfileSectionNames (KERNEL.142)
465 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
468 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
472 /***********************************************************************
473 * GetPrivateProfileSectionNames (KERNEL.143)
475 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
476 LPCSTR filename )
478 return GetPrivateProfileSectionNamesA(buffer,size,filename);
482 /***********************************************************************
483 * CreateDirectory (KERNEL.144)
485 BOOL16 WINAPI CreateDirectory16( LPCSTR path, LPVOID dummy )
487 return CreateDirectoryA( path, NULL );
491 /***********************************************************************
492 * RemoveDirectory (KERNEL.145)
494 BOOL16 WINAPI RemoveDirectory16( LPCSTR path )
496 return RemoveDirectoryA( path );
500 /***********************************************************************
501 * DeleteFile (KERNEL.146)
503 BOOL16 WINAPI DeleteFile16( LPCSTR path )
505 return DeleteFileA( path );
509 /***********************************************************************
510 * SetHandleCount (KERNEL.199)
512 UINT16 WINAPI SetHandleCount16( UINT16 count )
514 return SetHandleCount( count );
518 /***********************************************************************
519 * _hread16 (KERNEL.349)
521 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
523 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
527 /***********************************************************************
528 * _hwrite (KERNEL.350)
530 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
532 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
536 /***********************************************************************
537 * WritePrivateProfileStruct (KERNEL.406)
539 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
540 LPVOID buf, UINT16 bufsize, LPCSTR filename)
542 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
546 /***********************************************************************
547 * GetPrivateProfileStruct (KERNEL.407)
549 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
550 LPVOID buf, UINT16 len, LPCSTR filename)
552 return GetPrivateProfileStructA( section, key, buf, len, filename );
556 /***********************************************************************
557 * SetCurrentDirectory (KERNEL.412)
559 BOOL16 WINAPI SetCurrentDirectory16( LPCSTR dir )
561 return SetCurrentDirectoryA( dir );
565 /*************************************************************************
566 * FindFirstFile (KERNEL.413)
568 HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data )
570 HGLOBAL16 h16;
571 HANDLE handle, *ptr;
573 if (!(h16 = GlobalAlloc16( GMEM_MOVEABLE, sizeof(handle) ))) return INVALID_HANDLE_VALUE16;
574 ptr = GlobalLock16( h16 );
575 *ptr = handle = FindFirstFileA( path, data );
576 GlobalUnlock16( h16 );
578 if (handle == INVALID_HANDLE_VALUE)
580 GlobalFree16( h16 );
581 h16 = INVALID_HANDLE_VALUE16;
583 return h16;
587 /*************************************************************************
588 * FindNextFile (KERNEL.414)
590 BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data )
592 HANDLE *ptr;
593 BOOL ret = FALSE;
595 if ((handle == INVALID_HANDLE_VALUE16) || !(ptr = GlobalLock16( handle )))
597 SetLastError( ERROR_INVALID_HANDLE );
598 return ret;
600 ret = FindNextFileA( *ptr, data );
601 GlobalUnlock16( handle );
602 return ret;
606 /*************************************************************************
607 * FindClose (KERNEL.415)
609 BOOL16 WINAPI FindClose16( HANDLE16 handle )
611 HANDLE *ptr;
613 if ((handle == INVALID_HANDLE_VALUE16) || !(ptr = GlobalLock16( handle )))
615 SetLastError( ERROR_INVALID_HANDLE );
616 return FALSE;
618 FindClose( *ptr );
619 GlobalUnlock16( handle );
620 GlobalFree16( handle );
621 return TRUE;
625 /***********************************************************************
626 * WritePrivateProfileSection (KERNEL.416)
628 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
629 LPCSTR string, LPCSTR filename )
631 return WritePrivateProfileSectionA( section, string, filename );
635 /***********************************************************************
636 * WriteProfileSection (KERNEL.417)
638 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
640 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
644 /***********************************************************************
645 * GetPrivateProfileSection (KERNEL.418)
647 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
648 UINT16 len, LPCSTR filename )
650 return GetPrivateProfileSectionA( section, buffer, len, filename );
654 /***********************************************************************
655 * GetProfileSection (KERNEL.419)
657 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
659 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
663 /**************************************************************************
664 * GetFileAttributes (KERNEL.420)
666 DWORD WINAPI GetFileAttributes16( LPCSTR name )
668 return GetFileAttributesA( name );
672 /**************************************************************************
673 * SetFileAttributes (KERNEL.421)
675 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
677 return SetFileAttributesA( lpFileName, attributes );
681 /***********************************************************************
682 * GetDiskFreeSpace (KERNEL.422)
684 BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors,
685 LPDWORD sector_bytes, LPDWORD free_clusters,
686 LPDWORD total_clusters )
688 return GetDiskFreeSpaceA( root, cluster_sectors, sector_bytes,
689 free_clusters, total_clusters );