Added missing includes to avoid warnings/errors.
[wine] / server / file.c
1 /*
2  * Server-side file management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <sys/errno.h>
13 #include <sys/stat.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <time.h>
17 #include <unistd.h>
18 #include <utime.h>
19
20 #include "winerror.h"
21 #include "winbase.h"
22 #include "server/thread.h"
23
24 struct file
25 {
26     struct object  obj;             /* object header */
27     struct file   *next;            /* next file in hashing list */
28     char          *name;            /* file name */
29     int            fd;              /* Unix file descriptor */
30     unsigned int   access;          /* file access (GENERIC_READ/WRITE) */
31     unsigned int   flags;           /* flags (FILE_FLAG_*) */
32     unsigned int   sharing;         /* file sharing mode */
33 };
34
35 #define NAME_HASH_SIZE 37
36
37 static struct file *file_hash[NAME_HASH_SIZE];
38
39 static void file_dump( struct object *obj, int verbose );
40 static int file_add_queue( struct object *obj, struct wait_queue_entry *entry );
41 static void file_remove_queue( struct object *obj, struct wait_queue_entry *entry );
42 static int file_signaled( struct object *obj, struct thread *thread );
43 static int file_get_read_fd( struct object *obj );
44 static int file_get_write_fd( struct object *obj );
45 static int file_flush( struct object *obj );
46 static int file_get_info( struct object *obj, struct get_file_info_reply *reply );
47 static void file_destroy( struct object *obj );
48
49 static const struct object_ops file_ops =
50 {
51     file_dump,
52     file_add_queue,
53     file_remove_queue,
54     file_signaled,
55     no_satisfied,
56     file_get_read_fd,
57     file_get_write_fd,
58     file_flush,
59     file_get_info,
60     file_destroy
61 };
62
63 static const struct select_ops select_ops =
64 {
65     default_select_event,
66     NULL   /* we never set a timeout on a file */
67 };
68
69
70 static int get_name_hash( const char *name )
71 {
72     int hash = 0;
73     while (*name) hash ^= *name++;
74     return hash % NAME_HASH_SIZE;
75 }
76
77 /* check if the desired access is possible without violating */
78 /* the sharing mode of other opens of the same file */
79 static int check_sharing( const char *name, int hash, unsigned int access,
80                           unsigned int sharing )
81 {
82     struct file *file;
83     unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
84     unsigned int existing_access = 0;
85
86     for (file = file_hash[hash]; file; file = file->next)
87     {
88         if (strcmp( file->name, name )) continue;
89         existing_sharing &= file->sharing;
90         existing_access |= file->access;
91     }
92     if ((access & GENERIC_READ) && !(existing_sharing & FILE_SHARE_READ)) return 0;
93     if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) return 0;
94     if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) return 0;
95     if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) return 0;
96     return 1;
97 }
98
99 struct object *create_file( int fd, const char *name, unsigned int access,
100                             unsigned int sharing, int create, unsigned int attrs )
101 {
102     struct file *file;
103     int hash = 0;
104
105     if (fd == -1)
106     {
107         int flags;
108         struct stat st;
109
110         if (!name)
111         {
112             SET_ERROR( ERROR_INVALID_PARAMETER );
113             return NULL;
114         }
115
116         /* check sharing mode */
117         hash = get_name_hash( name );
118         if (!check_sharing( name, hash, access, sharing ))
119         {
120             SET_ERROR( ERROR_SHARING_VIOLATION );
121             return NULL;
122         }
123
124         switch(create)
125         {
126         case CREATE_NEW:        flags = O_CREAT | O_EXCL; break;
127         case CREATE_ALWAYS:     flags = O_CREAT | O_TRUNC; break;
128         case OPEN_ALWAYS:       flags = O_CREAT; break;
129         case TRUNCATE_EXISTING: flags = O_TRUNC; break;
130         case OPEN_EXISTING:     flags = 0; break;
131         default:                SET_ERROR( ERROR_INVALID_PARAMETER ); return NULL;
132         }
133         switch(access & (GENERIC_READ | GENERIC_WRITE))
134         {
135         case 0: break;
136         case GENERIC_READ:  flags |= O_RDONLY; break;
137         case GENERIC_WRITE: flags |= O_WRONLY; break;
138         case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;
139         }
140
141         if ((fd = open( name, flags | O_NONBLOCK,
142                         (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666 )) == -1)
143         {
144             file_set_error();
145             return NULL;
146         }
147         /* Refuse to open a directory */
148         if (fstat( fd, &st ) == -1)
149         {
150             file_set_error();
151             close( fd );
152             return NULL;
153         }
154         if (S_ISDIR(st.st_mode))
155         {
156             SET_ERROR( ERROR_ACCESS_DENIED );
157             close( fd );
158             return NULL;
159         }            
160     }
161     else
162     {
163         if ((fd = dup(fd)) == -1)
164         {
165             file_set_error();
166             return NULL;
167         }
168     }
169
170     if (!(file = mem_alloc( sizeof(*file) )))
171     {
172         close( fd );
173         return NULL;
174     }
175     if (name)
176     {
177         if (!(file->name = mem_alloc( strlen(name) + 1 )))
178         {
179             close( fd );
180             free( file );
181             return NULL;
182         }
183         strcpy( file->name, name );
184         file->next = file_hash[hash];
185         file_hash[hash] = file;
186     }
187     else
188     {
189         file->name = NULL;
190         file->next = NULL;
191     }
192     init_object( &file->obj, &file_ops, NULL );
193     file->fd      = fd;
194     file->access  = access;
195     file->flags   = attrs;
196     file->sharing = sharing;
197     CLEAR_ERROR();
198     return &file->obj;
199 }
200
201 static void file_dump( struct object *obj, int verbose )
202 {
203     struct file *file = (struct file *)obj;
204     assert( obj->ops == &file_ops );
205     printf( "File fd=%d flags=%08x name='%s'\n",
206             file->fd, file->flags, file->name );
207 }
208
209 static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
210 {
211     struct file *file = (struct file *)obj;
212     assert( obj->ops == &file_ops );
213     if (!obj->head)  /* first on the queue */
214     {
215         if (!add_select_user( file->fd, READ_EVENT | WRITE_EVENT, &select_ops, file ))
216         {
217             SET_ERROR( ERROR_OUTOFMEMORY );
218             return 0;
219         }
220     }
221     add_queue( obj, entry );
222     return 1;
223 }
224
225 static void file_remove_queue( struct object *obj, struct wait_queue_entry *entry )
226 {
227     struct file *file = (struct file *)grab_object(obj);
228     assert( obj->ops == &file_ops );
229
230     remove_queue( obj, entry );
231     if (!obj->head)  /* last on the queue is gone */
232         remove_select_user( file->fd );
233     release_object( obj );
234 }
235
236 static int file_signaled( struct object *obj, struct thread *thread )
237 {
238     fd_set read_fds, write_fds;
239     struct timeval tv = { 0, 0 };
240
241     struct file *file = (struct file *)obj;
242     assert( obj->ops == &file_ops );
243
244     FD_ZERO( &read_fds );
245     FD_ZERO( &write_fds );
246     if (file->access & GENERIC_READ) FD_SET( file->fd, &read_fds );
247     if (file->access & GENERIC_WRITE) FD_SET( file->fd, &write_fds );
248     return select( file->fd + 1, &read_fds, &write_fds, NULL, &tv ) > 0;
249 }
250
251 static int file_get_read_fd( struct object *obj )
252 {
253     struct file *file = (struct file *)obj;
254     assert( obj->ops == &file_ops );
255     return dup( file->fd );
256 }
257
258 static int file_get_write_fd( struct object *obj )
259 {
260     struct file *file = (struct file *)obj;
261     assert( obj->ops == &file_ops );
262     return dup( file->fd );
263 }
264
265 static int file_flush( struct object *obj )
266 {
267     int ret;
268     struct file *file = (struct file *)grab_object(obj);
269     assert( obj->ops == &file_ops );
270
271     ret = (fsync( file->fd ) != -1);
272     if (!ret) file_set_error();
273     release_object( file );
274     return ret;
275 }
276
277 static int file_get_info( struct object *obj, struct get_file_info_reply *reply )
278 {
279     struct stat st;
280     struct file *file = (struct file *)obj;
281     assert( obj->ops == &file_ops );
282
283     if (fstat( file->fd, &st ) == -1)
284     {
285         file_set_error();
286         return 0;
287     }
288     if (S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) ||
289         S_ISSOCK(st.st_mode) || isatty(file->fd)) reply->type = FILE_TYPE_CHAR;
290     else reply->type = FILE_TYPE_DISK;
291     if (S_ISDIR(st.st_mode)) reply->attr = FILE_ATTRIBUTE_DIRECTORY;
292     else reply->attr = FILE_ATTRIBUTE_ARCHIVE;
293     if (!(st.st_mode & S_IWUSR)) reply->attr |= FILE_ATTRIBUTE_READONLY;
294     reply->access_time = st.st_atime;
295     reply->write_time  = st.st_mtime;
296     reply->size_high   = 0;
297     reply->size_low    = S_ISDIR(st.st_mode) ? 0 : st.st_size;
298     reply->links       = st.st_nlink;
299     reply->index_high  = st.st_dev;
300     reply->index_low   = st.st_ino;
301     reply->serial      = 0; /* FIXME */
302     return 1;
303 }
304
305 static void file_destroy( struct object *obj )
306 {
307     struct file *file = (struct file *)obj;
308     assert( obj->ops == &file_ops );
309
310     if (file->name)
311     {
312         /* remove it from the hashing list */
313         struct file **pptr = &file_hash[get_name_hash( file->name )];
314         while (*pptr && *pptr != file) pptr = &(*pptr)->next;
315         assert( *pptr );
316         *pptr = (*pptr)->next;
317         free( file->name );
318     }
319     close( file->fd );
320     free( file );
321 }
322
323 /* set the last error depending on errno */
324 void file_set_error(void)
325 {
326     switch (errno)
327     {
328     case EAGAIN:    SET_ERROR( ERROR_SHARING_VIOLATION ); break;
329     case EBADF:     SET_ERROR( ERROR_INVALID_HANDLE ); break;
330     case ENOSPC:    SET_ERROR( ERROR_HANDLE_DISK_FULL ); break;
331     case EACCES:
332     case EPERM:     SET_ERROR( ERROR_ACCESS_DENIED ); break;
333     case EROFS:     SET_ERROR( ERROR_WRITE_PROTECT ); break;
334     case EBUSY:     SET_ERROR( ERROR_LOCK_VIOLATION ); break;
335     case ENOENT:    SET_ERROR( ERROR_FILE_NOT_FOUND ); break;
336     case EISDIR:    SET_ERROR( ERROR_CANNOT_MAKE ); break;
337     case ENFILE:
338     case EMFILE:    SET_ERROR( ERROR_NO_MORE_FILES ); break;
339     case EEXIST:    SET_ERROR( ERROR_FILE_EXISTS ); break;
340     case EINVAL:    SET_ERROR( ERROR_INVALID_PARAMETER ); break;
341     case ESPIPE:    SET_ERROR( ERROR_SEEK ); break;
342     case ENOTEMPTY: SET_ERROR( ERROR_DIR_NOT_EMPTY ); break;
343     default:        perror("file_set_error"); SET_ERROR( ERROR_UNKNOWN ); break;
344     }
345 }
346
347 struct file *get_file_obj( struct process *process, int handle,
348                            unsigned int access )
349 {
350     return (struct file *)get_handle_obj( current->process, handle,
351                                           access, &file_ops );
352 }
353
354 int file_get_mmap_fd( struct file *file )
355 {
356     return dup( file->fd );
357 }
358
359 int set_file_pointer( int handle, int *low, int *high, int whence )
360 {
361     struct file *file;
362     int result;
363
364     if (*high)
365     {
366         fprintf( stderr, "set_file_pointer: offset > 4Gb not supported yet\n" );
367         SET_ERROR( ERROR_INVALID_PARAMETER );
368         return 0;
369     }
370
371     if (!(file = get_file_obj( current->process, handle, 0 )))
372         return 0;
373     if ((result = lseek( file->fd, *low, whence )) == -1)
374     {
375         /* Check for seek before start of file */
376         if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
377             SET_ERROR( ERROR_NEGATIVE_SEEK );
378         else
379             file_set_error();
380         release_object( file );
381         return 0;
382     }
383     *low = result;
384     release_object( file );
385     return 1;
386 }
387
388 int truncate_file( int handle )
389 {
390     struct file *file;
391     int result;
392
393     if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE )))
394         return 0;
395     if (((result = lseek( file->fd, 0, SEEK_CUR )) == -1) ||
396         (ftruncate( file->fd, result ) == -1))
397     {
398         file_set_error();
399         release_object( file );
400         return 0;
401     }
402     release_object( file );
403     return 1;
404     
405 }
406
407 int set_file_time( int handle, time_t access_time, time_t write_time )
408 {
409     struct file *file;
410     struct utimbuf utimbuf;
411
412     if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE )))
413         return 0;
414     if (!access_time || !write_time)
415     {
416         struct stat st;
417         if (stat( file->name, &st ) == -1) goto error;
418         if (!access_time) access_time = st.st_atime;
419         if (!write_time) write_time = st.st_mtime;
420     }
421     utimbuf.actime  = access_time;
422     utimbuf.modtime = write_time;
423     if (utime( file->name, &utimbuf ) == -1) goto error;
424     release_object( file );
425     return 1;
426  error:
427     file_set_error();
428     release_object( file );
429     return 0;
430 }
431
432 int file_lock( struct file *file, int offset_high, int offset_low,
433                int count_high, int count_low )
434 {
435     /* FIXME: implement this */
436     return 1;
437 }
438
439 int file_unlock( struct file *file, int offset_high, int offset_low,
440                  int count_high, int count_low )
441 {
442     /* FIXME: implement this */
443     return 1;
444 }