aeca8e834772279e13195f45195c1c6dfb92a214
[captive.git] / src / libcaptive / client / file-slave.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 "file-slave.h" /* self */
23 #include "captive/client-file.h"        /* for CaptiveFileObject */
24 #include "file.h"       /* for CaptiveFileObject priv */
25 #include "directory.h"
26 #include "lib.h"
27 #include <glib/gmessages.h>
28 #include "captive/unicode.h"
29 #include "reactos/ntos/types.h" /* for HANDLE */
30 #include "reactos/ddk/iotypes.h"        /* for IO_STATUS_BLOCK */
31 #include "reactos/ddk/iofuncs.h"        /* for IoCreateFile() */
32 #include "result.h"
33 #include "captive/client-directory.h"
34 #include "reactos/ddk/obfuncs.h"        /* for ObReferenceObjectByHandle() */
35 #include "captive/macros.h"
36 #include "captive/leave.h"
37 #include "captive/usecount.h"
38 #include "vfs.h"
39 #include "vfs-slave.h"
40
41
42 /* Config: */
43 #define MAX_FILE_READ   0x1000000       /* FIXME: Workaround memory consumption for non-journalled fastfat.sys */
44 #define MAX_FILE_WRITTEN 0x100000       /* FIXME: Workaround memory consumption for non-journalled fastfat.sys */
45
46
47 struct _CaptiveFileSlaveObject {
48         CaptiveFileObject parent_instance;
49
50         /*< private >*/
51         HANDLE file_Handle;
52         GnomeVFSFileOffset offset;
53         };
54 struct _CaptiveFileSlaveObjectClass {
55         CaptiveFileObjectClass parent_class;
56         };
57
58
59 static gpointer captive_file_slave_object_parent_class=NULL;
60
61
62 static GnomeVFSResult captive_file_slave_close(CaptiveFileObject *captive_file_object);
63 static GnomeVFSResult captive_file_slave_read(CaptiveFileObject *captive_file_object,
64                 gpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_read_return);
65 static GnomeVFSResult captive_file_slave_write(CaptiveFileObject *captive_file_object,
66                 gconstpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_written_return);
67 static GnomeVFSResult captive_file_slave_seek
68                 (CaptiveFileObject *captive_file_object,GnomeVFSSeekPosition whence,GnomeVFSFileOffset offset);
69 static GnomeVFSResult captive_file_slave_tell(CaptiveFileObject *captive_file_object,GnomeVFSFileOffset *offset_return);
70 static GnomeVFSResult captive_file_slave_remove(CaptiveFileObject *captive_file_object);
71 static GnomeVFSResult captive_file_slave_file_info_get
72                 (CaptiveFileObject *captive_file_object,GnomeVFSFileInfo *file_info);
73 static GnomeVFSResult captive_file_slave_file_info_set
74                 (CaptiveFileObject *captive_file_object,const GnomeVFSFileInfo *info,GnomeVFSSetFileInfoMask mask);
75 static GnomeVFSResult captive_file_slave_truncate(CaptiveFileObject *captive_file_object,GnomeVFSFileSize file_size);
76 static GnomeVFSResult captive_file_slave_move
77                 (CaptiveFileObject *captive_file_object_old,const gchar *pathname_new,gboolean force_replace);
78
79
80 static void captive_file_slave_object_finalize(CaptiveFileSlaveObject *captive_file_slave_object)
81 {
82         g_return_if_fail(captive_file_slave_object!=NULL);
83
84         captive_file_slave_close(CAPTIVE_FILE_OBJECT(captive_file_slave_object));       /* errors ignored */
85
86         G_OBJECT_CLASS(captive_file_slave_object_parent_class)->finalize((GObject *)captive_file_slave_object);
87 }
88
89
90 static void captive_file_slave_object_class_init(CaptiveFileSlaveObjectClass *class)
91 {
92 GObjectClass *gobject_class=G_OBJECT_CLASS(class);
93 CaptiveFileObjectClass *captive_file_object_class=CAPTIVE_FILE_OBJECT_CLASS(class);
94
95         captive_file_slave_object_parent_class=g_type_class_ref(g_type_parent(G_TYPE_FROM_CLASS(class)));
96         gobject_class->finalize=(void (*)(GObject *object))captive_file_slave_object_finalize;
97
98         captive_file_object_class->read=captive_file_slave_read;
99         captive_file_object_class->write=captive_file_slave_write;
100         captive_file_object_class->seek=captive_file_slave_seek;
101         captive_file_object_class->tell=captive_file_slave_tell;
102         captive_file_object_class->remove=captive_file_slave_remove;
103         captive_file_object_class->file_info_get=captive_file_slave_file_info_get;
104         captive_file_object_class->file_info_set=captive_file_slave_file_info_set;
105         captive_file_object_class->truncate=captive_file_slave_truncate;
106         captive_file_object_class->move=captive_file_slave_move;
107 }
108
109
110 static void captive_file_slave_object_init(CaptiveFileSlaveObject *captive_file_slave_object)
111 {
112         captive_file_slave_object->file_Handle=NULL;
113 }
114
115
116 GType captive_file_slave_object_get_type(void)
117 {
118 static GType captive_file_slave_object_type=0;
119
120         if (!captive_file_slave_object_type) {
121 static const GTypeInfo captive_file_slave_object_info={
122                                 sizeof(CaptiveFileSlaveObjectClass),
123                                 NULL,   /* base_init */
124                                 NULL,   /* base_finalize */
125                                 (GClassInitFunc)captive_file_slave_object_class_init,
126                                 NULL,   /* class_finalize */
127                                 NULL,   /* class_data */
128                                 sizeof(CaptiveFileSlaveObject),
129                                 5,      /* n_preallocs */
130                                 (GInstanceInitFunc)captive_file_slave_object_init,
131                                 };
132
133                 captive_file_slave_object_type=g_type_register_static(CAPTIVE_FILE_TYPE_OBJECT,
134                                 "CaptiveFileSlaveObject",&captive_file_slave_object_info,0);
135                 }
136
137         return captive_file_slave_object_type;
138 }
139
140
141 static GnomeVFSResult captive_file_slave_new_internal(CaptiveFileSlaveObject *captive_file_slave_object,
142                 const gchar *pathname,GnomeVFSOpenMode mode,gboolean create,gboolean create_exclusive,guint create_perm)
143 {
144 IO_STATUS_BLOCK file_IoStatusBlock;
145 GnomeVFSResult errvfsresult;
146 OBJECT_ATTRIBUTES file_ObjectAttributes;
147 HANDLE file_Handle;
148 NTSTATUS err;
149
150         g_return_val_if_fail(captive_file_slave_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
151         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
152
153         errvfsresult=captive_ObjectAttributes_init(pathname,&file_ObjectAttributes);
154         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
155         
156         /* open */
157         err=IoCreateFile(
158                         &file_Handle,   /* FileHandle */
159                         0
160                                         /* sniffed: | SYNCHRONIZE       */
161                                         |(!(mode&GNOME_VFS_OPEN_READ ) ? 0 : FILE_READ_DATA)
162                                         |(!(mode&GNOME_VFS_OPEN_WRITE) ? 0 : FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES)
163                                         |(  mode!=0                    ? 0 : FILE_READ_ATTRIBUTES)
164                                         ,       /* DesiredAccess */
165                         &file_ObjectAttributes, /* ObjectAttributes */
166                         &file_IoStatusBlock,    /* IoStatusBlock */
167                         NULL,   /* AllocationSize; ignored for open */
168                         (!create || create_perm&0200 ? FILE_ATTRIBUTE_NORMAL: FILE_ATTRIBUTE_READONLY), /* FileAttributes; ignored for open */
169                         (!create || !create_exclusive   /* ShareAccess; 0 means exclusive */
170                                         ? (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
171                                         : 0),
172                         (!create ? FILE_OPEN : FILE_CREATE),    /* CreateDisposition */
173                         /* FILE_SYNCHRONOUS_IO_{,NON}ALERT: We need to allow W32 filesystem
174                                  * any waits to not to let it return STATUS_CANT_WAIT us.
175                                  * Alertability should have only effect on asynchronous events
176                                  * from KeWaitForSingleObject() by setting/clearing its parameter 'Alertable'.
177                                  */
178                         FILE_SYNCHRONOUS_IO_ALERT       /* CreateOptions */
179                                         /* sniffed: | FILE_DIRECTORY_FILE */
180                                         /* sniffed: | FILE_OPEN_FOR_BACKUP_INTENT */
181                                         ,
182                         NULL,   /* EaBuffer */
183                         0,      /* EaLength */
184                         CreateFileTypeNone,     /* CreateFileType */
185                         NULL,   /* ExtraCreateParameters */
186                         0);     /* Options */
187         g_free(file_ObjectAttributes.ObjectName);       /* left from captive_file_slave_uri_parent_init() */
188         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
189         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
190                 return errvfsresult;
191         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
192         g_return_val_if_fail(file_IoStatusBlock.Information
193                                         ==(!create ? FILE_OPENED : FILE_CREATED),
194                         GNOME_VFS_ERROR_GENERIC);
195
196         captive_file_slave_object->file_Handle=file_Handle;
197
198         return GNOME_VFS_OK;
199 }
200
201
202 GnomeVFSResult captive_file_slave_new_open(CaptiveFileObject **captive_file_object_return,
203                 CaptiveVfsObject *captive_vfs_object,const gchar *pathname,GnomeVFSOpenMode mode)
204 {
205 GnomeVFSResult r;
206 CaptiveFileSlaveObject *captive_file_slave_object;
207
208         g_return_val_if_fail(captive_file_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
209         g_return_val_if_fail(CAPTIVE_VFS_SLAVE_IS_OBJECT(captive_vfs_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
210         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
211
212         captive_file_slave_object=g_object_new(
213                         CAPTIVE_FILE_SLAVE_TYPE_OBJECT, /* object_type */
214                         NULL);  /* first_property_name; FIXME: support properties */
215
216         captive_file_init(CAPTIVE_FILE_OBJECT(captive_file_slave_object),captive_vfs_object);
217
218         *captive_file_object_return=CAPTIVE_FILE_OBJECT(captive_file_slave_object);
219
220         r=captive_file_slave_new_internal(captive_file_slave_object,pathname,mode,
221                         FALSE,  /* create */
222                         FALSE,  /* create_exclusive; ignored */
223                         0);     /* create_perm; ignored */
224
225         captive_leave();
226         if (r==GNOME_VFS_OK)
227                 captive_usecount(+1);
228         else {
229                 g_object_unref(captive_file_slave_object);
230                 *captive_file_object_return=NULL;
231                 }
232         return r;
233 }
234
235
236 GnomeVFSResult captive_file_slave_new_create(CaptiveFileObject **captive_file_object_return,
237                 CaptiveVfsObject *captive_vfs_object,const gchar *pathname,GnomeVFSOpenMode mode,gboolean exclusive,guint perm)
238 {
239 GnomeVFSResult r;
240 CaptiveFileSlaveObject *captive_file_slave_object;
241
242         g_return_val_if_fail(captive_file_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
243         g_return_val_if_fail(CAPTIVE_VFS_SLAVE_IS_OBJECT(captive_vfs_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
244         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
245
246         captive_file_slave_object=g_object_new(
247                         CAPTIVE_FILE_SLAVE_TYPE_OBJECT, /* object_type */
248                         NULL);  /* first_property_name; FIXME: support properties */
249
250         captive_file_init(CAPTIVE_FILE_OBJECT(captive_file_slave_object),captive_vfs_object);
251
252         *captive_file_object_return=CAPTIVE_FILE_OBJECT(captive_file_slave_object);
253
254         r=captive_file_slave_new_internal(captive_file_slave_object,pathname,mode,
255                         TRUE,   /* create */
256                         exclusive,      /* create_exclusive */
257                         perm);  /* create_perm */
258
259         captive_leave();
260         if (r==GNOME_VFS_OK)
261                 captive_usecount(+1);
262         else {
263                 g_object_unref(captive_file_slave_object);
264                 *captive_file_object_return=NULL;
265                 }
266         return r;
267 }
268
269
270 static GnomeVFSResult captive_file_slave_close(CaptiveFileObject *captive_file_object)
271 {
272 CaptiveFileSlaveObject *captive_file_slave_object;
273 NTSTATUS err;
274 HANDLE file_Handle;
275
276         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
277
278         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
279
280         if (captive_file_slave_object->file_Handle!=NULL) {     /* not yet already closed */
281                 captive_usecount(-1);   /* close() errors notwithstanding */
282
283                 file_Handle=captive_file_slave_object->file_Handle;
284                 captive_file_slave_object->file_Handle=NULL;
285                 err=NtClose(file_Handle);
286                 g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
287                 }
288
289         captive_leave();
290         return GNOME_VFS_OK;
291 }
292
293
294 GnomeVFSResult captive_file_slave_read(CaptiveFileObject *captive_file_object,
295                 gpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_read_return)
296 {
297 CaptiveFileSlaveObject *captive_file_slave_object;
298 NTSTATUS err;
299 IO_STATUS_BLOCK file_IoStatusBlock;
300 LARGE_INTEGER file_offset;
301 GnomeVFSResult errvfsresult;
302 static GnomeVFSFileSize total_read=0;
303
304         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
305         g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
306         g_return_val_if_fail(bytes_read_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
307         g_return_val_if_fail(num_bytes==(ULONG)num_bytes,GNOME_VFS_ERROR_BAD_PARAMETERS);
308
309         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
310
311         g_return_val_if_fail(captive_file_slave_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
312
313         /* FIXME: Workaround memory consumption for non-journalled fastfat.sys */
314         if (total_read>=MAX_FILE_READ && captive_options->sandbox)
315                 return GNOME_VFS_ERROR_SERVICE_OBSOLETE;
316         total_read+=num_bytes;
317
318         file_offset.QuadPart=captive_file_slave_object->offset;
319         err=NtReadFile(
320                         captive_file_slave_object->file_Handle, /* FileHandle */
321                         NULL,   /* EventHandle; completion signalling; optional */
322                         NULL,   /* ApcRoutine; optional */
323                         NULL,   /* ApcContext; optional */
324                         &file_IoStatusBlock,    /* IoStatusBlock */
325                         buffer, /* Buffer */
326                         num_bytes,      /* Length */
327                         &file_offset,   /* ByteOffset */
328                         NULL);  /* Key; NULL means no file locking key */
329         if (err==STATUS_END_OF_FILE) {
330                 g_return_val_if_fail(file_IoStatusBlock.Status==STATUS_END_OF_FILE,GNOME_VFS_ERROR_GENERIC);
331                 g_return_val_if_fail(file_IoStatusBlock.Information==0,GNOME_VFS_ERROR_GENERIC);
332                 *bytes_read_return=0;
333                 return GNOME_VFS_ERROR_EOF;
334                 }
335         g_return_val_if_fail(file_IoStatusBlock.Information>0,GNOME_VFS_ERROR_GENERIC); /* if not STATUS_END_OF_FILE... */
336         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
337                 return errvfsresult;
338         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
339         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
340         g_return_val_if_fail(file_IoStatusBlock.Information<=num_bytes,GNOME_VFS_ERROR_GENERIC);
341
342         captive_file_slave_object->offset+=file_IoStatusBlock.Information;
343         *bytes_read_return=file_IoStatusBlock.Information;
344         captive_leave();
345         return GNOME_VFS_OK;
346 }
347
348
349 GnomeVFSResult captive_file_slave_write(CaptiveFileObject *captive_file_object,
350                 gconstpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_written_return)
351 {
352 CaptiveFileSlaveObject *captive_file_slave_object;
353 NTSTATUS err;
354 IO_STATUS_BLOCK file_IoStatusBlock;
355 LARGE_INTEGER file_offset;
356 GnomeVFSFileInfo file_info;
357 GnomeVFSFileSize endoffile_wanted;
358 GnomeVFSResult errvfsresult;
359 static GnomeVFSFileSize total_written=0;
360
361         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
362         g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
363         g_return_val_if_fail(bytes_written_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
364         g_return_val_if_fail(num_bytes==(ULONG)num_bytes,GNOME_VFS_ERROR_BAD_PARAMETERS);
365
366         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
367
368         g_return_val_if_fail(captive_file_slave_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
369
370         /* FIXME: Workaround memory consumption for non-journalled fastfat.sys */
371         if (total_written>=MAX_FILE_WRITTEN && captive_options->sandbox)
372                 return GNOME_VFS_ERROR_SERVICE_OBSOLETE;
373         total_written+=num_bytes;
374
375         if ((GnomeVFSFileOffset)(captive_file_slave_object->offset+num_bytes) < captive_file_slave_object->offset)
376                 return GNOME_VFS_ERROR_TOO_BIG;
377         endoffile_wanted=captive_file_slave_object->offset+num_bytes;
378         if (GNOME_VFS_OK!=(errvfsresult=captive_file_slave_file_info_get(
379                         CAPTIVE_FILE_OBJECT(captive_file_slave_object),&file_info)))
380                 return errvfsresult;
381         if (file_info.size<endoffile_wanted) {
382                 if (GNOME_VFS_OK!=(errvfsresult=captive_file_slave_truncate(
383                                 CAPTIVE_FILE_OBJECT(captive_file_slave_object),endoffile_wanted)))
384                         return errvfsresult;
385                 }
386
387         file_offset.QuadPart=captive_file_slave_object->offset;
388         err=NtWriteFile(
389                         captive_file_slave_object->file_Handle, /* FileHandle */
390                         NULL,   /* Event; completion signalling; optional */
391                         NULL,   /* ApcRoutine; optional */
392                         NULL,   /* ApcContext; optional */
393                         &file_IoStatusBlock,    /* IoStatusBlock */
394                         (gpointer /* de-const */ )buffer,       /* Buffer */
395                         num_bytes,      /* Length */
396                         &file_offset,   /* ByteOffset */
397                         NULL);  /* Key; NULL means no file locking key */
398         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
399         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
400         if (!file_IoStatusBlock.Information) {
401                 /* FIXME: Check ExRaiseStatus(STATUS_LOG_FILE_FULL);
402                  * really occured. We expect so and we will remount the volume.
403                  */
404                 *bytes_written_return=0;
405                 return GNOME_VFS_ERROR_SERVICE_OBSOLETE;
406                 }
407         g_return_val_if_fail(file_IoStatusBlock.Information==num_bytes,GNOME_VFS_ERROR_GENERIC);
408
409         captive_file_slave_object->offset+=file_IoStatusBlock.Information;
410         *bytes_written_return=file_IoStatusBlock.Information;
411         captive_leave();
412         return GNOME_VFS_OK;
413 }
414
415
416 GnomeVFSResult captive_file_slave_seek
417                 (CaptiveFileObject *captive_file_object,GnomeVFSSeekPosition whence,GnomeVFSFileOffset offset)
418 {
419 CaptiveFileSlaveObject *captive_file_slave_object;
420
421         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
422
423         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
424
425         g_return_val_if_fail(captive_file_slave_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
426
427         switch (whence) {
428                 case GNOME_VFS_SEEK_START:
429                         captive_file_slave_object->offset=offset;
430                         break;
431                 case GNOME_VFS_SEEK_CURRENT:
432                         if (0
433                                         || (offset>0 && (captive_file_slave_object->offset+offset)<captive_file_slave_object->offset)
434                                         || (offset<0 && (captive_file_slave_object->offset+offset)>captive_file_slave_object->offset))
435                                 return GNOME_VFS_ERROR_BAD_PARAMETERS;
436                         captive_file_slave_object->offset+=offset;
437                         break;
438                 case GNOME_VFS_SEEK_END:
439                         g_assert_not_reached(); /* NOT IMPLEMENTED YET */
440                         break;
441                 default:
442                         g_return_val_if_reached(GNOME_VFS_ERROR_BAD_PARAMETERS);
443                 }
444
445         captive_leave();
446         return GNOME_VFS_OK;
447 }
448
449
450 GnomeVFSResult captive_file_slave_tell(CaptiveFileObject *captive_file_object,GnomeVFSFileOffset *offset_return)
451 {
452 CaptiveFileSlaveObject *captive_file_slave_object;
453
454         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
455         g_return_val_if_fail(offset_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
456
457         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
458
459         g_return_val_if_fail(captive_file_slave_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
460
461         *offset_return=captive_file_slave_object->offset;
462         captive_leave();
463         return GNOME_VFS_OK;
464 }
465
466
467 GnomeVFSResult captive_file_slave_remove(CaptiveFileObject *captive_file_object)
468 {
469 CaptiveFileSlaveObject *captive_file_slave_object;
470 NTSTATUS err;
471 FILE_DISPOSITION_INFORMATION FileDispositionInformation_struct;
472 IO_STATUS_BLOCK file_IoStatusBlock;
473 GnomeVFSResult errvfsresult;
474
475         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
476
477         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
478
479         g_return_val_if_fail(captive_file_slave_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
480
481         FileDispositionInformation_struct.DoDeleteFile=TRUE;
482
483         err=NtSetInformationFile(
484                         captive_file_slave_object->file_Handle, /* FileHandle */
485                         &file_IoStatusBlock,    /* IoStatusBlock */
486                         &FileDispositionInformation_struct,     /* FileInformation */
487                         sizeof(FileDispositionInformation_struct),      /* Length */
488                         FileDispositionInformation);    /* FileInformationClass */
489         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
490                 return errvfsresult;
491         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
492
493         captive_leave();
494         return GNOME_VFS_OK;
495 }
496
497
498 /* Use 'FileNameInformationStruct' identifier instead of the logical 'FileNameInformation'
499  * to prevent override of enum member 'FileNameInformation'
500  */
501 static GnomeVFSResult FileNameInformationStruct_to_GnomeVFSFileInfo(GnomeVFSFileInfo *file_info,
502                 FILE_NAME_INFORMATION *FileNameInformationStruct)
503 {
504 UNICODE_STRING FileName_UnicodeString;
505
506         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_GENERIC);
507         g_return_val_if_fail(FileNameInformationStruct!=NULL,GNOME_VFS_ERROR_GENERIC);
508
509         FileName_UnicodeString.Length=FileNameInformationStruct->FileNameLength;
510         FileName_UnicodeString.MaximumLength=FileNameInformationStruct->FileNameLength
511                         +sizeof(*FileNameInformationStruct->FileName);  /* 0-terminator */
512
513 #if 0   /* 'IoStatusBlock->Information' is sometimes weird, do not check it */
514         g_assert((gpointer)(((char *)FileNameInformationStruct->FileName)+FileName_UnicodeString.Length)
515                         <=(gpointer)(((char *)FileAllInformationStruct)+IoStatusBlock->Information));
516                                         /* ensure we fit below '->IoStatusBlock->Information' at least without the 0-terminator */
517 #endif
518
519         FileNameInformationStruct->FileName[FileNameInformationStruct->FileNameLength
520                         /sizeof(*FileNameInformationStruct->FileName)]=0;       /* 0-terminate it */
521         FileName_UnicodeString.Buffer=FileNameInformationStruct->FileName;
522         file_info->name=captive_UnicodeString_to_utf8_malloc(&FileName_UnicodeString);
523         /* '->name' assumed for 'file_info->valid_fields' */
524
525         return GNOME_VFS_OK;
526 }
527
528
529 /* Use 'FileBasicInformationStruct' identifier instead of the logical 'FileBasicInformation'
530  * to prevent override of enum member 'FileBasicInformation'
531  */
532 static GnomeVFSResult FileBasicInformationStruct_to_GnomeVFSFileInfo(GnomeVFSFileInfo *file_info,
533                 FILE_BASIC_INFORMATION *FileBasicInformationStruct)
534 {
535 BOOLEAN errBOOLEAN;
536 ULONG tmp_ULONG;
537
538         /* FIXME: What is 'FILE_ATTRIBUTE_NORMAL'? */
539         switch (FileBasicInformationStruct->FileAttributes & (0
540                         | FILE_ATTRIBUTE_DIRECTORY
541                         | FILE_ATTRIBUTE_DEVICE)) {
542                 case 0:                        file_info->type=GNOME_VFS_FILE_TYPE_REGULAR;   break;
543                 case FILE_ATTRIBUTE_DIRECTORY: file_info->type=GNOME_VFS_FILE_TYPE_DIRECTORY; break;
544                 case FILE_ATTRIBUTE_DEVICE:    file_info->type=GNOME_VFS_FILE_TYPE_SOCKET;
545                         /* or GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE or GNOME_VFS_FILE_TYPE_BLOCK_DEVICE ? */
546                         break;
547                 default:                       file_info->type=GNOME_VFS_FILE_TYPE_UNKNOWN;   break;
548                 }
549         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_TYPE;
550
551         /* we use 0600 for r/w files, 0400 for FILE_ATTRIBUTE_READONLY */
552         file_info->permissions=GNOME_VFS_PERM_USER_READ;
553         if (file_info->type==GNOME_VFS_FILE_TYPE_DIRECTORY)
554                 file_info->permissions|=GNOME_VFS_PERM_USER_EXEC;
555         if (!(FileBasicInformationStruct->FileAttributes & FILE_ATTRIBUTE_READONLY))
556                 file_info->permissions|=GNOME_VFS_PERM_USER_WRITE;
557         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
558
559         if (FileBasicInformationStruct->LastAccessTime.QuadPart) {      /* it may be 0 if not set */
560                 errBOOLEAN=RtlTimeToSecondsSince1970(&FileBasicInformationStruct->LastAccessTime,&tmp_ULONG);
561                 g_assert(errBOOLEAN==TRUE);
562                 file_info->atime=tmp_ULONG;
563                 file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_ATIME;
564                 }
565
566         /* it may be 0 if not set */
567         if (FileBasicInformationStruct->LastWriteTime.QuadPart || FileBasicInformationStruct->ChangeTime.QuadPart) {
568                 errBOOLEAN=RtlTimeToSecondsSince1970(
569                                 /* take the more recent (==bigger) time: */
570                                 (FileBasicInformationStruct->LastWriteTime.QuadPart > FileBasicInformationStruct->ChangeTime.QuadPart
571                                                 ? &FileBasicInformationStruct->LastWriteTime : &FileBasicInformationStruct->ChangeTime),
572                                 &tmp_ULONG);
573                 g_assert(errBOOLEAN==TRUE);
574                 file_info->mtime=tmp_ULONG;
575                 file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_MTIME;
576                 }
577
578         if (FileBasicInformationStruct->CreationTime.QuadPart) {        /* it may be 0 if not set */
579                 errBOOLEAN=RtlTimeToSecondsSince1970(&FileBasicInformationStruct->CreationTime,&tmp_ULONG);
580                 g_assert(errBOOLEAN==TRUE);
581                 file_info->ctime=tmp_ULONG;
582                 file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_CTIME;
583                 }
584
585         return GNOME_VFS_OK;
586 }
587
588
589 /* Use 'FileStandardInformationStruct' identifier instead of the logical 'FileStandardInformation'
590  * to prevent override of enum member 'FileStandardInformation'
591  */
592 static GnomeVFSResult FileStandardInformationStruct_to_GnomeVFSFileInfo(GnomeVFSFileInfo *file_info,
593                 FILE_STANDARD_INFORMATION *FileStandardInformationStruct)
594 {
595         file_info->size=FileStandardInformationStruct->EndOfFile.QuadPart;
596         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_SIZE;
597
598         file_info->block_count=FileStandardInformationStruct->AllocationSize.QuadPart/512;
599         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_BLOCK_COUNT;
600
601         return GNOME_VFS_OK;
602 }
603
604
605 GnomeVFSResult captive_file_slave_file_info_get(CaptiveFileObject *captive_file_object,
606                 GnomeVFSFileInfo *file_info)
607 {
608 CaptiveFileSlaveObject *captive_file_slave_object;
609 NTSTATUS err;
610 IO_STATUS_BLOCK file_IoStatusBlock;
611 FILE_NAME_INFORMATION *FileNameInformationStruct;
612 FILE_BASIC_INFORMATION *FileBasicInformationStruct;
613 FILE_STANDARD_INFORMATION *FileStandardInformationStruct;
614 GnomeVFSResult errvfsresult;
615 char QueryFile_buf[sizeof(FILE_NAME_INFORMATION)
616                 +0x1000 /* max 'FileName' length, 255 should be enough */ * sizeof(WCHAR /* *FILE_ALL_INFORMATION.NameInformation.FileName */ )];
617
618         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
619         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
620
621         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
622
623         g_return_val_if_fail(captive_file_slave_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
624
625         /* ntfs.sys of NT-5.1sp1 has *(FILE_BASIC_INFORMATION *)FILE_ALL_INFORMATION.BasicInformation
626          * size 0x28 although reactos includes and all the information says 0x24.
627          * fastfat.sys of NT-5.1sp1 also has the 'official' sizeof 0x24.
628          * It would be a bit of heuristic to correctly detect its expected sizeof.
629          */
630
631         file_info->valid_fields=0;
632
633         file_info->flags=GNOME_VFS_FILE_FLAGS_LOCAL;
634         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_FLAGS;
635
636         /* query NameInformation */
637         FileNameInformationStruct=(void *)QueryFile_buf;
638         err=NtQueryInformationFile(
639                         captive_file_slave_object->file_Handle, /* FileHandle */
640                         &file_IoStatusBlock,    /* IoStatusBlock */
641                         (gpointer)QueryFile_buf,        /* FileInformation */
642                         sizeof(QueryFile_buf)   /* Length */
643                                         -sizeof(*FileNameInformationStruct->FileName),  /* reserve space for a possible 0-terminator */
644                         FileNameInformation);   /* FileInformationClass; =>FILE_NAME_INFORMATION */
645         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
646                 return errvfsresult;
647         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
648         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
649         errvfsresult=FileNameInformationStruct_to_GnomeVFSFileInfo(file_info,FileNameInformationStruct);
650         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
651
652         /* query BasicInformation */
653         FileBasicInformationStruct=(void *)QueryFile_buf;
654         err=NtQueryInformationFile(
655                         captive_file_slave_object->file_Handle, /* FileHandle */
656                         &file_IoStatusBlock,    /* IoStatusBlock */
657                         (gpointer)QueryFile_buf,        /* FileInformation */
658                         sizeof(QueryFile_buf),  /* Length */
659                         FileBasicInformation);  /* FileInformationClass; =>FILE_BASIC_INFORMATION */
660         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
661                 return errvfsresult;
662         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
663         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
664         errvfsresult=FileBasicInformationStruct_to_GnomeVFSFileInfo(file_info,FileBasicInformationStruct);
665         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
666
667         /* query StandardInformation */
668         FileStandardInformationStruct=(void *)QueryFile_buf;
669         err=NtQueryInformationFile(
670                         captive_file_slave_object->file_Handle, /* FileHandle */
671                         &file_IoStatusBlock,    /* IoStatusBlock */
672                         (gpointer)QueryFile_buf,        /* FileInformation */
673                         sizeof(QueryFile_buf),  /* Length */
674                         FileStandardInformation);       /* FileInformationClass; =>FILE_STANDARD_INFORMATION */
675         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
676                 return errvfsresult;
677         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
678         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
679         errvfsresult=FileStandardInformationStruct_to_GnomeVFSFileInfo(file_info,FileStandardInformationStruct);
680         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
681
682         captive_leave();
683         return GNOME_VFS_OK;
684 }
685
686
687 GnomeVFSResult captive_file_slave_file_info_set(CaptiveFileObject *captive_file_object,
688     const GnomeVFSFileInfo *info,GnomeVFSSetFileInfoMask mask)
689 {
690 CaptiveFileSlaveObject *captive_file_slave_object;
691
692         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
693         g_return_val_if_fail(info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
694
695         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
696
697         g_return_val_if_fail(captive_file_slave_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
698
699         if (mask & GNOME_VFS_SET_FILE_INFO_NAME) {
700 gchar *name_dirname,*name_basename;
701 UNICODE_STRING *name_UnicodeString;
702 FILE_RENAME_INFORMATION *FileRenameInformation_structp;
703 gsize FileRenameInformation_struct_len;
704 IO_STATUS_BLOCK file_IoStatusBlock;
705 NTSTATUS err=STATUS_SUCCESS;    /* Prevent: ... might be used uninitialized in this function */
706 GnomeVFSResult errvfsresult;
707
708                 /* non-existing dirname assertion */
709                 name_dirname=g_path_get_dirname(info->name);
710                 if (*name_dirname) {
711                         g_assert_not_reached();
712                         errvfsresult=GNOME_VFS_ERROR_BAD_PARAMETERS;
713                         goto err;
714                         }
715
716                 /* fully-matching basename assertion */
717                 name_basename=g_path_get_basename(info->name);
718                 if (strcmp(name_basename,info->name)) {
719                         g_assert_not_reached();
720                         errvfsresult=GNOME_VFS_ERROR_BAD_PARAMETERS;
721                         goto err_free_name_dirname;
722                         }
723
724                 name_UnicodeString=captive_utf8_to_UnicodeString_alloca(info->name);
725                 FileRenameInformation_struct_len=sizeof(*FileRenameInformation_structp)
726                                 +name_UnicodeString->MaximumLength;     /* ==Length+(0-terminator); is the terminator needed? */
727
728                 FileRenameInformation_structp=g_alloca(FileRenameInformation_struct_len);
729                 FileRenameInformation_structp->Replace=FALSE;
730                 FileRenameInformation_structp->RootDir=NULL;    /* we do 'simple rename' here */
731                 FileRenameInformation_structp->FileNameLength=name_UnicodeString->Length;
732                 memcpy(FileRenameInformation_structp->FileName,name_UnicodeString->Buffer,
733                                 name_UnicodeString->MaximumLength);     /* ==Length+(0-terminator); is the terminator needed? */
734
735                 err=NtSetInformationFile(
736                                 captive_file_slave_object->file_Handle, /* FileHandle */
737                                 &file_IoStatusBlock,    /* IoStatusBlock */
738                                 FileRenameInformation_structp,  /* FileInformation */
739                                 FileRenameInformation_struct_len,       /* Length */
740                                 FileRenameInformation); /* FileInformationClass */
741                 if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
742                         goto err_free_name_basename;
743
744 err_free_name_basename:
745                 g_free(name_basename);
746 err_free_name_dirname:
747                 g_free(name_dirname);
748 err:
749
750                 if (errvfsresult!=GNOME_VFS_OK)
751                         return errvfsresult;
752                 g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
753                 }
754
755         if (mask & (GNOME_VFS_SET_FILE_INFO_PERMISSIONS | GNOME_VFS_SET_FILE_INFO_TIME)) {
756 char FileBasicInformation_buf[sizeof(FILE_BASIC_INFORMATION)+4];
757 FILE_BASIC_INFORMATION *FileBasicInformationp=(FILE_BASIC_INFORMATION *)FileBasicInformation_buf;
758 IO_STATUS_BLOCK file_IoStatusBlock;
759 NTSTATUS err;
760
761                 /* FIXME: Everywhere is is the declaration with 4xLARGE_INTEGER+1xULONG==36 bytes
762                  * but the precompiled ext2fsd.sys wants 40 bytes - why?
763                  * The same case applies to ntfs.sys of NT-5.1sp1.
764                  */
765                 g_assert(sizeof(FILE_BASIC_INFORMATION)==36);
766                 g_assert(sizeof(FileBasicInformation_buf)==40);
767                 err=NtQueryInformationFile(
768                                 captive_file_slave_object->file_Handle, /* FileHandle */
769                                 &file_IoStatusBlock,    /* IoStatusBlock */
770                                 FileBasicInformation_buf,       /* FileInformation */
771                                 sizeof(FileBasicInformation_buf),       /* Length */
772                                 FileBasicInformation);  /* FileInformationClass */
773                 g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
774
775                 if (mask & GNOME_VFS_SET_FILE_INFO_PERMISSIONS) {
776                         FileBasicInformationp->FileAttributes&=~FILE_ATTRIBUTE_READONLY;
777                         g_assert(info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS);
778                         if (!(info->permissions&0200))
779                                 FileBasicInformationp->FileAttributes|=FILE_ATTRIBUTE_READONLY;
780                         }
781
782                 if (mask & GNOME_VFS_SET_FILE_INFO_TIME) {
783                         g_assert(info->valid_fields & (0
784                                         | GNOME_VFS_FILE_INFO_FIELDS_ATIME
785                                         | GNOME_VFS_FILE_INFO_FIELDS_MTIME));
786                         /* !GNOME_VFS_FILE_INFO_FIELDS_CTIME is used by FUSE op_utime(). */
787                         if (info->valid_fields&GNOME_VFS_FILE_INFO_FIELDS_ATIME) {
788                                 RtlSecondsSince1970ToTime(
789                                                 info->atime,    /* SecondsSince1970 */
790                                                 &FileBasicInformationp->LastAccessTime);        /* Time */
791                                 }
792                         if (info->valid_fields&GNOME_VFS_FILE_INFO_FIELDS_MTIME) {
793                                 RtlSecondsSince1970ToTime(
794                                                 info->mtime,    /* SecondsSince1970 */
795                                                 &FileBasicInformationp->LastWriteTime); /* Time */
796                                 FileBasicInformationp->ChangeTime=FileBasicInformationp->LastWriteTime;
797                                 }
798                         if (info->valid_fields&GNOME_VFS_FILE_INFO_FIELDS_CTIME) {
799                                 RtlSecondsSince1970ToTime(
800                                                 info->ctime,    /* SecondsSince1970 */
801                                                 &FileBasicInformationp->CreationTime);  /* Time */
802                                 }
803                         }
804
805                 err=NtSetInformationFile(
806                                 captive_file_slave_object->file_Handle, /* FileHandle */
807                                 &file_IoStatusBlock,    /* IoStatusBlock */
808                                 FileBasicInformation_buf,       /* FileInformation */
809                                 sizeof(FileBasicInformation_buf),       /* Length */
810                                 FileBasicInformation);  /* FileInformationClass */
811                 g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
812                 }
813
814         if (mask & GNOME_VFS_SET_FILE_INFO_OWNER) {
815                 /* FIXME: g_assert(info->valid_fields & ???); */
816                 /* owner ignored for W32 */
817                 }
818
819         captive_leave();
820         return GNOME_VFS_OK;
821 }
822
823
824 GnomeVFSResult captive_file_slave_truncate(CaptiveFileObject *captive_file_object,GnomeVFSFileSize file_size)
825 {
826 CaptiveFileSlaveObject *captive_file_slave_object;
827 NTSTATUS err;
828 FILE_END_OF_FILE_INFORMATION FileEndOfFileInformation_struct;
829 IO_STATUS_BLOCK file_IoStatusBlock;
830 GnomeVFSResult errvfsresult;
831
832         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
833
834         captive_file_slave_object=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object);
835
836         g_return_val_if_fail(captive_file_slave_object->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
837
838         FileEndOfFileInformation_struct.EndOfFile.QuadPart=file_size;
839
840         err=NtSetInformationFile(
841                         captive_file_slave_object->file_Handle, /* FileHandle */
842                         &file_IoStatusBlock,    /* IoStatusBlock */
843                         &FileEndOfFileInformation_struct,       /* FileInformation */
844                         sizeof(FileEndOfFileInformation_struct),        /* Length */
845                         FileEndOfFileInformation);      /* FileInformationClass */
846         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
847                 return errvfsresult;
848         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
849
850         captive_leave();
851         return GNOME_VFS_OK;
852 }
853
854
855 GnomeVFSResult captive_file_slave_move
856                 (CaptiveFileObject *captive_file_object_old,const gchar *pathname_new,gboolean force_replace)
857 {
858 CaptiveFileSlaveObject *captive_file_slave_object_old;
859 NTSTATUS err;
860 FILE_RENAME_INFORMATION *FileRenameInformation_structp;
861 IO_STATUS_BLOCK file_IoStatusBlock;
862 GnomeVFSResult errvfsresult;
863 OBJECT_ATTRIBUTES pathname_new_ObjectAttributes;
864
865         g_return_val_if_fail(CAPTIVE_FILE_SLAVE_IS_OBJECT(captive_file_object_old),GNOME_VFS_ERROR_BAD_PARAMETERS);
866         g_return_val_if_fail(pathname_new!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
867
868         captive_file_slave_object_old=CAPTIVE_FILE_SLAVE_OBJECT(captive_file_object_old);
869
870         g_return_val_if_fail(captive_file_slave_object_old->file_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
871
872         errvfsresult=captive_ObjectAttributes_init(pathname_new,&pathname_new_ObjectAttributes);
873         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
874
875         FileRenameInformation_structp=
876                         g_alloca(sizeof(*FileRenameInformation_structp)+pathname_new_ObjectAttributes.ObjectName->MaximumLength);
877         FileRenameInformation_structp->Replace=force_replace;
878         FileRenameInformation_structp->RootDir=0;       /* AFAIK never set by orig W32 */
879         FileRenameInformation_structp->FileNameLength=pathname_new_ObjectAttributes.ObjectName->Length;
880         memcpy(FileRenameInformation_structp->FileName,pathname_new_ObjectAttributes.ObjectName->Buffer,
881                         pathname_new_ObjectAttributes.ObjectName->MaximumLength);
882
883         err=NtSetInformationFile(
884                         captive_file_slave_object_old->file_Handle,     /* FileHandle */
885                         &file_IoStatusBlock,    /* IoStatusBlock */
886                         FileRenameInformation_structp,  /* FileInformation */
887                         sizeof(*FileRenameInformation_structp)+pathname_new_ObjectAttributes.ObjectName->MaximumLength, /* Length */
888                         FileRenameInformation); /* FileInformationClass */
889         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
890                 goto err_free_ObjectAttributes;
891         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
892
893         errvfsresult=GNOME_VFS_OK;
894
895 err_free_ObjectAttributes:
896         g_free(pathname_new_ObjectAttributes.ObjectName);       /* left from captive_file_slave_uri_parent_init() */
897
898         captive_leave();
899         return errvfsresult;
900 }