source: trunk/third/gnome-vfs/libgnomevfs/gnome-vfs-seekable.c @ 18154

Revision 18154, 10.2 KB checked in by ghudson, 22 years ago (diff)
Work around Solaris #defines for truncate, tell, and stat.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* gnome-vfs-seekable.c - Emulation of seek / tell for non seekable filesystems.
3
4   Copyright (C) 1999 Free Software Foundation
5
6   The Gnome Library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Library General Public License as
8   published by the Free Software Foundation; either version 2 of the
9   License, or (at your option) any later version.
10
11   The Gnome Library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Library General Public License for more details.
15
16   You should have received a copy of the GNU Library General Public
17   License along with the Gnome Library; see the file COPYING.LIB.  If not,
18   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   Boston, MA 02111-1307, USA.
20
21   Author: Michael Meeks <michael@imaginator.com>
22*/
23
24/* TODO: Cancellation throughout!  */
25
26#include <config.h>
27#include "gnome-vfs-seekable.h"
28
29#include "gnome-vfs-private.h"
30#include "gnome-vfs.h"
31#include <glib.h>
32#include <stdio.h>
33#include <stdlib.h> /* for mkstemp */
34#include <string.h>
35#include <unistd.h> /* for close */
36
37static GnomeVFSResult   do_open         (GnomeVFSMethod *method,
38                                         GnomeVFSMethodHandle **method_handle,
39                                         GnomeVFSURI *uri,
40                                         GnomeVFSOpenMode mode,
41                                         GnomeVFSContext *context);
42static GnomeVFSResult   do_create       (GnomeVFSMethod *method,
43                                         GnomeVFSMethodHandle **method_handle,
44                                         GnomeVFSURI *uri,
45                                         GnomeVFSOpenMode mode,
46                                         gboolean exclusive,
47                                         guint perm,
48                                         GnomeVFSContext *context);
49static GnomeVFSResult   do_close        (GnomeVFSMethod *method,
50                                         GnomeVFSMethodHandle *method_handle,
51                                         GnomeVFSContext *context);
52static GnomeVFSResult   do_read         (GnomeVFSMethod *method,
53                                         GnomeVFSMethodHandle *method_handle,
54                                         gpointer buffer,
55                                         GnomeVFSFileSize num_bytes,
56                                         GnomeVFSFileSize *bytes_read,
57                                         GnomeVFSContext *context);
58static GnomeVFSResult   do_write        (GnomeVFSMethod *method,
59                                         GnomeVFSMethodHandle *method_handle,
60                                         gconstpointer buffer,
61                                         GnomeVFSFileSize num_bytes,
62                                         GnomeVFSFileSize *bytes_written,
63                                         GnomeVFSContext *context);
64static GnomeVFSResult   do_seek         (GnomeVFSMethod *method,
65                                         GnomeVFSMethodHandle *method_handle,
66                                         GnomeVFSSeekPosition whence,
67                                         GnomeVFSFileOffset offset,
68                                         GnomeVFSContext *context);
69static GnomeVFSResult   do_tell         (GnomeVFSMethod *method,
70                                         GnomeVFSMethodHandle *method_handle,
71                                         GnomeVFSFileOffset *offset_return);
72static GnomeVFSResult   do_truncate_handle      (GnomeVFSMethod *method,
73                                                 GnomeVFSMethodHandle *method_handle,
74                                                 GnomeVFSFileSize where,
75                                                 GnomeVFSContext *context);
76
77/* Our method_handle */
78typedef struct  {
79        /* Child chaining info */
80        GnomeVFSMethodHandle *child_handle;
81        GnomeVFSMethod      *child_method;
82
83        /* Housekeeping info */
84        GnomeVFSHandle       *tmp_file;
85        gchar                *tmp_uri;
86        GnomeVFSOpenMode      open_mode;
87        gboolean              dirty;
88
89        /* Each SeekableMethodHandle has a unique wrapper method */
90        GnomeVFSMethod      *wrapper_method;
91} SeekableMethodHandle;
92
93#define CHECK_IF_SUPPORTED(method, what)                \
94G_STMT_START{                                           \
95        if (!VFS_METHOD_HAS_FUNC(method, what)) \
96                return GNOME_VFS_ERROR_NOT_SUPPORTED;   \
97}G_STMT_END
98
99#define INVOKE_CHILD(result, method, what, params)      \
100G_STMT_START{                                           \
101        CHECK_IF_SUPPORTED (method->child_method, what);\
102        (result) = method->child_method->what params;   \
103}G_STMT_END
104
105#define CHECK_INIT(handle)                      \
106G_STMT_START{                                   \
107        if (!handle->tmp_file) {                \
108                GnomeVFSResult result;          \
109                result = init_seek (handle);    \
110                if (result != GNOME_VFS_OK)     \
111                        return result;          \
112        }                                       \
113}G_STMT_END
114
115#define BLK_SIZE 4096
116
117static GnomeVFSResult
118read_file (SeekableMethodHandle *mh)
119{
120        GnomeVFSResult   result;
121        guint8           buffer[BLK_SIZE];
122        GnomeVFSFileSize blk_read, blk_write;
123
124        g_return_val_if_fail (mh != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
125
126        do {
127                INVOKE_CHILD (result, mh, read, (mh->child_method, mh->child_handle, buffer, BLK_SIZE, &blk_read,
128                                                 NULL));
129                if (result != GNOME_VFS_OK)
130                        return result;
131                result = gnome_vfs_write (mh->tmp_file, buffer, blk_read, &blk_write);
132                if (result != GNOME_VFS_OK)
133                        return result;
134                if (blk_write != blk_read)
135                        return GNOME_VFS_ERROR_NO_SPACE;
136               
137        } while (blk_read > 0);
138        /* } while (blk_read == BLK_SIZE); */
139
140        result = gnome_vfs_seek (mh->tmp_file, GNOME_VFS_SEEK_START, 0);
141
142        return result;
143}
144
145static GnomeVFSResult
146write_file (SeekableMethodHandle *mh)
147{
148        GnomeVFSResult   result;
149        guint8           buffer[BLK_SIZE];
150        GnomeVFSFileSize blk_read, blk_write;
151
152        g_return_val_if_fail (mh != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
153
154        do {
155                result = gnome_vfs_read (mh->tmp_file, buffer, BLK_SIZE,
156                                         &blk_read);
157                if (result != GNOME_VFS_OK)
158                        return result;
159                INVOKE_CHILD (result, mh, write, (mh->child_method, mh->child_handle, buffer,
160                                                  blk_read, &blk_write, NULL));
161                if (result != GNOME_VFS_OK)
162                        return result;
163                if (blk_write != blk_read)
164                        return GNOME_VFS_ERROR_NO_SPACE;
165               
166        } while (blk_read == BLK_SIZE);
167
168        return GNOME_VFS_OK;
169}
170
171#undef  BLK_SIZE
172
173static GnomeVFSResult
174init_seek (SeekableMethodHandle *mh)
175{
176        GnomeVFSResult   result;
177        gchar            *stem;
178        gint             fd;
179
180        /* Create a temporary file name */
181        stem = g_strdup("/tmp/gnome-vfs-seekable-temp-XXXXXX"); /* template */
182        fd = mkstemp(stem);
183        if (fd < 0) {
184                g_free(stem);
185                return GNOME_VFS_ERROR_NO_SPACE;
186        }
187
188        mh->tmp_uri = g_strdup_printf ("file:%s", stem);
189        g_warning ("Opening temp seekable file '%s'", mh->tmp_uri);
190
191        close(fd);
192        g_free(stem);
193       
194        /* Open the file */
195        result = gnome_vfs_open (&mh->tmp_file, mh->tmp_uri,
196                                   GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE |
197                                   GNOME_VFS_OPEN_RANDOM);
198
199        if (result != GNOME_VFS_OK)
200                return result;
201
202        mh->dirty = FALSE;
203
204        if (mh->open_mode & GNOME_VFS_OPEN_READ)
205                return read_file (mh);
206        else
207                return GNOME_VFS_OK;
208}
209
210/* Athena hack to work around Solaris #define of "tell" */
211#undef tell
212
213GnomeVFSMethodHandle *
214gnome_vfs_seek_emulate (GnomeVFSURI *uri, GnomeVFSMethodHandle *child_handle,
215                        GnomeVFSOpenMode open_mode)
216{
217        GnomeVFSMethod      *m  = g_new (GnomeVFSMethod, 1);
218        SeekableMethodHandle *mh = g_new (SeekableMethodHandle, 1);
219
220        g_return_val_if_fail (m != NULL, NULL);
221        g_return_val_if_fail (mh != NULL, NULL);
222        g_return_val_if_fail (uri != NULL, NULL);
223        g_return_val_if_fail (uri->method != NULL, NULL);
224
225        memcpy (m, uri->method, uri->method->method_table_size);
226
227        /*
228         *  This subset of method contains those operations that we need
229         * to wrap in order to extract the neccessary information for
230         * seek / tell.
231         */
232        m->open     = do_open;
233        m->create   = do_create;
234        m->close    = do_close;
235        m->read     = do_read;
236        m->write    = do_write;
237        m->seek     = do_seek;
238        m->tell     = do_tell;
239        m->truncate_handle = do_truncate_handle;
240
241        mh->child_handle   = child_handle;
242        mh->child_method   = uri->method;
243        mh->open_mode      = open_mode;
244        mh->tmp_file       = NULL;
245        mh->tmp_uri        = NULL;
246        mh->wrapper_method = m;
247
248        uri->method        = m;
249
250        return (GnomeVFSMethodHandle *)mh;
251}
252
253static GnomeVFSResult
254do_open (GnomeVFSMethod *method,
255         GnomeVFSMethodHandle **method_handle,
256         GnomeVFSURI *uri,
257         GnomeVFSOpenMode mode,
258         GnomeVFSContext *context)
259{
260        g_warning ("FIXME bugzilla.eazel.com 1192: Unhandled re-open");
261        return GNOME_VFS_ERROR_NOT_SUPPORTED;
262}
263
264static GnomeVFSResult
265do_create (GnomeVFSMethod *method,
266           GnomeVFSMethodHandle **method_handle,
267           GnomeVFSURI *uri,
268           GnomeVFSOpenMode mode,
269           gboolean exclusive,
270           guint perm,
271           GnomeVFSContext *context)
272{
273        g_warning ("FIXME bugzilla.eazel.com 1192: Unhandled re-create");
274        return GNOME_VFS_ERROR_NOT_SUPPORTED;
275}
276
277static GnomeVFSResult
278do_close (GnomeVFSMethod *method,
279          GnomeVFSMethodHandle *method_handle,
280          GnomeVFSContext *context)
281{
282        GnomeVFSResult result;
283        SeekableMethodHandle *mh = (SeekableMethodHandle *)method_handle;
284
285        if ((mh->open_mode & GNOME_VFS_OPEN_WRITE) &&
286            mh->dirty)
287                write_file (mh);
288
289        result = gnome_vfs_close (mh->tmp_file);
290        mh->tmp_file = NULL;
291
292        if (mh->tmp_uri) {
293                if (result == GNOME_VFS_OK)
294                        result = gnome_vfs_unlink (mh->tmp_uri);
295                g_free (mh->tmp_uri);
296                mh->tmp_uri  = NULL;
297        }
298
299        INVOKE_CHILD (result, mh, close, (mh->child_method, mh->child_handle, NULL));
300
301        /* Cover your back. */
302        memset (mh->wrapper_method, 0xae, sizeof (GnomeVFSMethod));
303
304        g_free (mh->wrapper_method);
305        mh->wrapper_method = NULL;
306
307        g_free (mh);
308
309        return result;
310}
311
312static GnomeVFSResult
313do_read (GnomeVFSMethod *method,
314         GnomeVFSMethodHandle *method_handle,
315         gpointer buffer,
316         GnomeVFSFileSize num_bytes,
317         GnomeVFSFileSize *bytes_read,
318         GnomeVFSContext *context)
319{
320        SeekableMethodHandle *mh = (SeekableMethodHandle *)method_handle;
321        CHECK_INIT (mh);
322
323        return gnome_vfs_read (mh->tmp_file, buffer, num_bytes, bytes_read);
324}
325
326static GnomeVFSResult
327do_write (GnomeVFSMethod *method,
328          GnomeVFSMethodHandle *method_handle,
329          gconstpointer buffer,
330          GnomeVFSFileSize num_bytes,
331          GnomeVFSFileSize *bytes_written,
332          GnomeVFSContext *context)
333{
334        SeekableMethodHandle *mh = (SeekableMethodHandle *)method_handle;
335        CHECK_INIT (mh);
336        mh->dirty = TRUE;
337        return gnome_vfs_write (mh->tmp_file, buffer, num_bytes, bytes_written);
338}
339
340static GnomeVFSResult
341do_seek (GnomeVFSMethod *method,
342         GnomeVFSMethodHandle *method_handle,
343         GnomeVFSSeekPosition whence,
344         GnomeVFSFileOffset offset,
345         GnomeVFSContext *context)
346{
347        SeekableMethodHandle *mh = (SeekableMethodHandle *)method_handle;
348        CHECK_INIT (mh);
349       
350        return gnome_vfs_seek (mh->tmp_file, whence, offset);
351}
352
353static GnomeVFSResult
354do_tell (GnomeVFSMethod *method,
355         GnomeVFSMethodHandle *method_handle,
356         GnomeVFSFileOffset *offset_return)
357{
358        SeekableMethodHandle *mh = (SeekableMethodHandle *)method_handle;
359        CHECK_INIT (mh);
360
361        return gnome_vfs_tell (mh->tmp_file, offset_return);
362}
363
364static GnomeVFSResult
365do_truncate_handle (GnomeVFSMethod *method,
366                    GnomeVFSMethodHandle *method_handle,
367                    GnomeVFSFileSize where,
368                    GnomeVFSContext *context)
369{
370        SeekableMethodHandle *mh = (SeekableMethodHandle *)method_handle;
371        CHECK_INIT (mh);
372
373        g_warning ("FIXME bugzilla.eazel.com 1194: truncate needs implementing");
374        mh->dirty = TRUE;
375
376        return GNOME_VFS_ERROR_NOT_SUPPORTED;
377}
Note: See TracBrowser for help on using the repository browser.