+file remove
[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 #include "captive/sandbox.h"
30 #include "result.h"
31
32
33 static gpointer captive_file_object_parent_class=NULL;
34
35
36 static GnomeVFSResult captive_file_close(CaptiveFileObject *captive_file_object);
37
38 static void captive_file_object_finalize(CaptiveFileObject *captive_file_object)
39 {
40 GnomeVFSResult errvfsresult;
41
42         g_return_if_fail(captive_file_object!=NULL);
43
44         errvfsresult=captive_file_close(captive_file_object);
45         g_assert(errvfsresult==GNOME_VFS_OK);
46
47         G_OBJECT_CLASS(captive_file_object_parent_class)->finalize((GObject *)captive_file_object);
48 }
49
50
51 static void captive_file_object_class_init(CaptiveFileObjectClass *class)
52 {
53 GObjectClass *gobject_class=G_OBJECT_CLASS(class);
54
55         captive_file_object_parent_class=g_type_class_ref(G_TYPE_OBJECT);
56         gobject_class->finalize=(void (*)(GObject *object))captive_file_object_finalize;
57 }
58
59
60 static void captive_file_object_init(CaptiveFileObject *captive_file_object)
61 {
62         captive_file_object->file_Handle=NULL;
63 }
64
65
66 GType captive_file_object_get_type(void)
67 {
68 static GType captive_file_object_type=0;
69
70         if (!captive_file_object_type) {
71 static const GTypeInfo captive_file_object_info={
72                                 sizeof(CaptiveFileObjectClass),
73                                 NULL,   /* base_init */
74                                 NULL,   /* base_finalize */
75                                 (GClassInitFunc)captive_file_object_class_init,
76                                 NULL,   /* class_finalize */
77                                 NULL,   /* class_data */
78                                 sizeof(CaptiveFileObject),
79                                 5,      /* n_preallocs */
80                                 (GInstanceInitFunc)captive_file_object_init,
81                                 };
82
83                 captive_file_object_type=g_type_register_static(G_TYPE_OBJECT,
84                                 "CaptiveFileObject",&captive_file_object_info,0);
85                 }
86
87         return captive_file_object_type;
88 }
89
90
91 static GnomeVFSResult captive_file_new_internal(CaptiveFileObject **captive_file_object_return,
92                 const gchar *pathname,GnomeVFSOpenMode mode,gboolean create,gboolean create_exclusive,guint create_perm)
93 {
94 IO_STATUS_BLOCK file_IoStatusBlock;
95 GnomeVFSResult errvfsresult;
96 OBJECT_ATTRIBUTES file_ObjectAttributes;
97 HANDLE file_Handle;
98 CaptiveFileObject *captive_file_object;
99 NTSTATUS err;
100
101         if (CAPTIVE_IS_SANDBOX_PARENT())
102                 return captive_sandbox_parent_file_new_open(captive_file_object_return,pathname,mode);
103
104         g_return_val_if_fail(captive_file_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
105         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
106
107         *captive_file_object_return=NULL;
108
109         errvfsresult=captive_ObjectAttributes_init(pathname,&file_ObjectAttributes);
110         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
111         
112         /* open */
113         err=IoCreateFile(
114                         &file_Handle,   /* FileHandle */
115                         0
116                                         |(!(mode&GNOME_VFS_OPEN_READ ) ? 0 : FILE_READ_DATA)
117                                         |(!(mode&GNOME_VFS_OPEN_WRITE) ? 0 : FILE_WRITE_DATA | FILE_APPEND_DATA)
118                                         ,       /* DesiredAccess */
119                         &file_ObjectAttributes, /* ObjectAttributes */
120                         &file_IoStatusBlock,    /* IoStatusBlock */
121                         NULL,   /* AllocationSize; ignored for open */
122                         (!create || create_perm&0200 ? FILE_ATTRIBUTE_NORMAL: FILE_ATTRIBUTE_READONLY), /* FileAttributes; ignored for open */
123                         (!create || !create_exclusive ? FILE_SHARE_DELETE : 0), /* ShareAccess; 0 means exclusive */
124                         (!create ? FILE_OPEN : FILE_CREATE),    /* CreateDisposition */
125                         /* FILE_SYNCHRONOUS_IO_{,NON}ALERT: We need to allow W32 filesystem
126                                  * any waits to not to let it return STATUS_CANT_WAIT us.
127                                  * Alertability should have only effect on asynchronous events
128                                  * from KeWaitForSingleObject() by setting/clearing its parameter 'Alertable'.
129                                  */
130                         FILE_SYNCHRONOUS_IO_ALERT,      /* CreateOptions */
131                         NULL,   /* EaBuffer */
132                         0,      /* EaLength */
133                         CreateFileTypeNone,     /* CreateFileType */
134                         NULL,   /* ExtraCreateParameters */
135                         0);     /* Options */
136         g_free(file_ObjectAttributes.ObjectName);       /* left from captive_file_uri_parent_init() */
137         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
138         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
139                 return errvfsresult;
140         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
141         g_return_val_if_fail(file_IoStatusBlock.Information
142                                         ==(!create ? FILE_OPENED : FILE_CREATED),
143                         GNOME_VFS_ERROR_GENERIC);
144
145         captive_file_object=g_object_new(
146                         CAPTIVE_FILE_TYPE_OBJECT,       /* object_type */
147                         NULL);  /* first_property_name; FIXME: support properties */
148
149         captive_file_object->file_Handle=file_Handle;
150         captive_file_object->offset=0;
151
152         *captive_file_object_return=captive_file_object;
153         return GNOME_VFS_OK;
154 }
155
156
157 GnomeVFSResult captive_file_new_open
158                 (CaptiveFileObject **captive_file_object_return,const gchar *pathname,GnomeVFSOpenMode mode)
159 {
160         g_return_val_if_fail(captive_file_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
161         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
162
163         return captive_file_new_internal(captive_file_object_return,pathname,mode,
164                         FALSE,  /* create */
165                         FALSE,  /* create_exclusive; ignored */
166                         0);     /* create_perm; ignored */
167 }
168
169
170 GnomeVFSResult captive_file_new_create
171                 (CaptiveFileObject **captive_file_object_return,const gchar *pathname,GnomeVFSOpenMode mode,gboolean exclusive,guint perm)
172 {
173         g_return_val_if_fail(captive_file_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
174         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
175
176         return captive_file_new_internal(captive_file_object_return,pathname,mode,
177                         TRUE,   /* create */
178                         exclusive,      /* create_exclusive */
179                         perm);  /* create_perm */
180 }
181
182
183 static GnomeVFSResult captive_file_close(CaptiveFileObject *captive_file_object)
184 {
185 NTSTATUS err;
186 HANDLE file_Handle;
187
188         if (CAPTIVE_IS_SANDBOX_PARENT())
189                 return captive_sandbox_parent_file_close(captive_file_object);
190
191         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
192         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);    /* already closed */
193
194         file_Handle=captive_file_object->file_Handle;
195         captive_file_object->file_Handle=NULL;
196         err=NtClose(file_Handle);
197         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
198
199         return GNOME_VFS_OK;
200 }
201
202
203 GnomeVFSResult captive_file_read(CaptiveFileObject *captive_file_object,
204                 gpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_read_return)
205 {
206 NTSTATUS err;
207 IO_STATUS_BLOCK file_IoStatusBlock;
208 LARGE_INTEGER file_offset;
209 GnomeVFSResult errvfsresult;
210
211         if (CAPTIVE_IS_SANDBOX_PARENT())
212                 return captive_sandbox_parent_file_read(captive_file_object,buffer,num_bytes,bytes_read_return);
213
214         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
215         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
216         g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
217         g_return_val_if_fail(bytes_read_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
218         g_return_val_if_fail(num_bytes==(ULONG)num_bytes,GNOME_VFS_ERROR_BAD_PARAMETERS);
219
220         file_offset.QuadPart=captive_file_object->offset;
221         err=NtReadFile(
222                         captive_file_object->file_Handle,       /* FileHandle */
223                         NULL,   /* EventHandle; completion signalling; optional */
224                         NULL,   /* ApcRoutine; optional */
225                         NULL,   /* ApcContext; optional */
226                         &file_IoStatusBlock,    /* IoStatusBlock */
227                         buffer, /* Buffer */
228                         num_bytes,      /* Length */
229                         &file_offset,   /* ByteOffset */
230                         NULL);  /* Key; NULL means no file locking key */
231         if (err==STATUS_END_OF_FILE) {
232                 g_return_val_if_fail(file_IoStatusBlock.Status==STATUS_END_OF_FILE,GNOME_VFS_ERROR_GENERIC);
233                 g_return_val_if_fail(file_IoStatusBlock.Information==0,GNOME_VFS_ERROR_GENERIC);
234                 *bytes_read_return=0;
235                 return GNOME_VFS_ERROR_EOF;
236                 }
237         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
238                 return errvfsresult;
239         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
240         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
241         g_return_val_if_fail(file_IoStatusBlock.Information<=num_bytes,GNOME_VFS_ERROR_GENERIC);
242
243         captive_file_object->offset+=file_IoStatusBlock.Information;
244         *bytes_read_return=file_IoStatusBlock.Information;
245         return GNOME_VFS_OK;
246 }
247
248
249 GnomeVFSResult captive_file_write(CaptiveFileObject *captive_file_object,
250                 gconstpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_written_return)
251 {
252 NTSTATUS err;
253 IO_STATUS_BLOCK file_IoStatusBlock;
254 LARGE_INTEGER file_offset;
255
256         if (CAPTIVE_IS_SANDBOX_PARENT())
257                 return captive_sandbox_parent_file_write(captive_file_object,buffer,num_bytes,bytes_written_return);
258
259         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
260         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
261         g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
262         g_return_val_if_fail(bytes_written_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
263         g_return_val_if_fail(num_bytes==(ULONG)num_bytes,GNOME_VFS_ERROR_BAD_PARAMETERS);
264
265         file_offset.QuadPart=captive_file_object->offset;
266         err=NtWriteFile(
267                         captive_file_object->file_Handle,       /* FileHandle */
268                         NULL,   /* Event; completion signalling; optional */
269                         NULL,   /* ApcRoutine; optional */
270                         NULL,   /* ApcContext; optional */
271                         &file_IoStatusBlock,    /* IoStatusBlock */
272                         (gpointer /* de-const */ )buffer,       /* Buffer */
273                         num_bytes,      /* Length */
274                         &file_offset,   /* ByteOffset */
275                         NULL);  /* Key; NULL means no file locking key */
276         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
277         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
278         g_return_val_if_fail(file_IoStatusBlock.Information==num_bytes,GNOME_VFS_ERROR_GENERIC);
279
280         captive_file_object->offset+=file_IoStatusBlock.Information;
281         *bytes_written_return=file_IoStatusBlock.Information;
282         return GNOME_VFS_OK;
283 }
284
285
286 GnomeVFSResult captive_file_seek
287                 (CaptiveFileObject *captive_file_object,GnomeVFSSeekPosition whence,GnomeVFSFileOffset offset)
288 {
289         if (CAPTIVE_IS_SANDBOX_PARENT())
290                 return captive_sandbox_parent_file_seek(captive_file_object,whence,offset);
291
292         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
293         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
294
295         switch (whence) {
296                 case GNOME_VFS_SEEK_START:
297                         captive_file_object->offset=offset;
298                         break;
299                 case GNOME_VFS_SEEK_CURRENT:
300                         if (0
301                                         || (offset>0 && (captive_file_object->offset+offset)<captive_file_object->offset)
302                                         || (offset<0 && (captive_file_object->offset+offset)>captive_file_object->offset))
303                                 return GNOME_VFS_ERROR_BAD_PARAMETERS;
304                         captive_file_object->offset+=offset;
305                         break;
306                 case GNOME_VFS_SEEK_END:
307                         g_assert_not_reached(); /* NOT IMPLEMENTED YET */
308                         break;
309                 default:
310                         g_return_val_if_reached(GNOME_VFS_ERROR_BAD_PARAMETERS);
311                 }
312
313         return GNOME_VFS_OK;
314 }
315
316
317 GnomeVFSResult captive_file_tell(CaptiveFileObject *captive_file_object,GnomeVFSFileOffset *offset_return)
318 {
319         if (CAPTIVE_IS_SANDBOX_PARENT())
320                 return captive_sandbox_parent_file_tell(captive_file_object,offset_return);
321
322         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
323         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
324         g_return_val_if_fail(offset_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
325
326         *offset_return=captive_file_object->offset;
327         return GNOME_VFS_OK;
328 }
329
330
331 GnomeVFSResult captive_file_remove(CaptiveFileObject *captive_file_object)
332 {
333 NTSTATUS err;
334 FILE_DISPOSITION_INFORMATION FileDispositionInformation_struct;
335 IO_STATUS_BLOCK file_IoStatusBlock;
336 GnomeVFSResult errvfsresult;
337
338         g_return_val_if_fail(captive_file_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
339         g_return_val_if_fail(captive_file_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
340
341         FileDispositionInformation_struct.DoDeleteFile=TRUE;
342
343         err=NtSetInformationFile(
344                         captive_file_object->file_Handle,       /* FileHandle */
345                         &file_IoStatusBlock,    /* IoStatusBlock */
346                         &FileDispositionInformation_struct,     /* FileInformation */
347                         sizeof(FileDispositionInformation_struct),      /* Length */
348                         FileDispositionInformation);    /* FileInformationClass */
349         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
350                 return errvfsresult;
351         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
352
353         return GNOME_VFS_OK;
354 }