[5/5] msvcirt: Implement filebuf::open/close

Iván Matellanes matellanesivan at gmail.com
Mon Aug 3 09:49:10 CDT 2015


---
 dlls/msvcirt/msvcirt.c       |  63 ++++++++++++++++++--
 dlls/msvcirt/tests/msvcirt.c | 139 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 198 insertions(+), 4 deletions(-)

diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c
index 0fd9123..80aedab 100644
--- a/dlls/msvcirt/msvcirt.c
+++ b/dlls/msvcirt/msvcirt.c
@@ -19,8 +19,12 @@
 
 #include "config.h"
 
+#include <fcntl.h>
+#include <io.h>
+#include <share.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <sys/stat.h>
 
 #include "msvcirt.h"
 #include "windef.h"
@@ -100,6 +104,8 @@ typedef struct {
     int close;
 } filebuf;
 
+filebuf* __thiscall filebuf_close(filebuf*);
+
 /* class ios */
 struct _ostream;
 typedef struct {
@@ -549,6 +555,7 @@ void __thiscall streambuf_setp(streambuf *this, char *pb, char *ep)
 /* ?sync at streambuf@@UAEHXZ */
 /* ?sync at streambuf@@UEAAHXZ */
 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)
 {
     TRACE("(%p)\n", this);
@@ -821,6 +828,8 @@ DEFINE_THISCALL_WRAPPER(filebuf_dtor, 4)
 void __thiscall filebuf_dtor(filebuf* this)
 {
     TRACE("(%p)\n", this);
+    if (this->close)
+        filebuf_close(this);
     streambuf_dtor(&this->base);
 }
 
@@ -884,8 +893,16 @@ filebuf* __thiscall filebuf_attach(filebuf *this, filedesc fd)
 DEFINE_THISCALL_WRAPPER(filebuf_close, 4)
 filebuf* __thiscall filebuf_close(filebuf *this)
 {
-    FIXME("(%p) stub\n", this);
-    return NULL;
+    TRACE("(%p)\n", this);
+    if (this->fd == -1)
+        return NULL;
+
+    streambuf_lock(&this->base);
+    call_streambuf_sync(&this->base);
+    if (_close(this->fd) == 0)
+        this->fd = -1;
+    streambuf_unlock(&this->base);
+    return (this->fd == -1) ? this : NULL;
 }
 
 /* ?fd at filebuf@@QBEHXZ */
@@ -911,8 +928,46 @@ int __thiscall filebuf_is_open(const filebuf *this)
 DEFINE_THISCALL_WRAPPER(filebuf_open, 16)
 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);
-    return NULL;
+    const int inout_mode[4] = {-1, _O_RDONLY, _O_WRONLY, _O_RDWR};
+    const int share_mode[4] = {_SH_DENYRW, _SH_DENYWR, _SH_DENYRD, _SH_DENYNO};
+    int op_flags, sh_flags, fd;
+
+    TRACE("(%p %s %d %d)\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 %d, sh_flags %d\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->fd = fd;
+    this->close = 1;
+    if (mode & OPENMODE_ate)
+        call_streambuf_seekoff(&this->base, 0, SEEKDIR_end, OPENMODE_in|OPENMODE_out);
+    streambuf_unlock(&this->base);
+    return this;
 }
 
 /* ?overflow at filebuf@@UAEHH at Z */
diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c
index b1d49a6..e0bda56 100644
--- a/dlls/msvcirt/tests/msvcirt.c
+++ b/dlls/msvcirt/tests/msvcirt.c
@@ -16,6 +16,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <io.h>
 #include <stdio.h>
 #include <windef.h>
 #include <winbase.h>
@@ -32,6 +33,17 @@ typedef enum {
 } 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 {
     FLAGS_skipws     = 0x1,
     FLAGS_left       = 0x2,
     FLAGS_right      = 0x4,
@@ -49,6 +61,11 @@ typedef enum {
     FLAGS_stdio      = 0x4000
 } 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 */
 typedef struct {
     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 void (*__thiscall p_filebuf_dtor)(filebuf*);
 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 */
 static ios* (*__thiscall p_ios_copy_ctor)(ios*, const ios*);
@@ -271,6 +290,8 @@ static BOOL init(void)
         SET(p_filebuf_ctor, "??0filebuf@@QEAA at XZ");
         SET(p_filebuf_dtor, "??1filebuf@@UEAA at XZ");
         SET(p_filebuf_attach, "?attach at filebuf@@QEAAPEAV1 at H@Z");
+        SET(p_filebuf_open, "?open at filebuf@@QEAAPEAV1 at PEBDHH@Z");
+        SET(p_filebuf_close, "?close at filebuf@@QEAAPEAV1 at XZ");
 
         SET(p_ios_copy_ctor, "??0ios@@IEAA at AEBV0@@Z");
         SET(p_ios_ctor, "??0ios@@IEAA at XZ");
@@ -327,6 +348,8 @@ static BOOL init(void)
         SET(p_filebuf_ctor, "??0filebuf@@QAE at XZ");
         SET(p_filebuf_dtor, "??1filebuf@@UAE at XZ");
         SET(p_filebuf_attach, "?attach at filebuf@@QAEPAV1 at H@Z");
+        SET(p_filebuf_open, "?open at filebuf@@QAEPAV1 at PBDHH@Z");
+        SET(p_filebuf_close, "?close at filebuf@@QAEPAV1 at XZ");
 
         SET(p_ios_copy_ctor, "??0ios@@IAE at ABV0@@Z");
         SET(p_ios_ctor, "??0ios@@IAE at XZ");
@@ -930,6 +953,10 @@ static void test_filebuf(void)
     filebuf fb1, fb2, fb3, *pret;
     struct filebuf_lock_arg lock_arg;
     HANDLE thread;
+    const char filename1[] = "test1";
+    const char filename2[] = "test2";
+    const char filename3[] = "test3";
+    char read_buffer[16];
 
     memset(&fb1, 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);
     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);
     WaitForSingleObject(thread, INFINITE);
 
     /* destructor */
     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, &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.test);
     CloseHandle(thread);
-- 
2.1.4




More information about the wine-patches mailing list