libcaptive-gnomevfs.so separated to Gnome-VFS vs. reactos specific parts
[captive.git] / src / libcaptive / client / file.c
1 /* $Id$
2  * captive vfs 'file' interface to reactos
3  * Copyright (C) 2002-2003 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "captive/client-file.h"        /* self */
23 #include "lib.h"
24 #include <glib/gmessages.h>
25 #include "captive/unicode.h"
26 #include "reactos/ntos/types.h" /* for HANDLE */
27 #include "reactos/ddk/iotypes.h"        /* for IO_STATUS_BLOCK */
28 #include "reactos/ddk/iofuncs.h"        /* for IoCreateFile() */
29
30
31 static gpointer captive_file_object_parent_class=NULL;
32
33
34 static GnomeVFSResult captive_file_close(CaptiveFileObject *captive_file_object);
35
36 static void captive_file_object_finalize(CaptiveFileObject *captive_file_object)
37 {
38 GnomeVFSResult errvfsresult;
39
40         g_return_if_fail(captive_file_object!=NULL);
41
42         errvfsresult=captive_file_close(captive_file_object);
43         g_assert(errvfsresult==GNOME_VFS_OK);
44
45         G_OBJECT_CLASS(captive_file_object_parent_class)->finalize((GObject *)captive_file_object);
46 }
47
48
49 static void captive_file_object_class_init(CaptiveFileObjectClass *class)
50 {
51 GObjectClass *gobject_class=G_OBJECT_CLASS(class);
52
53         captive_file_object_parent_class=g_type_class_ref(G_TYPE_OBJECT);
54         gobject_class->finalize=(void (*)(GObject *object))captive_file_object_finalize;
55 }
56
57
58 static void captive_file_object_init(CaptiveFileObject *captive_file_object)
59 {
60         captive_file_object->file_Handle=NULL;
61 }
62
63
64 GType captive_file_object_get_type(void)
65 {
66 static GType captive_file_object_type=0;
67
68         if (!captive_file_object_type) {
69 static const GTypeInfo captive_file_object_info={
70                                 sizeof(CaptiveFileObjectClass),
71                                 NULL,   /* base_init */
72                                 NULL,   /* base_finalize */
73                                 (GClassInitFunc)captive_file_object_class_init,
74                                 NULL,   /* class_finalize */
75                                 NULL,   /* class_data */
76                                 sizeof(CaptiveFileObject),
77                                 5,      /* n_preallocs */
78                                 (GInstanceInitFunc)captive_file_object_init,
79                                 };
80
81                 captive_file_object_type=g_type_register_static(G_TYPE_OBJECT,
82                                 "CaptiveFileObject",&captive_file_object_info,0);
83                 }
84
85         return captive_file_object_type;
86 }
87
88
89 GnomeVFSResult captive_file_new_open
90                 (CaptiveFileObject **captive_file_object_return,const gchar *pathname,GnomeVFSOpenMode mode)
91 {
92 IO_STATUS_BLOCK file_IoStatusBlock;
93 GnomeVFSResult errvfsresult;
94 OBJECT_ATTRIBUTES file_ObjectAttributes;
95 HANDLE file_Handle;
96 CaptiveFileObject *captive_file_object;
97 NTSTATUS err;
98
99         if (CAPTIVE_IS_SANDBOX_PARENT())
100                 return captive_sandbox_parent_file_new_open(captive_file_object_return,pathname,mode);
101
102         g_return_val_if_fail(captive_file_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
103         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
104
105         *captive_file_object_return=NULL;
106
107         errvfsresult=captive_ObjectAttributes_init(pathname,&file_ObjectAttributes);
108         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
109         
110         /* open */
111         err=IoCreateFile(
112                         &file_Handle,   /* FileHandle */
113                         0
114                                         |(!(mode&GNOME_VFS_OPEN_READ ) ? 0 : FILE_READ_DATA)
115                                         |(!(mode&GNOME_VFS_OPEN_WRITE) ? 0 : FILE_WRITE_DATA | FILE_APPEND_DATA)
116                                         ,       /* DesiredAccess */
117                         &file_ObjectAttributes, /* ObjectAttributes */
118                         &file_IoStatusBlock,    /* IoStatusBlock */
119                         NULL,   /* AllocationSize; ignored for open */
120                         FILE_ATTRIBUTE_NORMAL,  /* FileAttributes; ignored for open */
121                         FILE_SHARE_WRITE,       /* ShareAccess; 0 means exclusive */
122                         FILE_OPEN,      /* CreateDisposition */
123                         /* FILE_SYNCHRONOUS_IO_{,NON}ALERT: We need to allow W32 filesystem
124                                  * any waits to not to let it return STATUS_CANT_WAIT us.
125                                  * Alertability should have only effect on asynchronous events
126                                  * from KeWaitForSingleObject() by setting/clearing its parameter 'Alertable'.
127                                  */
128                         FILE_SYNCHRONOUS_IO_ALERT,      /* CreateOptions */
129                         NULL,   /* EaBuffer */
130                         0,      /* EaLength */
131                         CreateFileTypeNone,     /* CreateFileType */
132                         NULL,   /* ExtraCreateParameters */
133                         0);     /* Options */
134         g_free(file_ObjectAttributes.ObjectName);       /* left from captive_file_uri_parent_init() */
135         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
136         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
137         g_return_val_if_fail(file_IoStatusBlock.Information==FILE_OPENED,GNOME_VFS_ERROR_GENERIC);
138
139         captive_file_object=g_object_new(
140                         CAPTIVE_FILE_TYPE_OBJECT,       /* object_type */
141                         NULL);  /* first_property_name; FIXME: support properties */
142
143         captive_file_object->file_Handle=file_Handle;
144         captive_file_object->offset=0;
145
146         *captive_file_object_return=captive_file_object;
147         return GNOME_VFS_OK;
148 }
149
150
151 static GnomeVFSResult captive_file_close(CaptiveFileObject *captive_file_object)
152 {
153 NTSTATUS err;
154 HANDLE file_Handle;
155
156         if (CAPTIVE_IS_SANDBOX_PARENT())
157                 return captive_sandbox_parent_file_close(captive_file_object);
158
159         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
160         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);    /* already closed */
161
162         file_Handle=captive_file_object->file_Handle;
163         captive_file_object->file_Handle=NULL;
164         err=NtClose(file_Handle);
165         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
166
167         return GNOME_VFS_OK;
168 }
169
170
171 GnomeVFSResult captive_file_read
172                 (CaptiveFileObject *captive_file_object,gpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_read_return)
173 {
174 NTSTATUS err;
175 IO_STATUS_BLOCK file_IoStatusBlock;
176 LARGE_INTEGER file_offset;
177
178         if (CAPTIVE_IS_SANDBOX_PARENT())
179                 return captive_sandbox_parent_file_read(captive_file_object,buffer,num_bytes,bytes_read_return);
180
181         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
182         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
183         g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
184         g_return_val_if_fail(bytes_read_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
185         g_return_val_if_fail(num_bytes==(ULONG)num_bytes,GNOME_VFS_ERROR_BAD_PARAMETERS);
186
187         file_offset.QuadPart=captive_file_object->offset;
188         err=NtReadFile(
189                         captive_file_object->file_Handle,       /* FileHandle */
190                         NULL,   /* EventHandle; completion signalling; optional */
191                         NULL,   /* ApcRoutine; optional */
192                         NULL,   /* ApcContext; optional */
193                         &file_IoStatusBlock,    /* IoStatusBlock */
194                         buffer, /* Buffer */
195                         num_bytes,      /* Length */
196                         &file_offset,   /* ByteOffset */
197                         NULL);  /* Key; NULL means no file locking key */
198         if (err==STATUS_END_OF_FILE) {
199                 g_return_val_if_fail(file_IoStatusBlock.Status==STATUS_END_OF_FILE,GNOME_VFS_ERROR_GENERIC);
200                 g_return_val_if_fail(file_IoStatusBlock.Information==0,GNOME_VFS_ERROR_GENERIC);
201                 *bytes_read_return=0;
202                 return GNOME_VFS_ERROR_EOF;
203                 }
204         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
205         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
206         g_return_val_if_fail(file_IoStatusBlock.Information<=num_bytes,GNOME_VFS_ERROR_GENERIC);
207
208         captive_file_object->offset+=file_IoStatusBlock.Information;
209         *bytes_read_return=file_IoStatusBlock.Information;
210         return GNOME_VFS_OK;
211 }
212
213
214 GnomeVFSResult captive_file_seek
215                 (CaptiveFileObject *captive_file_object,GnomeVFSSeekPosition whence,GnomeVFSFileOffset offset)
216 {
217         if (CAPTIVE_IS_SANDBOX_PARENT())
218                 return captive_sandbox_parent_file_seek(captive_file_object,whence,offset);
219
220         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
221         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
222
223         switch (whence) {
224                 case GNOME_VFS_SEEK_START:
225                         captive_file_object->offset=offset;
226                         break;
227                 case GNOME_VFS_SEEK_CURRENT:
228                         if (0
229                                         || (offset>0 && (captive_file_object->offset+offset)<captive_file_object->offset)
230                                         || (offset<0 && (captive_file_object->offset+offset)>captive_file_object->offset))
231                                 return GNOME_VFS_ERROR_BAD_PARAMETERS;
232                         captive_file_object->offset+=offset;
233                         break;
234                 case GNOME_VFS_SEEK_END:
235                         g_assert_not_reached(); /* NOT IMPLEMENTED YET */
236                         break;
237                 default:
238                         g_return_val_if_reached(GNOME_VFS_ERROR_BAD_PARAMETERS);
239                 }
240
241         return GNOME_VFS_OK;
242 }
243
244
245 GnomeVFSResult captive_file_tell(CaptiveFileObject *captive_file_object,GnomeVFSFileOffset *offset_return)
246 {
247         if (CAPTIVE_IS_SANDBOX_PARENT())
248                 return captive_sandbox_parent_file_tell(captive_file_object,offset_return);
249
250         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
251         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
252         g_return_val_if_fail(offset_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
253
254         *offset_return=captive_file_object->offset;
255         return GNOME_VFS_OK;
256 }