~james-w/+junk/fuse-ubuntu-upstream

« back to all changes in this revision

Viewing changes to lib/modules/iconv.c

  • Committer: James Westby
  • Date: 2008-05-16 12:59:17 UTC
  • Revision ID: jw+debian@jameswestby.net-20080516125917-tp1sifyaxglg2kjk
Tags: upstream-debian-2.7.2, upstream-ubuntu-2.7.2
Import upstream from fuse_2.7.2.orig.tar.gz

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
    fuse iconv module: file name charset conversion
3
 
    Copyright (C) 2007  Miklos Szeredi <miklos@szeredi.hu>
 
2
  fuse iconv module: file name charset conversion
 
3
  Copyright (C) 2007  Miklos Szeredi <miklos@szeredi.hu>
4
4
 
5
 
    This program can be distributed under the terms of the GNU LGPLv2.
6
 
    See the file COPYING.LIB
 
5
  This program can be distributed under the terms of the GNU LGPLv2.
 
6
  See the file COPYING.LIB
7
7
*/
8
8
 
9
9
#define FUSE_USE_VERSION 26
20
20
#include <langinfo.h>
21
21
 
22
22
struct iconv {
23
 
    struct fuse_fs *next;
24
 
    pthread_mutex_t lock;
25
 
    char *from_code;
26
 
    char *to_code;
27
 
    iconv_t tofs;
28
 
    iconv_t fromfs;
 
23
        struct fuse_fs *next;
 
24
        pthread_mutex_t lock;
 
25
        char *from_code;
 
26
        char *to_code;
 
27
        iconv_t tofs;
 
28
        iconv_t fromfs;
29
29
};
30
30
 
31
31
struct iconv_dh {
32
 
    struct iconv *ic;
33
 
    void *prev_buf;
34
 
    fuse_fill_dir_t prev_filler;
 
32
        struct iconv *ic;
 
33
        void *prev_buf;
 
34
        fuse_fill_dir_t prev_filler;
35
35
};
36
36
 
37
37
static struct iconv *iconv_get(void)
38
38
{
39
 
    return fuse_get_context()->private_data;
 
39
        return fuse_get_context()->private_data;
40
40
}
41
41
 
42
42
static int iconv_convpath(struct iconv *ic, const char *path, char **newpathp,
43
 
                          int fromfs)
 
43
                          int fromfs)
44
44
{
45
 
    size_t pathlen = strlen(path);
46
 
    size_t newpathlen = pathlen * 4;
47
 
    char *newpath = malloc(newpathlen + 1);
48
 
    size_t plen = newpathlen;
49
 
    char *p = newpath;
50
 
    size_t res;
51
 
    int err;
52
 
 
53
 
    if (!newpath)
54
 
        return -ENOMEM;
55
 
 
56
 
    pthread_mutex_lock(&ic->lock);
57
 
    do {
58
 
        res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path, &pathlen,
59
 
                    &p, &plen);
60
 
        if (res == (size_t) -1) {
61
 
            char *tmp;
62
 
            size_t inc;
63
 
 
64
 
            err = -EILSEQ;
65
 
            if (errno != E2BIG)
66
 
                goto err;
67
 
 
68
 
            inc = (pathlen + 1) * 4;
69
 
            newpathlen += inc;
70
 
            tmp = realloc(newpath, newpathlen + 1);
71
 
            err = -ENOMEM;
72
 
            if (!tmp)
73
 
                goto err;
74
 
 
75
 
            p = tmp + (p - newpath);
76
 
            plen += inc;
77
 
            newpath = tmp;
78
 
        }
79
 
    } while (res == (size_t) -1);
80
 
    pthread_mutex_unlock(&ic->lock);
81
 
    *p = '\0';
82
 
    *newpathp = newpath;
83
 
    return 0;
84
 
 
85
 
 err:
86
 
    iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL);
87
 
    pthread_mutex_unlock(&ic->lock);
88
 
    free(newpath);
89
 
    return err;
 
45
        size_t pathlen = strlen(path);
 
46
        size_t newpathlen = pathlen * 4;
 
47
        char *newpath = malloc(newpathlen + 1);
 
48
        size_t plen = newpathlen;
 
49
        char *p = newpath;
 
50
        size_t res;
 
51
        int err;
 
52
 
 
53
        if (!newpath)
 
54
                return -ENOMEM;
 
55
 
 
56
        pthread_mutex_lock(&ic->lock);
 
57
        do {
 
58
                res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path,
 
59
                            &pathlen, &p, &plen);
 
60
                if (res == (size_t) -1) {
 
61
                        char *tmp;
 
62
                        size_t inc;
 
63
 
 
64
                        err = -EILSEQ;
 
65
                        if (errno != E2BIG)
 
66
                                goto err;
 
67
 
 
68
                        inc = (pathlen + 1) * 4;
 
69
                        newpathlen += inc;
 
70
                        tmp = realloc(newpath, newpathlen + 1);
 
71
                        err = -ENOMEM;
 
72
                        if (!tmp)
 
73
                                goto err;
 
74
 
 
75
                        p = tmp + (p - newpath);
 
76
                        plen += inc;
 
77
                        newpath = tmp;
 
78
                }
 
79
        } while (res == (size_t) -1);
 
80
        pthread_mutex_unlock(&ic->lock);
 
81
        *p = '\0';
 
82
        *newpathp = newpath;
 
83
        return 0;
 
84
 
 
85
err:
 
86
        iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL);
 
87
        pthread_mutex_unlock(&ic->lock);
 
88
        free(newpath);
 
89
        return err;
90
90
}
91
91
 
92
92
static int iconv_getattr(const char *path, struct stat *stbuf)
93
93
{
94
 
    struct iconv *ic = iconv_get();
95
 
    char *newpath;
96
 
    int err = iconv_convpath(ic, path, &newpath, 0);
97
 
    if (!err) {
98
 
        err = fuse_fs_getattr(ic->next, newpath, stbuf);
99
 
        free(newpath);
100
 
    }
101
 
    return err;
 
94
        struct iconv *ic = iconv_get();
 
95
        char *newpath;
 
96
        int err = iconv_convpath(ic, path, &newpath, 0);
 
97
        if (!err) {
 
98
                err = fuse_fs_getattr(ic->next, newpath, stbuf);
 
99
                free(newpath);
 
100
        }
 
101
        return err;
102
102
}
103
103
 
104
104
static int iconv_fgetattr(const char *path, struct stat *stbuf,
105
 
                          struct fuse_file_info *fi)
 
105
                          struct fuse_file_info *fi)
106
106
{
107
 
    struct iconv *ic = iconv_get();
108
 
    char *newpath;
109
 
    int err = iconv_convpath(ic, path, &newpath, 0);
110
 
    if (!err) {
111
 
        err = fuse_fs_fgetattr(ic->next, newpath, stbuf, fi);
112
 
        free(newpath);
113
 
    }
114
 
    return err;
 
107
        struct iconv *ic = iconv_get();
 
108
        char *newpath;
 
109
        int err = iconv_convpath(ic, path, &newpath, 0);
 
110
        if (!err) {
 
111
                err = fuse_fs_fgetattr(ic->next, newpath, stbuf, fi);
 
112
                free(newpath);
 
113
        }
 
114
        return err;
115
115
}
116
116
 
117
117
static int iconv_access(const char *path, int mask)
118
118
{
119
 
    struct iconv *ic = iconv_get();
120
 
    char *newpath;
121
 
    int err = iconv_convpath(ic, path, &newpath, 0);
122
 
    if (!err) {
123
 
        err = fuse_fs_access(ic->next, newpath, mask);
124
 
        free(newpath);
125
 
    }
126
 
    return err;
 
119
        struct iconv *ic = iconv_get();
 
120
        char *newpath;
 
121
        int err = iconv_convpath(ic, path, &newpath, 0);
 
122
        if (!err) {
 
123
                err = fuse_fs_access(ic->next, newpath, mask);
 
124
                free(newpath);
 
125
        }
 
126
        return err;
127
127
}
128
128
 
129
129
static int iconv_readlink(const char *path, char *buf, size_t size)
130
130
{
131
 
    struct iconv *ic = iconv_get();
132
 
    char *newpath;
133
 
    int err = iconv_convpath(ic, path, &newpath, 0);
134
 
    if (!err) {
135
 
        err = fuse_fs_readlink(ic->next, newpath, buf, size);
136
 
        if (!err) {
137
 
            char *newlink;
138
 
            err = iconv_convpath(ic, buf, &newlink, 1);
139
 
            if (!err) {
140
 
                strncpy(buf, newlink, size - 1);
141
 
                buf[size - 1] = '\0';
142
 
                free(newlink);
143
 
            }
144
 
        }
145
 
        free(newpath);
146
 
    }
147
 
    return err;
 
131
        struct iconv *ic = iconv_get();
 
132
        char *newpath;
 
133
        int err = iconv_convpath(ic, path, &newpath, 0);
 
134
        if (!err) {
 
135
                err = fuse_fs_readlink(ic->next, newpath, buf, size);
 
136
                if (!err) {
 
137
                        char *newlink;
 
138
                        err = iconv_convpath(ic, buf, &newlink, 1);
 
139
                        if (!err) {
 
140
                                strncpy(buf, newlink, size - 1);
 
141
                                buf[size - 1] = '\0';
 
142
                                free(newlink);
 
143
                        }
 
144
                }
 
145
                free(newpath);
 
146
        }
 
147
        return err;
148
148
}
149
149
 
150
150
static int iconv_opendir(const char *path, struct fuse_file_info *fi)
151
151
{
152
 
    struct iconv *ic = iconv_get();
153
 
    char *newpath;
154
 
    int err = iconv_convpath(ic, path, &newpath, 0);
155
 
    if (!err) {
156
 
        err = fuse_fs_opendir(ic->next, newpath, fi);
157
 
        free(newpath);
158
 
    }
159
 
    return err;
 
152
        struct iconv *ic = iconv_get();
 
153
        char *newpath;
 
154
        int err = iconv_convpath(ic, path, &newpath, 0);
 
155
        if (!err) {
 
156
                err = fuse_fs_opendir(ic->next, newpath, fi);
 
157
                free(newpath);
 
158
        }
 
159
        return err;
160
160
}
161
161
 
162
162
static int iconv_dir_fill(void *buf, const char *name,
163
 
                          const struct stat *stbuf, off_t off)
 
163
                          const struct stat *stbuf, off_t off)
164
164
{
165
 
    struct iconv_dh *dh = buf;
166
 
    char *newname;
167
 
    int res = 0;
168
 
    if (iconv_convpath(dh->ic, name, &newname, 1) == 0) {
169
 
        res = dh->prev_filler(dh->prev_buf, newname, stbuf, off);
170
 
        free(newname);
171
 
    }
172
 
    return res;
 
165
        struct iconv_dh *dh = buf;
 
166
        char *newname;
 
167
        int res = 0;
 
168
        if (iconv_convpath(dh->ic, name, &newname, 1) == 0) {
 
169
                res = dh->prev_filler(dh->prev_buf, newname, stbuf, off);
 
170
                free(newname);
 
171
        }
 
172
        return res;
173
173
}
174
174
 
175
175
static int iconv_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
176
 
                         off_t offset, struct fuse_file_info *fi)
 
176
                         off_t offset, struct fuse_file_info *fi)
177
177
{
178
 
    struct iconv *ic = iconv_get();
179
 
    char *newpath;
180
 
    int err = iconv_convpath(ic, path, &newpath, 0);
181
 
    if (!err) {
182
 
        struct iconv_dh dh;
183
 
        dh.ic = ic;
184
 
        dh.prev_buf = buf;
185
 
        dh.prev_filler = filler;
186
 
        err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill, offset,
187
 
                              fi);
188
 
        free(newpath);
189
 
    }
190
 
    return err;
 
178
        struct iconv *ic = iconv_get();
 
179
        char *newpath;
 
180
        int err = iconv_convpath(ic, path, &newpath, 0);
 
181
        if (!err) {
 
182
                struct iconv_dh dh;
 
183
                dh.ic = ic;
 
184
                dh.prev_buf = buf;
 
185
                dh.prev_filler = filler;
 
186
                err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill,
 
187
                                      offset, fi);
 
188
                free(newpath);
 
189
        }
 
190
        return err;
191
191
}
192
192
 
193
193
static int iconv_releasedir(const char *path, struct fuse_file_info *fi)
194
194
{
195
 
    struct iconv *ic = iconv_get();
196
 
    char *newpath;
197
 
    int err = iconv_convpath(ic, path, &newpath, 0);
198
 
    if (!err) {
199
 
        err = fuse_fs_releasedir(ic->next, newpath, fi);
200
 
        free(newpath);
201
 
    }
202
 
    return err;
 
195
        struct iconv *ic = iconv_get();
 
196
        char *newpath;
 
197
        int err = iconv_convpath(ic, path, &newpath, 0);
 
198
        if (!err) {
 
199
                err = fuse_fs_releasedir(ic->next, newpath, fi);
 
200
                free(newpath);
 
201
        }
 
202
        return err;
203
203
}
204
204
 
205
205
static int iconv_mknod(const char *path, mode_t mode, dev_t rdev)
206
206
{
207
 
    struct iconv *ic = iconv_get();
208
 
    char *newpath;
209
 
    int err = iconv_convpath(ic, path, &newpath, 0);
210
 
    if (!err) {
211
 
        err = fuse_fs_mknod(ic->next, newpath, mode, rdev);
212
 
        free(newpath);
213
 
    }
214
 
    return err;
 
207
        struct iconv *ic = iconv_get();
 
208
        char *newpath;
 
209
        int err = iconv_convpath(ic, path, &newpath, 0);
 
210
        if (!err) {
 
211
                err = fuse_fs_mknod(ic->next, newpath, mode, rdev);
 
212
                free(newpath);
 
213
        }
 
214
        return err;
215
215
}
216
216
 
217
217
static int iconv_mkdir(const char *path, mode_t mode)
218
218
{
219
 
    struct iconv *ic = iconv_get();
220
 
    char *newpath;
221
 
    int err = iconv_convpath(ic, path, &newpath, 0);
222
 
    if (!err) {
223
 
        err = fuse_fs_mkdir(ic->next, newpath, mode);
224
 
        free(newpath);
225
 
    }
226
 
    return err;
 
219
        struct iconv *ic = iconv_get();
 
220
        char *newpath;
 
221
        int err = iconv_convpath(ic, path, &newpath, 0);
 
222
        if (!err) {
 
223
                err = fuse_fs_mkdir(ic->next, newpath, mode);
 
224
                free(newpath);
 
225
        }
 
226
        return err;
227
227
}
228
228
 
229
229
static int iconv_unlink(const char *path)
230
230
{
231
 
    struct iconv *ic = iconv_get();
232
 
    char *newpath;
233
 
    int err = iconv_convpath(ic, path, &newpath, 0);
234
 
    if (!err) {
235
 
        err = fuse_fs_unlink(ic->next, newpath);
236
 
        free(newpath);
237
 
    }
238
 
    return err;
 
231
        struct iconv *ic = iconv_get();
 
232
        char *newpath;
 
233
        int err = iconv_convpath(ic, path, &newpath, 0);
 
234
        if (!err) {
 
235
                err = fuse_fs_unlink(ic->next, newpath);
 
236
                free(newpath);
 
237
        }
 
238
        return err;
239
239
}
240
240
 
241
241
static int iconv_rmdir(const char *path)
242
242
{
243
 
    struct iconv *ic = iconv_get();
244
 
    char *newpath;
245
 
    int err = iconv_convpath(ic, path, &newpath, 0);
246
 
    if (!err) {
247
 
        err = fuse_fs_rmdir(ic->next, newpath);
248
 
        free(newpath);
249
 
    }
250
 
    return err;
 
243
        struct iconv *ic = iconv_get();
 
244
        char *newpath;
 
245
        int err = iconv_convpath(ic, path, &newpath, 0);
 
246
        if (!err) {
 
247
                err = fuse_fs_rmdir(ic->next, newpath);
 
248
                free(newpath);
 
249
        }
 
250
        return err;
251
251
}
252
252
 
253
253
static int iconv_symlink(const char *from, const char *to)
254
254
{
255
 
    struct iconv *ic = iconv_get();
256
 
    char *newfrom;
257
 
    char *newto;
258
 
    int err = iconv_convpath(ic, from, &newfrom, 0);
259
 
    if (!err) {
260
 
        err = iconv_convpath(ic, to, &newto, 0);
261
 
        if (!err) {
262
 
            err = fuse_fs_symlink(ic->next, newfrom, newto);
263
 
            free(newto);
264
 
        }
265
 
        free(newfrom);
266
 
    }
267
 
    return err;
 
255
        struct iconv *ic = iconv_get();
 
256
        char *newfrom;
 
257
        char *newto;
 
258
        int err = iconv_convpath(ic, from, &newfrom, 0);
 
259
        if (!err) {
 
260
                err = iconv_convpath(ic, to, &newto, 0);
 
261
                if (!err) {
 
262
                        err = fuse_fs_symlink(ic->next, newfrom, newto);
 
263
                        free(newto);
 
264
                }
 
265
                free(newfrom);
 
266
        }
 
267
        return err;
268
268
}
269
269
 
270
270
static int iconv_rename(const char *from, const char *to)
271
271
{
272
 
    struct iconv *ic = iconv_get();
273
 
    char *newfrom;
274
 
    char *newto;
275
 
    int err = iconv_convpath(ic, from, &newfrom, 0);
276
 
    if (!err) {
277
 
        err = iconv_convpath(ic, to, &newto, 0);
278
 
        if (!err) {
279
 
            err = fuse_fs_rename(ic->next, newfrom, newto);
280
 
            free(newto);
281
 
        }
282
 
        free(newfrom);
283
 
    }
284
 
    return err;
 
272
        struct iconv *ic = iconv_get();
 
273
        char *newfrom;
 
274
        char *newto;
 
275
        int err = iconv_convpath(ic, from, &newfrom, 0);
 
276
        if (!err) {
 
277
                err = iconv_convpath(ic, to, &newto, 0);
 
278
                if (!err) {
 
279
                        err = fuse_fs_rename(ic->next, newfrom, newto);
 
280
                        free(newto);
 
281
                }
 
282
                free(newfrom);
 
283
        }
 
284
        return err;
285
285
}
286
286
 
287
287
static int iconv_link(const char *from, const char *to)
288
288
{
289
 
    struct iconv *ic = iconv_get();
290
 
    char *newfrom;
291
 
    char *newto;
292
 
    int err = iconv_convpath(ic, from, &newfrom, 0);
293
 
    if (!err) {
294
 
        err = iconv_convpath(ic, to, &newto, 0);
295
 
        if (!err) {
296
 
            err = fuse_fs_link(ic->next, newfrom, newto);
297
 
            free(newto);
298
 
        }
299
 
        free(newfrom);
300
 
    }
301
 
    return err;
 
289
        struct iconv *ic = iconv_get();
 
290
        char *newfrom;
 
291
        char *newto;
 
292
        int err = iconv_convpath(ic, from, &newfrom, 0);
 
293
        if (!err) {
 
294
                err = iconv_convpath(ic, to, &newto, 0);
 
295
                if (!err) {
 
296
                        err = fuse_fs_link(ic->next, newfrom, newto);
 
297
                        free(newto);
 
298
                }
 
299
                free(newfrom);
 
300
        }
 
301
        return err;
302
302
}
303
303
 
304
304
static int iconv_chmod(const char *path, mode_t mode)
305
305
{
306
 
    struct iconv *ic = iconv_get();
307
 
    char *newpath;
308
 
    int err = iconv_convpath(ic, path, &newpath, 0);
309
 
    if (!err) {
310
 
        err = fuse_fs_chmod(ic->next, newpath, mode);
311
 
        free(newpath);
312
 
    }
313
 
    return err;
 
306
        struct iconv *ic = iconv_get();
 
307
        char *newpath;
 
308
        int err = iconv_convpath(ic, path, &newpath, 0);
 
309
        if (!err) {
 
310
                err = fuse_fs_chmod(ic->next, newpath, mode);
 
311
                free(newpath);
 
312
        }
 
313
        return err;
314
314
}
315
315
 
316
316
static int iconv_chown(const char *path, uid_t uid, gid_t gid)
317
317
{
318
 
    struct iconv *ic = iconv_get();
319
 
    char *newpath;
320
 
    int err = iconv_convpath(ic, path, &newpath, 0);
321
 
    if (!err) {
322
 
        err = fuse_fs_chown(ic->next, newpath, uid, gid);
323
 
        free(newpath);
324
 
    }
325
 
    return err;
 
318
        struct iconv *ic = iconv_get();
 
319
        char *newpath;
 
320
        int err = iconv_convpath(ic, path, &newpath, 0);
 
321
        if (!err) {
 
322
                err = fuse_fs_chown(ic->next, newpath, uid, gid);
 
323
                free(newpath);
 
324
        }
 
325
        return err;
326
326
}
327
327
 
328
328
static int iconv_truncate(const char *path, off_t size)
329
329
{
330
 
    struct iconv *ic = iconv_get();
331
 
    char *newpath;
332
 
    int err = iconv_convpath(ic, path, &newpath, 0);
333
 
    if (!err) {
334
 
        err = fuse_fs_truncate(ic->next, newpath, size);
335
 
        free(newpath);
336
 
    }
337
 
    return err;
 
330
        struct iconv *ic = iconv_get();
 
331
        char *newpath;
 
332
        int err = iconv_convpath(ic, path, &newpath, 0);
 
333
        if (!err) {
 
334
                err = fuse_fs_truncate(ic->next, newpath, size);
 
335
                free(newpath);
 
336
        }
 
337
        return err;
338
338
}
339
339
 
340
340
static int iconv_ftruncate(const char *path, off_t size,
341
 
                           struct fuse_file_info *fi)
 
341
                           struct fuse_file_info *fi)
342
342
{
343
 
    struct iconv *ic = iconv_get();
344
 
    char *newpath;
345
 
    int err = iconv_convpath(ic, path, &newpath, 0);
346
 
    if (!err) {
347
 
        err = fuse_fs_ftruncate(ic->next, newpath, size, fi);
348
 
        free(newpath);
349
 
    }
350
 
    return err;
 
343
        struct iconv *ic = iconv_get();
 
344
        char *newpath;
 
345
        int err = iconv_convpath(ic, path, &newpath, 0);
 
346
        if (!err) {
 
347
                err = fuse_fs_ftruncate(ic->next, newpath, size, fi);
 
348
                free(newpath);
 
349
        }
 
350
        return err;
351
351
}
352
352
 
353
353
static int iconv_utimens(const char *path, const struct timespec ts[2])
354
354
{
355
 
    struct iconv *ic = iconv_get();
356
 
    char *newpath;
357
 
    int err = iconv_convpath(ic, path, &newpath, 0);
358
 
    if (!err) {
359
 
        err = fuse_fs_utimens(ic->next, newpath, ts);
360
 
        free(newpath);
361
 
    }
362
 
    return err;
 
355
        struct iconv *ic = iconv_get();
 
356
        char *newpath;
 
357
        int err = iconv_convpath(ic, path, &newpath, 0);
 
358
        if (!err) {
 
359
                err = fuse_fs_utimens(ic->next, newpath, ts);
 
360
                free(newpath);
 
361
        }
 
362
        return err;
363
363
}
364
364
 
365
365
static int iconv_create(const char *path, mode_t mode,
366
 
                        struct fuse_file_info *fi)
 
366
                        struct fuse_file_info *fi)
367
367
{
368
 
    struct iconv *ic = iconv_get();
369
 
    char *newpath;
370
 
    int err = iconv_convpath(ic, path, &newpath, 0);
371
 
    if (!err) {
372
 
        err = fuse_fs_create(ic->next, newpath, mode, fi);
373
 
        free(newpath);
374
 
    }
375
 
    return err;
 
368
        struct iconv *ic = iconv_get();
 
369
        char *newpath;
 
370
        int err = iconv_convpath(ic, path, &newpath, 0);
 
371
        if (!err) {
 
372
                err = fuse_fs_create(ic->next, newpath, mode, fi);
 
373
                free(newpath);
 
374
        }
 
375
        return err;
376
376
}
377
377
 
378
378
static int iconv_open_file(const char *path, struct fuse_file_info *fi)
379
379
{
380
 
    struct iconv *ic = iconv_get();
381
 
    char *newpath;
382
 
    int err = iconv_convpath(ic, path, &newpath, 0);
383
 
    if (!err) {
384
 
        err = fuse_fs_open(ic->next, newpath, fi);
385
 
        free(newpath);
386
 
    }
387
 
    return err;
 
380
        struct iconv *ic = iconv_get();
 
381
        char *newpath;
 
382
        int err = iconv_convpath(ic, path, &newpath, 0);
 
383
        if (!err) {
 
384
                err = fuse_fs_open(ic->next, newpath, fi);
 
385
                free(newpath);
 
386
        }
 
387
        return err;
388
388
}
389
389
 
390
390
static int iconv_read(const char *path, char *buf, size_t size, off_t offset,
391
 
                    struct fuse_file_info *fi)
 
391
                      struct fuse_file_info *fi)
392
392
{
393
 
    struct iconv *ic = iconv_get();
394
 
    char *newpath;
395
 
    int err = iconv_convpath(ic, path, &newpath, 0);
396
 
    if (!err) {
397
 
        err = fuse_fs_read(ic->next, newpath, buf, size, offset, fi);
398
 
        free(newpath);
399
 
    }
400
 
    return err;
 
393
        struct iconv *ic = iconv_get();
 
394
        char *newpath;
 
395
        int err = iconv_convpath(ic, path, &newpath, 0);
 
396
        if (!err) {
 
397
                err = fuse_fs_read(ic->next, newpath, buf, size, offset, fi);
 
398
                free(newpath);
 
399
        }
 
400
        return err;
401
401
}
402
402
 
403
403
static int iconv_write(const char *path, const char *buf, size_t size,
404
 
                       off_t offset, struct fuse_file_info *fi)
 
404
                       off_t offset, struct fuse_file_info *fi)
405
405
{
406
 
    struct iconv *ic = iconv_get();
407
 
    char *newpath;
408
 
    int err = iconv_convpath(ic, path, &newpath, 0);
409
 
    if (!err) {
410
 
        err = fuse_fs_write(ic->next, newpath, buf, size, offset, fi);
411
 
        free(newpath);
412
 
    }
413
 
    return err;
 
406
        struct iconv *ic = iconv_get();
 
407
        char *newpath;
 
408
        int err = iconv_convpath(ic, path, &newpath, 0);
 
409
        if (!err) {
 
410
                err = fuse_fs_write(ic->next, newpath, buf, size, offset, fi);
 
411
                free(newpath);
 
412
        }
 
413
        return err;
414
414
}
415
415
 
416
416
static int iconv_statfs(const char *path, struct statvfs *stbuf)
417
417
{
418
 
    struct iconv *ic = iconv_get();
419
 
    char *newpath;
420
 
    int err = iconv_convpath(ic, path, &newpath, 0);
421
 
    if (!err) {
422
 
        err = fuse_fs_statfs(ic->next, newpath, stbuf);
423
 
        free(newpath);
424
 
    }
425
 
    return err;
 
418
        struct iconv *ic = iconv_get();
 
419
        char *newpath;
 
420
        int err = iconv_convpath(ic, path, &newpath, 0);
 
421
        if (!err) {
 
422
                err = fuse_fs_statfs(ic->next, newpath, stbuf);
 
423
                free(newpath);
 
424
        }
 
425
        return err;
426
426
}
427
427
 
428
428
static int iconv_flush(const char *path, struct fuse_file_info *fi)
429
429
{
430
 
    struct iconv *ic = iconv_get();
431
 
    char *newpath;
432
 
    int err = iconv_convpath(ic, path, &newpath, 0);
433
 
    if (!err) {
434
 
        err = fuse_fs_flush(ic->next, newpath, fi);
435
 
        free(newpath);
436
 
    }
437
 
    return err;
 
430
        struct iconv *ic = iconv_get();
 
431
        char *newpath;
 
432
        int err = iconv_convpath(ic, path, &newpath, 0);
 
433
        if (!err) {
 
434
                err = fuse_fs_flush(ic->next, newpath, fi);
 
435
                free(newpath);
 
436
        }
 
437
        return err;
438
438
}
439
439
 
440
440
static int iconv_release(const char *path, struct fuse_file_info *fi)
441
441
{
442
 
    struct iconv *ic = iconv_get();
443
 
    char *newpath;
444
 
    int err = iconv_convpath(ic, path, &newpath, 0);
445
 
    if (!err) {
446
 
        err = fuse_fs_release(ic->next, newpath, fi);
447
 
        free(newpath);
448
 
    }
449
 
    return err;
 
442
        struct iconv *ic = iconv_get();
 
443
        char *newpath;
 
444
        int err = iconv_convpath(ic, path, &newpath, 0);
 
445
        if (!err) {
 
446
                err = fuse_fs_release(ic->next, newpath, fi);
 
447
                free(newpath);
 
448
        }
 
449
        return err;
450
450
}
451
451
 
452
452
static int iconv_fsync(const char *path, int isdatasync,
453
 
                       struct fuse_file_info *fi)
 
453
                       struct fuse_file_info *fi)
454
454
{
455
 
    struct iconv *ic = iconv_get();
456
 
    char *newpath;
457
 
    int err = iconv_convpath(ic, path, &newpath, 0);
458
 
    if (!err) {
459
 
        err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi);
460
 
        free(newpath);
461
 
    }
462
 
    return err;
 
455
        struct iconv *ic = iconv_get();
 
456
        char *newpath;
 
457
        int err = iconv_convpath(ic, path, &newpath, 0);
 
458
        if (!err) {
 
459
                err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi);
 
460
                free(newpath);
 
461
        }
 
462
        return err;
463
463
}
464
464
 
465
465
static int iconv_fsyncdir(const char *path, int isdatasync,
466
 
                          struct fuse_file_info *fi)
 
466
                          struct fuse_file_info *fi)
467
467
{
468
 
    struct iconv *ic = iconv_get();
469
 
    char *newpath;
470
 
    int err = iconv_convpath(ic, path, &newpath, 0);
471
 
    if (!err) {
472
 
        err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi);
473
 
        free(newpath);
474
 
    }
475
 
    return err;
 
468
        struct iconv *ic = iconv_get();
 
469
        char *newpath;
 
470
        int err = iconv_convpath(ic, path, &newpath, 0);
 
471
        if (!err) {
 
472
                err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi);
 
473
                free(newpath);
 
474
        }
 
475
        return err;
476
476
}
477
477
 
478
478
static int iconv_setxattr(const char *path, const char *name,
479
 
                          const char *value, size_t size, int flags)
 
479
                          const char *value, size_t size, int flags)
480
480
{
481
 
    struct iconv *ic = iconv_get();
482
 
    char *newpath;
483
 
    int err = iconv_convpath(ic, path, &newpath, 0);
484
 
    if (!err) {
485
 
        err = fuse_fs_setxattr(ic->next, newpath, name, value, size, flags);
486
 
        free(newpath);
487
 
    }
488
 
    return err;
 
481
        struct iconv *ic = iconv_get();
 
482
        char *newpath;
 
483
        int err = iconv_convpath(ic, path, &newpath, 0);
 
484
        if (!err) {
 
485
                err = fuse_fs_setxattr(ic->next, newpath, name, value, size,
 
486
                                       flags);
 
487
                free(newpath);
 
488
        }
 
489
        return err;
489
490
}
490
491
 
491
492
static int iconv_getxattr(const char *path, const char *name, char *value,
492
 
                          size_t size)
 
493
                          size_t size)
493
494
{
494
 
    struct iconv *ic = iconv_get();
495
 
    char *newpath;
496
 
    int err = iconv_convpath(ic, path, &newpath, 0);
497
 
    if (!err) {
498
 
        err = fuse_fs_getxattr(ic->next, newpath, name, value, size);
499
 
        free(newpath);
500
 
    }
501
 
    return err;
 
495
        struct iconv *ic = iconv_get();
 
496
        char *newpath;
 
497
        int err = iconv_convpath(ic, path, &newpath, 0);
 
498
        if (!err) {
 
499
                err = fuse_fs_getxattr(ic->next, newpath, name, value, size);
 
500
                free(newpath);
 
501
        }
 
502
        return err;
502
503
}
503
504
 
504
505
static int iconv_listxattr(const char *path, char *list, size_t size)
505
506
{
506
 
    struct iconv *ic = iconv_get();
507
 
    char *newpath;
508
 
    int err = iconv_convpath(ic, path, &newpath, 0);
509
 
    if (!err) {
510
 
        err = fuse_fs_listxattr(ic->next, newpath, list, size);
511
 
        free(newpath);
512
 
    }
513
 
    return err;
 
507
        struct iconv *ic = iconv_get();
 
508
        char *newpath;
 
509
        int err = iconv_convpath(ic, path, &newpath, 0);
 
510
        if (!err) {
 
511
                err = fuse_fs_listxattr(ic->next, newpath, list, size);
 
512
                free(newpath);
 
513
        }
 
514
        return err;
514
515
}
515
516
 
516
517
static int iconv_removexattr(const char *path, const char *name)
517
518
{
518
 
    struct iconv *ic = iconv_get();
519
 
    char *newpath;
520
 
    int err = iconv_convpath(ic, path, &newpath, 0);
521
 
    if (!err) {
522
 
        err = fuse_fs_removexattr(ic->next, newpath, name);
523
 
        free(newpath);
524
 
    }
525
 
    return err;
 
519
        struct iconv *ic = iconv_get();
 
520
        char *newpath;
 
521
        int err = iconv_convpath(ic, path, &newpath, 0);
 
522
        if (!err) {
 
523
                err = fuse_fs_removexattr(ic->next, newpath, name);
 
524
                free(newpath);
 
525
        }
 
526
        return err;
526
527
}
527
528
 
528
529
static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd,
529
 
                      struct flock *lock)
 
530
                      struct flock *lock)
530
531
{
531
 
    struct iconv *ic = iconv_get();
532
 
    char *newpath;
533
 
    int err = iconv_convpath(ic, path, &newpath, 0);
534
 
    if (!err) {
535
 
        err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock);
536
 
        free(newpath);
537
 
    }
538
 
    return err;
 
532
        struct iconv *ic = iconv_get();
 
533
        char *newpath;
 
534
        int err = iconv_convpath(ic, path, &newpath, 0);
 
535
        if (!err) {
 
536
                err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock);
 
537
                free(newpath);
 
538
        }
 
539
        return err;
539
540
}
540
541
 
541
542
static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx)
542
543
{
543
 
    struct iconv *ic = iconv_get();
544
 
    char *newpath;
545
 
    int err = iconv_convpath(ic, path, &newpath, 0);
546
 
    if (!err) {
547
 
        err = fuse_fs_bmap(ic->next, newpath, blocksize, idx);
548
 
        free(newpath);
549
 
    }
550
 
    return err;
 
544
        struct iconv *ic = iconv_get();
 
545
        char *newpath;
 
546
        int err = iconv_convpath(ic, path, &newpath, 0);
 
547
        if (!err) {
 
548
                err = fuse_fs_bmap(ic->next, newpath, blocksize, idx);
 
549
                free(newpath);
 
550
        }
 
551
        return err;
551
552
}
552
553
 
553
554
static void *iconv_init(struct fuse_conn_info *conn)
554
555
{
555
 
    struct iconv *ic = iconv_get();
556
 
    fuse_fs_init(ic->next, conn);
557
 
    return ic;
 
556
        struct iconv *ic = iconv_get();
 
557
        fuse_fs_init(ic->next, conn);
 
558
        return ic;
558
559
}
559
560
 
560
561
static void iconv_destroy(void *data)
561
562
{
562
 
    struct iconv *ic = data;
563
 
    fuse_fs_destroy(ic->next);
564
 
    iconv_close(ic->tofs);
565
 
    iconv_close(ic->fromfs);
566
 
    pthread_mutex_destroy(&ic->lock);
567
 
    free(ic->from_code);
568
 
    free(ic->to_code);
569
 
    free(ic);
 
563
        struct iconv *ic = data;
 
564
        fuse_fs_destroy(ic->next);
 
565
        iconv_close(ic->tofs);
 
566
        iconv_close(ic->fromfs);
 
567
        pthread_mutex_destroy(&ic->lock);
 
568
        free(ic->from_code);
 
569
        free(ic->to_code);
 
570
        free(ic);
570
571
}
571
572
 
572
573
static struct fuse_operations iconv_oper = {
573
 
    .destroy    = iconv_destroy,
574
 
    .init       = iconv_init,
575
 
    .getattr    = iconv_getattr,
576
 
    .fgetattr   = iconv_fgetattr,
577
 
    .access     = iconv_access,
578
 
    .readlink   = iconv_readlink,
579
 
    .opendir    = iconv_opendir,
580
 
    .readdir    = iconv_readdir,
581
 
    .releasedir = iconv_releasedir,
582
 
    .mknod      = iconv_mknod,
583
 
    .mkdir      = iconv_mkdir,
584
 
    .symlink    = iconv_symlink,
585
 
    .unlink     = iconv_unlink,
586
 
    .rmdir      = iconv_rmdir,
587
 
    .rename     = iconv_rename,
588
 
    .link       = iconv_link,
589
 
    .chmod      = iconv_chmod,
590
 
    .chown      = iconv_chown,
591
 
    .truncate   = iconv_truncate,
592
 
    .ftruncate  = iconv_ftruncate,
593
 
    .utimens    = iconv_utimens,
594
 
    .create     = iconv_create,
595
 
    .open       = iconv_open_file,
596
 
    .read       = iconv_read,
597
 
    .write      = iconv_write,
598
 
    .statfs     = iconv_statfs,
599
 
    .flush      = iconv_flush,
600
 
    .release    = iconv_release,
601
 
    .fsync      = iconv_fsync,
602
 
    .fsyncdir   = iconv_fsyncdir,
603
 
    .setxattr   = iconv_setxattr,
604
 
    .getxattr   = iconv_getxattr,
605
 
    .listxattr  = iconv_listxattr,
606
 
    .removexattr= iconv_removexattr,
607
 
    .lock       = iconv_lock,
608
 
    .bmap       = iconv_bmap,
 
574
        .destroy        = iconv_destroy,
 
575
        .init           = iconv_init,
 
576
        .getattr        = iconv_getattr,
 
577
        .fgetattr       = iconv_fgetattr,
 
578
        .access         = iconv_access,
 
579
        .readlink       = iconv_readlink,
 
580
        .opendir        = iconv_opendir,
 
581
        .readdir        = iconv_readdir,
 
582
        .releasedir     = iconv_releasedir,
 
583
        .mknod          = iconv_mknod,
 
584
        .mkdir          = iconv_mkdir,
 
585
        .symlink        = iconv_symlink,
 
586
        .unlink         = iconv_unlink,
 
587
        .rmdir          = iconv_rmdir,
 
588
        .rename         = iconv_rename,
 
589
        .link           = iconv_link,
 
590
        .chmod          = iconv_chmod,
 
591
        .chown          = iconv_chown,
 
592
        .truncate       = iconv_truncate,
 
593
        .ftruncate      = iconv_ftruncate,
 
594
        .utimens        = iconv_utimens,
 
595
        .create         = iconv_create,
 
596
        .open           = iconv_open_file,
 
597
        .read           = iconv_read,
 
598
        .write          = iconv_write,
 
599
        .statfs         = iconv_statfs,
 
600
        .flush          = iconv_flush,
 
601
        .release        = iconv_release,
 
602
        .fsync          = iconv_fsync,
 
603
        .fsyncdir       = iconv_fsyncdir,
 
604
        .setxattr       = iconv_setxattr,
 
605
        .getxattr       = iconv_getxattr,
 
606
        .listxattr      = iconv_listxattr,
 
607
        .removexattr    = iconv_removexattr,
 
608
        .lock           = iconv_lock,
 
609
        .bmap           = iconv_bmap,
609
610
};
610
611
 
611
612
static struct fuse_opt iconv_opts[] = {
612
 
    FUSE_OPT_KEY("-h", 0),
613
 
    FUSE_OPT_KEY("--help", 0),
614
 
    { "from_code=%s", offsetof(struct iconv, from_code), 0 },
615
 
    { "to_code=%s", offsetof(struct iconv, to_code), 1 },
616
 
    FUSE_OPT_END
 
613
        FUSE_OPT_KEY("-h", 0),
 
614
        FUSE_OPT_KEY("--help", 0),
 
615
        { "from_code=%s", offsetof(struct iconv, from_code), 0 },
 
616
        { "to_code=%s", offsetof(struct iconv, to_code), 1 },
 
617
        FUSE_OPT_END
617
618
};
618
619
 
619
620
static void iconv_help(void)
620
621
{
621
 
    char *old = strdup(setlocale(LC_CTYPE, ""));
622
 
    char *charmap = strdup(nl_langinfo(CODESET));
623
 
    setlocale(LC_CTYPE, old);
624
 
    free(old);
625
 
    fprintf(stderr,
 
622
        char *old = strdup(setlocale(LC_CTYPE, ""));
 
623
        char *charmap = strdup(nl_langinfo(CODESET));
 
624
        setlocale(LC_CTYPE, old);
 
625
        free(old);
 
626
        fprintf(stderr,
626
627
"    -o from_code=CHARSET   original encoding of file names (default: UTF-8)\n"
627
 
"    -o to_code=CHARSET     new encoding of the file names (default: %s)\n",
628
 
            charmap);
629
 
    free(charmap);
 
628
"    -o to_code=CHARSET     new encoding of the file names (default: %s)\n",
 
629
                charmap);
 
630
        free(charmap);
630
631
}
631
632
 
632
633
static int iconv_opt_proc(void *data, const char *arg, int key,
633
 
                           struct fuse_args *outargs)
 
634
                          struct fuse_args *outargs)
634
635
{
635
 
    (void) data; (void) arg; (void) outargs;
636
 
 
637
 
    if (!key) {
638
 
        iconv_help();
639
 
        return -1;
640
 
    }
641
 
 
642
 
    return 1;
 
636
        (void) data; (void) arg; (void) outargs;
 
637
 
 
638
        if (!key) {
 
639
                iconv_help();
 
640
                return -1;
 
641
        }
 
642
 
 
643
        return 1;
643
644
}
644
645
 
645
646
static struct fuse_fs *iconv_new(struct fuse_args *args,
646
 
                                  struct fuse_fs *next[])
 
647
                                 struct fuse_fs *next[])
647
648
{
648
 
    struct fuse_fs *fs;
649
 
    struct iconv *ic;
650
 
    char *old = NULL;
651
 
    const char *from;
652
 
    const char *to;
653
 
 
654
 
    ic = calloc(1, sizeof(struct iconv));
655
 
    if (ic == NULL) {
656
 
        fprintf(stderr, "fuse-iconv: memory allocation failed\n");
657
 
        return NULL;
658
 
    }
659
 
 
660
 
    if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1)
661
 
        goto out_free;
662
 
 
663
 
    if (!next[0] || next[1]) {
664
 
        fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n");
665
 
        goto out_free;
666
 
    }
667
 
 
668
 
    from = ic->from_code ? ic->from_code : "UTF-8";
669
 
    to = ic->to_code ? ic->to_code : "";
670
 
    /* FIXME: detect charset equivalence? */
671
 
    if (!to[0])
672
 
        old = strdup(setlocale(LC_CTYPE, ""));
673
 
    ic->tofs = iconv_open(from, to);
674
 
    if (ic->tofs == (iconv_t) -1) {
675
 
        fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
676
 
                to, from);
677
 
        goto out_free;
678
 
    }
679
 
    ic->fromfs = iconv_open(to, from);
680
 
    if (ic->tofs == (iconv_t) -1) {
681
 
        fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
682
 
                from, to);
683
 
        goto out_iconv_close_to;
684
 
    }
685
 
    if (old) {
686
 
        setlocale(LC_CTYPE, old);
687
 
        free(old);
688
 
    }
689
 
 
690
 
    ic->next = next[0];
691
 
    fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic);
692
 
    if (!fs)
693
 
        goto out_iconv_close_from;
694
 
 
695
 
    return fs;
696
 
 
697
 
 out_iconv_close_from:
698
 
    iconv_close(ic->fromfs);
699
 
 out_iconv_close_to:
700
 
    iconv_close(ic->tofs);
701
 
 out_free:
702
 
    free(ic->from_code);
703
 
    free(ic->to_code);
704
 
    free(ic);
705
 
    return NULL;
 
649
        struct fuse_fs *fs;
 
650
        struct iconv *ic;
 
651
        char *old = NULL;
 
652
        const char *from;
 
653
        const char *to;
 
654
 
 
655
        ic = calloc(1, sizeof(struct iconv));
 
656
        if (ic == NULL) {
 
657
                fprintf(stderr, "fuse-iconv: memory allocation failed\n");
 
658
                return NULL;
 
659
        }
 
660
 
 
661
        if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1)
 
662
                goto out_free;
 
663
 
 
664
        if (!next[0] || next[1]) {
 
665
                fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n");
 
666
                goto out_free;
 
667
        }
 
668
 
 
669
        from = ic->from_code ? ic->from_code : "UTF-8";
 
670
        to = ic->to_code ? ic->to_code : "";
 
671
        /* FIXME: detect charset equivalence? */
 
672
        if (!to[0])
 
673
                old = strdup(setlocale(LC_CTYPE, ""));
 
674
        ic->tofs = iconv_open(from, to);
 
675
        if (ic->tofs == (iconv_t) -1) {
 
676
                fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
 
677
                        to, from);
 
678
                goto out_free;
 
679
        }
 
680
        ic->fromfs = iconv_open(to, from);
 
681
        if (ic->tofs == (iconv_t) -1) {
 
682
                fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
 
683
                        from, to);
 
684
                goto out_iconv_close_to;
 
685
        }
 
686
        if (old) {
 
687
                setlocale(LC_CTYPE, old);
 
688
                free(old);
 
689
        }
 
690
 
 
691
        ic->next = next[0];
 
692
        fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic);
 
693
        if (!fs)
 
694
                goto out_iconv_close_from;
 
695
 
 
696
        return fs;
 
697
 
 
698
out_iconv_close_from:
 
699
        iconv_close(ic->fromfs);
 
700
out_iconv_close_to:
 
701
        iconv_close(ic->tofs);
 
702
out_free:
 
703
        free(ic->from_code);
 
704
        free(ic->to_code);
 
705
        free(ic);
 
706
        return NULL;
706
707
}
707
708
 
708
709
FUSE_REGISTER_MODULE(iconv, iconv_new);