+file remove
[captive.git] / src / libcaptive / client / file_info.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_info.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 /* Use 'FileAllInformationStruct' identifier instead of the logical 'FileAllInformation'
34  * to prevent override of enum member 'FileAllInformation'
35  */
36 static GnomeVFSResult FileAllInformationStruct_to_GnomeVFSFileInfo(GnomeVFSFileInfo *file_info,
37                 FILE_ALL_INFORMATION *FileAllInformationStruct,IO_STATUS_BLOCK *IoStatusBlock)
38 {
39 UNICODE_STRING FileName_UnicodeString;
40 BOOLEAN errBOOLEAN;
41 ULONG tmp_ULONG;
42
43         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_GENERIC);
44         g_return_val_if_fail(FileAllInformationStruct!=NULL,GNOME_VFS_ERROR_GENERIC);
45
46         g_return_val_if_fail(NT_SUCCESS(IoStatusBlock->Status),GNOME_VFS_ERROR_GENERIC);
47
48         file_info->valid_fields=0;
49
50         FileName_UnicodeString.Length=FileAllInformationStruct->NameInformation.FileNameLength;
51         FileName_UnicodeString.MaximumLength=FileAllInformationStruct->NameInformation.FileNameLength
52                         +sizeof(*FileAllInformationStruct->NameInformation.FileName);   /* 0-terminator */
53         g_assert((gpointer)(((char *)FileAllInformationStruct->NameInformation.FileName)+FileName_UnicodeString.Length)
54                         <=(gpointer)(((char *)FileAllInformationStruct)+IoStatusBlock->Information));
55                                         /* ensure we fit below '->IoStatusBlock->Information' at least without the 0-terminator */
56         FileAllInformationStruct->NameInformation.FileName[FileAllInformationStruct->NameInformation.FileNameLength
57                         /sizeof(*FileAllInformationStruct->NameInformation.FileName)]=0;        /* 0-terminate it */
58         FileName_UnicodeString.Buffer=FileAllInformationStruct->NameInformation.FileName;
59         file_info->name=captive_UnicodeString_to_utf8_malloc(&FileName_UnicodeString);
60         /* '->name' assumed for 'file_info->valid_fields' */
61
62         /* FIXME: What is 'FILE_ATTRIBUTE_NORMAL'? */
63         switch (FileAllInformationStruct->BasicInformation.FileAttributes & (0
64                         | FILE_ATTRIBUTE_DIRECTORY
65                         | FILE_ATTRIBUTE_DEVICE)) {
66                 case 0:                        file_info->type=GNOME_VFS_FILE_TYPE_REGULAR;   break;
67                 case FILE_ATTRIBUTE_DIRECTORY: file_info->type=GNOME_VFS_FILE_TYPE_DIRECTORY; break;
68                 case FILE_ATTRIBUTE_DEVICE:    file_info->type=GNOME_VFS_FILE_TYPE_SOCKET;
69                         /* or GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE or GNOME_VFS_FILE_TYPE_BLOCK_DEVICE ? */
70                         break;
71                 default:                       file_info->type=GNOME_VFS_FILE_TYPE_UNKNOWN;   break;
72                 }
73         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_TYPE;
74
75         /* we use 0600 for r/w files, 0400 for FILE_ATTRIBUTE_READONLY */
76         file_info->permissions=GNOME_VFS_PERM_USER_READ;
77         if (file_info->type==GNOME_VFS_FILE_TYPE_DIRECTORY)
78                 file_info->permissions|=GNOME_VFS_PERM_USER_EXEC;
79         if (!(FileAllInformationStruct->BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY))
80                 file_info->permissions|=GNOME_VFS_PERM_USER_WRITE;
81         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
82
83         file_info->size=FileAllInformationStruct->StandardInformation.EndOfFile.QuadPart;
84         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_SIZE;
85
86         file_info->block_count=FileAllInformationStruct->StandardInformation.AllocationSize.QuadPart/512;
87         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_BLOCK_COUNT;
88
89         file_info->flags=GNOME_VFS_FILE_FLAGS_LOCAL;
90         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_FLAGS;
91
92         if (FileAllInformationStruct->BasicInformation.LastAccessTime.QuadPart) {       /* it may be 0 if not set */
93                 errBOOLEAN=RtlTimeToSecondsSince1970(&FileAllInformationStruct->BasicInformation.LastAccessTime,&tmp_ULONG);
94                 g_assert(errBOOLEAN==TRUE);
95                 file_info->atime=tmp_ULONG;
96                 file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_ATIME;
97                 }
98
99         /* it may be 0 if not set */
100         if (FileAllInformationStruct->BasicInformation.LastWriteTime.QuadPart || FileAllInformationStruct->BasicInformation.ChangeTime.QuadPart) {
101                 errBOOLEAN=RtlTimeToSecondsSince1970(
102                                 /* take the more recent (==bigger) time: */
103                                 (FileAllInformationStruct->BasicInformation.LastWriteTime.QuadPart > FileAllInformationStruct->BasicInformation.ChangeTime.QuadPart
104                                                 ? &FileAllInformationStruct->BasicInformation.LastWriteTime : &FileAllInformationStruct->BasicInformation.ChangeTime),
105                                 &tmp_ULONG);
106                 g_assert(errBOOLEAN==TRUE);
107                 file_info->mtime=tmp_ULONG;
108                 file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_MTIME;
109                 }
110
111         if (FileAllInformationStruct->BasicInformation.CreationTime.QuadPart) { /* it may be 0 if not set */
112                 errBOOLEAN=RtlTimeToSecondsSince1970(&FileAllInformationStruct->BasicInformation.CreationTime,&tmp_ULONG);
113                 g_assert(errBOOLEAN==TRUE);
114                 file_info->ctime=tmp_ULONG;
115                 file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_CTIME;
116                 }
117
118         return GNOME_VFS_OK;
119 }
120
121
122 GnomeVFSResult captive_file_info_get(const gchar *pathname,GnomeVFSFileInfo *file_info)
123 {
124 NTSTATUS err;
125 IO_STATUS_BLOCK file_IoStatusBlock;
126 FILE_ALL_INFORMATION *FileAllInformationStruct;
127 GnomeVFSResult errvfsresult;
128 OBJECT_ATTRIBUTES file_ObjectAttributes;
129 HANDLE file_Handle;
130 char QueryFile_buf[sizeof(FILE_ALL_INFORMATION)
131                 +0x1000 /* max 'FileName' length, 255 should be enough */ * sizeof(WCHAR /* *FILE_ALL_INFORMATION.NameInformation.FileName */ )];
132
133         if (CAPTIVE_IS_SANDBOX_PARENT())
134                 return captive_sandbox_parent_file_info_get(pathname,file_info);
135
136         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
137         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
138
139         errvfsresult=captive_ObjectAttributes_init(pathname,&file_ObjectAttributes);
140         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
141         
142         /* open */
143         err=IoCreateFile(
144                         &file_Handle,   /* FileHandle */
145                         FILE_READ_ATTRIBUTES,   /* DesiredAccess */
146                         &file_ObjectAttributes, /* ObjectAttributes */
147                         &file_IoStatusBlock,    /* IoStatusBlock */
148                         NULL,   /* AllocationSize; ignored for open */
149                         FILE_ATTRIBUTE_NORMAL,  /* FileAttributes; ignored for open */
150                         FILE_SHARE_WRITE,       /* ShareAccess; 0 means exclusive */
151                         FILE_OPEN,      /* CreateDisposition */
152                         /* FILE_SYNCHRONOUS_IO_{,NON}ALERT: We need to allow W32 filesystem
153                                  * any waits to not to let it return STATUS_CANT_WAIT us.
154                                  * Alertability should have only effect on asynchronous events
155                                  * from KeWaitForSingleObject() by setting/clearing its parameter 'Alertable'.
156                                  */
157                         FILE_SYNCHRONOUS_IO_ALERT,      /* CreateOptions */
158                         NULL,   /* EaBuffer */
159                         0,      /* EaLength */
160                         CreateFileTypeNone,     /* CreateFileType */
161                         NULL,   /* ExtraCreateParameters */
162                         0);     /* Options */
163         g_free(file_ObjectAttributes.ObjectName);       /* left from captive_gnomevfs_uri_parent_init() */
164         g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(file_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
165         if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
166                 return errvfsresult;
167         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
168         g_return_val_if_fail(file_IoStatusBlock.Information==FILE_OPENED,GNOME_VFS_ERROR_GENERIC);
169
170         /* query */
171         FileAllInformationStruct=(void *)QueryFile_buf;
172         err=NtQueryInformationFile(
173                         file_Handle,    /* FileHandle */
174                         &file_IoStatusBlock,    /* IoStatusBlock */
175                         (gpointer)QueryFile_buf,        /* FileInformation */
176                         sizeof(QueryFile_buf)   /* Length */
177                                         -sizeof(*FileAllInformationStruct->NameInformation.FileName),   /* reserve space for 0-terminator */
178                         FileAllInformation);    /* FileInformationClass; =>FILE_ALL_INFORMATION */
179         if (!NT_SUCCESS(err)) {
180                 g_assert_not_reached();
181                 goto err_close;
182                 }
183
184         /* close */
185         err=NtClose(file_Handle);
186         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
187
188         /* process gathered info */
189         errvfsresult=FileAllInformationStruct_to_GnomeVFSFileInfo(file_info,FileAllInformationStruct,
190                         &file_IoStatusBlock);
191         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
192
193         return GNOME_VFS_OK;
194
195 err_close:
196         err=NtClose(file_Handle);
197         g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
198 /* err: */
199         g_return_val_if_reached(GNOME_VFS_ERROR_GENERIC);
200 }