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