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