msvcirt: Implement filebuf::open/close.

This commit is contained in:
Iván Matellanes 2015-08-05 20:32:29 +02:00 committed by Alexandre Julliard
parent bb060fe62f
commit 95fd3af190
2 changed files with 207 additions and 6 deletions

View File

@ -19,8 +19,12 @@
#include "config.h" #include "config.h"
#include <fcntl.h>
#include <io.h>
#include <share.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <sys/stat.h>
#include "msvcirt.h" #include "msvcirt.h"
#include "windef.h" #include "windef.h"
@ -100,6 +104,8 @@ typedef struct {
int close; int close;
} filebuf; } filebuf;
filebuf* __thiscall filebuf_close(filebuf*);
/* class ios */ /* class ios */
struct _ostream; struct _ostream;
typedef struct { typedef struct {
@ -549,6 +555,7 @@ void __thiscall streambuf_setp(streambuf *this, char *pb, char *ep)
/* ?sync@streambuf@@UAEHXZ */ /* ?sync@streambuf@@UAEHXZ */
/* ?sync@streambuf@@UEAAHXZ */ /* ?sync@streambuf@@UEAAHXZ */
DEFINE_THISCALL_WRAPPER(streambuf_sync, 4) DEFINE_THISCALL_WRAPPER(streambuf_sync, 4)
#define call_streambuf_sync(this) CALL_VTBL_FUNC(this, 4, int, (streambuf*), (this))
int __thiscall streambuf_sync(streambuf *this) int __thiscall streambuf_sync(streambuf *this)
{ {
TRACE("(%p)\n", this); TRACE("(%p)\n", this);
@ -821,6 +828,8 @@ DEFINE_THISCALL_WRAPPER(filebuf_dtor, 4)
void __thiscall filebuf_dtor(filebuf* this) void __thiscall filebuf_dtor(filebuf* this)
{ {
TRACE("(%p)\n", this); TRACE("(%p)\n", this);
if (this->close)
filebuf_close(this);
streambuf_dtor(&this->base); streambuf_dtor(&this->base);
} }
@ -884,8 +893,21 @@ filebuf* __thiscall filebuf_attach(filebuf *this, filedesc fd)
DEFINE_THISCALL_WRAPPER(filebuf_close, 4) DEFINE_THISCALL_WRAPPER(filebuf_close, 4)
filebuf* __thiscall filebuf_close(filebuf *this) filebuf* __thiscall filebuf_close(filebuf *this)
{ {
FIXME("(%p) stub\n", this); filebuf *ret;
return NULL;
TRACE("(%p)\n", this);
if (this->fd == -1)
return NULL;
streambuf_lock(&this->base);
if (call_streambuf_sync(&this->base) == EOF || _close(this->fd) < 0) {
ret = NULL;
} else {
this->fd = -1;
ret = this;
}
streambuf_unlock(&this->base);
return ret;
} }
/* ?fd@filebuf@@QBEHXZ */ /* ?fd@filebuf@@QBEHXZ */
@ -911,8 +933,48 @@ int __thiscall filebuf_is_open(const filebuf *this)
DEFINE_THISCALL_WRAPPER(filebuf_open, 16) DEFINE_THISCALL_WRAPPER(filebuf_open, 16)
filebuf* __thiscall filebuf_open(filebuf *this, const char *name, ios_open_mode mode, int protection) filebuf* __thiscall filebuf_open(filebuf *this, const char *name, ios_open_mode mode, int protection)
{ {
FIXME("(%p %s %d %d) stub\n", this, name, mode, protection); const int inout_mode[4] = {-1, _O_RDONLY, _O_WRONLY, _O_RDWR};
return NULL; const int share_mode[4] = {_SH_DENYRW, _SH_DENYWR, _SH_DENYRD, _SH_DENYNO};
int op_flags, sh_flags, fd;
TRACE("(%p %s %x %x)\n", this, name, mode, protection);
if (this->fd != -1)
return NULL;
/* mode */
if (mode & (OPENMODE_app|OPENMODE_trunc))
mode |= OPENMODE_out;
op_flags = inout_mode[mode & (OPENMODE_in|OPENMODE_out)];
if (op_flags < 0)
return NULL;
if (mode & OPENMODE_app)
op_flags |= _O_APPEND;
if ((mode & OPENMODE_trunc) ||
((mode & OPENMODE_out) && !(mode & (OPENMODE_in|OPENMODE_app|OPENMODE_ate))))
op_flags |= _O_TRUNC;
if (!(mode & OPENMODE_nocreate))
op_flags |= _O_CREAT;
if (mode & OPENMODE_noreplace)
op_flags |= _O_EXCL;
op_flags |= (mode & OPENMODE_binary) ? _O_BINARY : _O_TEXT;
/* share protection */
sh_flags = (protection & filebuf_sh_none) ? share_mode[(protection >> 9) & 3] : _SH_DENYNO;
TRACE("op_flags %x, sh_flags %x\n", op_flags, sh_flags);
fd = _sopen(name, op_flags, sh_flags, _S_IREAD|_S_IWRITE);
if (fd < 0)
return NULL;
streambuf_lock(&this->base);
this->close = 1;
if ((mode & OPENMODE_ate) &&
call_streambuf_seekoff(&this->base, 0, SEEKDIR_end, mode & (OPENMODE_in|OPENMODE_out)) == EOF) {
_close(fd);
} else
this->fd = fd;
streambuf_unlock(&this->base);
return (this->fd == -1) ? NULL : this;
} }
/* ?overflow@filebuf@@UAEHH@Z */ /* ?overflow@filebuf@@UAEHH@Z */
@ -930,7 +992,7 @@ DEFINE_THISCALL_WRAPPER(filebuf_seekoff, 16)
streampos __thiscall filebuf_seekoff(filebuf *this, streamoff offset, ios_seek_dir dir, int mode) streampos __thiscall filebuf_seekoff(filebuf *this, streamoff offset, ios_seek_dir dir, int mode)
{ {
FIXME("(%p %d %d %d) stub\n", this, offset, dir, mode); FIXME("(%p %d %d %d) stub\n", this, offset, dir, mode);
return EOF; return 0;
} }
/* ?setbuf@filebuf@@UAEPAVstreambuf@@PADH@Z */ /* ?setbuf@filebuf@@UAEPAVstreambuf@@PADH@Z */
@ -957,7 +1019,7 @@ DEFINE_THISCALL_WRAPPER(filebuf_sync, 4)
int __thiscall filebuf_sync(filebuf *this) int __thiscall filebuf_sync(filebuf *this)
{ {
FIXME("(%p) stub\n", this); FIXME("(%p) stub\n", this);
return EOF; return 0;
} }
/* ?underflow@filebuf@@UAEHXZ */ /* ?underflow@filebuf@@UAEHXZ */

View File

@ -16,6 +16,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <io.h>
#include <stdio.h> #include <stdio.h>
#include <windef.h> #include <windef.h>
#include <winbase.h> #include <winbase.h>
@ -31,6 +32,17 @@ typedef enum {
IOSTATE_badbit = 0x4 IOSTATE_badbit = 0x4
} ios_io_state; } ios_io_state;
typedef enum {
OPENMODE_in = 0x1,
OPENMODE_out = 0x2,
OPENMODE_ate = 0x4,
OPENMODE_app = 0x8,
OPENMODE_trunc = 0x10,
OPENMODE_nocreate = 0x20,
OPENMODE_noreplace = 0x40,
OPENMODE_binary = 0x80
} ios_open_mode;
typedef enum { typedef enum {
FLAGS_skipws = 0x1, FLAGS_skipws = 0x1,
FLAGS_left = 0x2, FLAGS_left = 0x2,
@ -49,6 +61,11 @@ typedef enum {
FLAGS_stdio = 0x4000 FLAGS_stdio = 0x4000
} ios_flags; } ios_flags;
const int filebuf_sh_none = 0x800;
const int filebuf_sh_read = 0xa00;
const int filebuf_sh_write = 0xc00;
const int filebuf_openprot = 420;
/* class streambuf */ /* class streambuf */
typedef struct { typedef struct {
const vtable_ptr *vtable; const vtable_ptr *vtable;
@ -135,6 +152,8 @@ static filebuf* (*__thiscall p_filebuf_fd_reserve_ctor)(filebuf*, int, char*, in
static filebuf* (*__thiscall p_filebuf_ctor)(filebuf*); static filebuf* (*__thiscall p_filebuf_ctor)(filebuf*);
static void (*__thiscall p_filebuf_dtor)(filebuf*); static void (*__thiscall p_filebuf_dtor)(filebuf*);
static filebuf* (*__thiscall p_filebuf_attach)(filebuf*, filedesc); static filebuf* (*__thiscall p_filebuf_attach)(filebuf*, filedesc);
static filebuf* (*__thiscall p_filebuf_open)(filebuf*, const char*, ios_open_mode, int);
static filebuf* (*__thiscall p_filebuf_close)(filebuf*);
/* ios */ /* ios */
static ios* (*__thiscall p_ios_copy_ctor)(ios*, const ios*); static ios* (*__thiscall p_ios_copy_ctor)(ios*, const ios*);
@ -271,6 +290,8 @@ static BOOL init(void)
SET(p_filebuf_ctor, "??0filebuf@@QEAA@XZ"); SET(p_filebuf_ctor, "??0filebuf@@QEAA@XZ");
SET(p_filebuf_dtor, "??1filebuf@@UEAA@XZ"); SET(p_filebuf_dtor, "??1filebuf@@UEAA@XZ");
SET(p_filebuf_attach, "?attach@filebuf@@QEAAPEAV1@H@Z"); SET(p_filebuf_attach, "?attach@filebuf@@QEAAPEAV1@H@Z");
SET(p_filebuf_open, "?open@filebuf@@QEAAPEAV1@PEBDHH@Z");
SET(p_filebuf_close, "?close@filebuf@@QEAAPEAV1@XZ");
SET(p_ios_copy_ctor, "??0ios@@IEAA@AEBV0@@Z"); SET(p_ios_copy_ctor, "??0ios@@IEAA@AEBV0@@Z");
SET(p_ios_ctor, "??0ios@@IEAA@XZ"); SET(p_ios_ctor, "??0ios@@IEAA@XZ");
@ -327,6 +348,8 @@ static BOOL init(void)
SET(p_filebuf_ctor, "??0filebuf@@QAE@XZ"); SET(p_filebuf_ctor, "??0filebuf@@QAE@XZ");
SET(p_filebuf_dtor, "??1filebuf@@UAE@XZ"); SET(p_filebuf_dtor, "??1filebuf@@UAE@XZ");
SET(p_filebuf_attach, "?attach@filebuf@@QAEPAV1@H@Z"); SET(p_filebuf_attach, "?attach@filebuf@@QAEPAV1@H@Z");
SET(p_filebuf_open, "?open@filebuf@@QAEPAV1@PBDHH@Z");
SET(p_filebuf_close, "?close@filebuf@@QAEPAV1@XZ");
SET(p_ios_copy_ctor, "??0ios@@IAE@ABV0@@Z"); SET(p_ios_copy_ctor, "??0ios@@IAE@ABV0@@Z");
SET(p_ios_ctor, "??0ios@@IAE@XZ"); SET(p_ios_ctor, "??0ios@@IAE@XZ");
@ -930,6 +953,10 @@ static void test_filebuf(void)
filebuf fb1, fb2, fb3, *pret; filebuf fb1, fb2, fb3, *pret;
struct filebuf_lock_arg lock_arg; struct filebuf_lock_arg lock_arg;
HANDLE thread; HANDLE thread;
const char filename1[] = "test1";
const char filename2[] = "test2";
const char filename3[] = "test3";
char read_buffer[16];
memset(&fb1, 0xab, sizeof(filebuf)); memset(&fb1, 0xab, sizeof(filebuf));
memset(&fb2, 0xab, sizeof(filebuf)); memset(&fb2, 0xab, sizeof(filebuf));
@ -982,14 +1009,126 @@ static void test_filebuf(void)
ok(fb3.fd == 2, "wrong fd, expected 2 got %d\n", fb3.fd); ok(fb3.fd == 2, "wrong fd, expected 2 got %d\n", fb3.fd);
fb3.base.do_lock = -1; fb3.base.do_lock = -1;
/* open modes */
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_out, filebuf_openprot);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
fb1.fd = -1;
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1,
OPENMODE_ate|OPENMODE_nocreate|OPENMODE_noreplace|OPENMODE_binary, filebuf_openprot);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
fb1.base.do_lock = 0;
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_out, filebuf_openprot);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
ok(_write(fb1.fd, "testing", 7) == 7, "_write failed\n");
pret = (filebuf*) call_func1(p_filebuf_close, &fb1);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
ok(fb1.fd == -1, "wrong fd, expected -1 got %d\n", fb1.fd);
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_out, filebuf_openprot);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
ok(_read(fb1.fd, read_buffer, 1) == -1, "file should not be open for reading\n");
pret = (filebuf*) call_func1(p_filebuf_close, &fb1);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_app, filebuf_openprot);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
ok(_read(fb1.fd, read_buffer, 1) == -1, "file should not be open for reading\n");
ok(_write(fb1.fd, "testing", 7) == 7, "_write failed\n");
ok(_lseek(fb1.fd, 0, SEEK_SET) == 0, "_lseek failed\n");
ok(_write(fb1.fd, "append", 6) == 6, "_write failed\n");
pret = (filebuf*) call_func1(p_filebuf_close, &fb1);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_out|OPENMODE_ate, filebuf_openprot);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
ok(_read(fb1.fd, read_buffer, 1) == -1, "file should not be open for reading\n");
ok(_lseek(fb1.fd, 0, SEEK_SET) == 0, "_lseek failed\n");
ok(_write(fb1.fd, "ate", 3) == 3, "_write failed\n");
pret = (filebuf*) call_func1(p_filebuf_close, &fb1);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_in, filebuf_openprot);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
ok(_read(fb1.fd, read_buffer, 13) == 13, "read failed\n");
read_buffer[13] = 0;
ok(!strncmp(read_buffer, "atetingappend", 13), "wrong contents, expected 'atetingappend' got '%s'\n", read_buffer);
pret = (filebuf*) call_func1(p_filebuf_close, &fb1);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_in|OPENMODE_trunc, filebuf_openprot);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
ok(_read(fb1.fd, read_buffer, 1) == 0, "read failed\n");
ok(_write(fb1.fd, "file1", 5) == 5, "_write failed\n");
pret = (filebuf*) call_func1(p_filebuf_close, &fb1);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_in|OPENMODE_app, filebuf_openprot);
ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
ok(_write(fb1.fd, "app", 3) == 3, "_write failed\n");
ok(_read(fb1.fd, read_buffer, 1) == 0, "read failed\n");
ok(_lseek(fb1.fd, 0, SEEK_SET) == 0, "_lseek failed\n");
ok(_read(fb1.fd, read_buffer, 8) == 8, "read failed\n");
read_buffer[8] = 0;
ok(!strncmp(read_buffer, "file1app", 8), "wrong contents, expected 'file1app' got '%s'\n", read_buffer);
fb1.base.do_lock = -1;
fb2.fd = -1;
pret = (filebuf*) call_func4(p_filebuf_open, &fb2, filename2, OPENMODE_out|OPENMODE_nocreate, filebuf_openprot);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb2, filename2, OPENMODE_in|OPENMODE_nocreate, filebuf_openprot);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
fb2.base.do_lock = 0;
pret = (filebuf*) call_func4(p_filebuf_open, &fb2, filename2, OPENMODE_in, filebuf_openprot);
ok(pret == &fb2, "wrong return, expected %p got %p\n", &fb2, pret);
ok(_read(fb1.fd, read_buffer, 1) == 0, "read failed\n");
pret = (filebuf*) call_func1(p_filebuf_close, &fb2);
ok(pret == &fb2, "wrong return, expected %p got %p\n", &fb2, pret);
fb2.base.do_lock = -1;
pret = (filebuf*) call_func4(p_filebuf_open, &fb2, filename2, OPENMODE_in|OPENMODE_noreplace, filebuf_openprot);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb2, filename2, OPENMODE_trunc|OPENMODE_noreplace, filebuf_openprot);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb2, filename3, OPENMODE_out|OPENMODE_nocreate|OPENMODE_noreplace, filebuf_openprot);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
/* open protection*/
fb3.fd = -1;
fb3.base.do_lock = 0;
pret = (filebuf*) call_func4(p_filebuf_open, &fb3, filename3, OPENMODE_in, filebuf_openprot);
ok(pret == &fb3, "wrong return, expected %p got %p\n", &fb3, pret);
fb2.base.do_lock = 0;
pret = (filebuf*) call_func4(p_filebuf_open, &fb2, filename3, OPENMODE_in|OPENMODE_out, filebuf_openprot);
ok(pret == &fb2, "wrong return, expected %p got %p\n", &fb2, pret);
pret = (filebuf*) call_func1(p_filebuf_close, &fb2);
ok(pret == &fb2, "wrong return, expected %p got %p\n", &fb2, pret);
fb2.base.do_lock = -1;
pret = (filebuf*) call_func1(p_filebuf_close, &fb3);
ok(pret == &fb3, "wrong return, expected %p got %p\n", &fb3, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb3, filename3, OPENMODE_in, filebuf_sh_none);
ok(pret == &fb3, "wrong return, expected %p got %p\n", &fb3, pret);
pret = (filebuf*) call_func4(p_filebuf_open, &fb2, filename3, OPENMODE_in, filebuf_openprot);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
fb3.base.do_lock = -1;
/* close */
pret = (filebuf*) call_func1(p_filebuf_close, &fb2);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
fb3.base.do_lock = 0;
pret = (filebuf*) call_func1(p_filebuf_close, &fb3);
ok(pret == &fb3, "wrong return, expected %p got %p\n", &fb3, pret);
ok(fb3.fd == -1, "wrong fd, expected -1 got %d\n", fb3.fd);
fb3.fd = 5;
pret = (filebuf*) call_func1(p_filebuf_close, &fb3);
ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
ok(fb3.fd == 5, "wrong fd, expected 5 got %d\n", fb3.fd);
fb3.base.do_lock = -1;
SetEvent(lock_arg.test); SetEvent(lock_arg.test);
WaitForSingleObject(thread, INFINITE); WaitForSingleObject(thread, INFINITE);
/* destructor */ /* destructor */
call_func1(p_filebuf_dtor, &fb1); call_func1(p_filebuf_dtor, &fb1);
ok(fb1.fd == -1, "wrong fd, expected -1 got %d\n", fb1.fd);
call_func1(p_filebuf_dtor, &fb2); call_func1(p_filebuf_dtor, &fb2);
call_func1(p_filebuf_dtor, &fb3); call_func1(p_filebuf_dtor, &fb3);
ok(_unlink(filename1) == 0, "Couldn't unlink file named '%s'\n", filename1);
ok(_unlink(filename2) == 0, "Couldn't unlink file named '%s'\n", filename2);
ok(_unlink(filename3) == 0, "Couldn't unlink file named '%s'\n", filename3);
CloseHandle(lock_arg.lock); CloseHandle(lock_arg.lock);
CloseHandle(lock_arg.test); CloseHandle(lock_arg.test);
CloseHandle(thread); CloseHandle(thread);