OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [hfs/] [file_hdr.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/fs/hfs/file_hdr.c
3
 *
4
 * Copyright (C) 1995-1997  Paul H. Hargrove
5
 * This file may be distributed under the terms of the GNU General Public License.
6
 *
7
 * This file contains the file_ops and inode_ops for the metadata
8
 * files under the AppleDouble and Netatalk representations.
9
 *
10
 * The source code distributions of Netatalk, versions 1.3.3b2 and
11
 * 1.4b2, were used as a specification of the location and format of
12
 * files used by Netatalk's afpd.  No code from Netatalk appears in
13
 * hfs_fs.  hfs_fs is not a work ``derived'' from Netatalk in the
14
 * sense of intellectual property law.
15
 *
16
 * "XXX" in a comment is a note to myself to consider changing something.
17
 *
18
 * In function preconditions the term "valid" applied to a pointer to
19
 * a structure means that the pointer is non-NULL and the structure it
20
 * points to has all fields initialized to consistent values.
21
 *
22
 * XXX: Note the reason that there is not bmap() for AppleDouble
23
 * header files is that dynamic nature of their structure make it
24
 * very difficult to safely mmap them.  Maybe in the distant future
25
 * I'll get bored enough to implement it.
26
 */
27
 
28
#include "hfs.h"
29
#include <linux/hfs_fs_sb.h>
30
#include <linux/hfs_fs_i.h>
31
#include <linux/hfs_fs.h>
32
 
33
/* prodos types */
34
#define PRODOSI_FTYPE_DIR   0x0F
35
#define PRODOSI_FTYPE_TEXT  0x04
36
#define PRODOSI_FTYPE_8BIT  0xFF
37
#define PRODOSI_FTYPE_16BIT 0xB3
38
 
39
#define PRODOSI_AUXTYPE_DIR 0x0200
40
 
41
/*================ Forward declarations ================*/
42
static loff_t      hdr_llseek(struct file *, loff_t, int);
43
static hfs_rwret_t hdr_read(struct file *, char *, hfs_rwarg_t, loff_t *);
44
static hfs_rwret_t hdr_write(struct file *, const char *,
45
                             hfs_rwarg_t, loff_t *);
46
/*================ Global variables ================*/
47
 
48
struct file_operations hfs_hdr_operations = {
49
        llseek:         hdr_llseek,
50
        read:           hdr_read,
51
        write:          hdr_write,
52
        fsync:          file_fsync,
53
};
54
 
55
struct inode_operations hfs_hdr_inode_operations = {
56
        setattr:        hfs_notify_change_hdr,
57
};
58
 
59
const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = {
60
        __constant_htonl(HFS_DBL_MAGIC),        /* magic   */
61
        __constant_htonl(HFS_HDR_VERSION_2),    /* version */
62
        6,                                      /* entries */
63
        {                                       /* descr[] */
64
                {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
65
                {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
66
                {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
67
                {HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
68
                {HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4},
69
                {HFS_HDR_RSRC,  HFS_DBL_HDR_LEN,                           ~0}
70
        },
71
        {                                       /* order[] */
72
                (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[0],
73
                (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[1],
74
                (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[2],
75
                (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[3],
76
                (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[4],
77
                (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[5]
78
        }
79
};
80
 
81
const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout = {
82
        __constant_htonl(HFS_DBL_MAGIC),        /* magic   */
83
        __constant_htonl(HFS_HDR_VERSION_2),    /* version */
84
        5,                                      /* entries */
85
        {                                       /* descr[] */
86
                {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
87
                {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
88
                {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
89
                {HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
90
                {HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4}
91
        },
92
        {                                       /* order[] */
93
                (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[0],
94
                (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[1],
95
                (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[2],
96
                (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[3],
97
                (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[4]
98
        }
99
};
100
 
101
const struct hfs_hdr_layout hfs_nat2_hdr_layout = {
102
        __constant_htonl(HFS_DBL_MAGIC),        /* magic   */
103
        __constant_htonl(HFS_HDR_VERSION_2),    /* version */
104
        9,                                      /* entries */
105
        {                                       /* descr[] */
106
                {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
107
                {HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
108
                {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
109
                {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
110
                {HFS_HDR_AFPI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
111
                {HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4},
112
                {HFS_HDR_SNAME,  offsetof(struct hfs_dbl_hdr, short_name), ~0},
113
                {HFS_HDR_PRODOSI,  offsetof(struct hfs_dbl_hdr, prodosi),   8},
114
                {HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0}
115
        },
116
        {                                       /* order[] */
117
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
118
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
119
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
120
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
121
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4],
122
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[5],
123
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[6],
124
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[7],
125
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[8]
126
        }
127
};
128
 
129
const struct hfs_hdr_layout hfs_nat_hdr_layout = {
130
        __constant_htonl(HFS_DBL_MAGIC),        /* magic   */
131
        __constant_htonl(HFS_HDR_VERSION_1),    /* version */
132
        5,                                      /* entries */
133
        {                                       /* descr[] */
134
                {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
135
                {HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
136
                {HFS_HDR_OLDI,  offsetof(struct hfs_dbl_hdr, create_time), 16},
137
                {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
138
                {HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0},
139
        },
140
        {                                       /* order[] */
141
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
142
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
143
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
144
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
145
                (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4]
146
        }
147
};
148
 
149
/*================ File-local variables ================*/
150
 
151
static const char fstype[16] =
152
        {'M','a','c','i','n','t','o','s','h',' ',' ',' ',' ',' ',' ',' '};
153
 
154
/*================ File-local data types ================*/
155
 
156
struct hdr_hdr {
157
        hfs_lword_t     magic;
158
        hfs_lword_t     version;
159
        hfs_byte_t      filler[16];
160
        hfs_word_t      entries;
161
        hfs_byte_t      descrs[12*HFS_HDR_MAX];
162
}  __attribute__((packed));
163
 
164
/*================ File-local functions ================*/
165
 
166
/*
167
 * dlength()
168
 */
169
static int dlength(const struct hfs_hdr_descr *descr,
170
                   const struct hfs_cat_entry *entry)
171
{
172
        hfs_u32 length = descr->length;
173
 
174
        /* handle auto-sized entries */
175
        if (length == ~0) {
176
                switch (descr->id) {
177
                case HFS_HDR_DATA:
178
                        if (entry->type == HFS_CDR_FIL) {
179
                                length = entry->u.file.data_fork.lsize;
180
                        } else {
181
                                length = 0;
182
                        }
183
                        break;
184
 
185
                case HFS_HDR_RSRC:
186
                        if (entry->type == HFS_CDR_FIL) {
187
                                length = entry->u.file.rsrc_fork.lsize;
188
                        } else {
189
                                length = 0;
190
                        }
191
                        break;
192
 
193
                case HFS_HDR_FNAME:
194
                        length = entry->key.CName.Len;
195
                        break;
196
 
197
                case HFS_HDR_SNAME:
198
                default:
199
                        length = 0;
200
                }
201
        }
202
        return length;
203
}
204
 
205
/*
206
 * hdr_build_meta()
207
 */
208
static void hdr_build_meta(struct hdr_hdr *meta,
209
                           const struct hfs_hdr_layout *layout,
210
                           const struct hfs_cat_entry *entry)
211
{
212
        const struct hfs_hdr_descr *descr;
213
        hfs_byte_t *ptr;
214
        int lcv;
215
 
216
        hfs_put_nl(layout->magic,   meta->magic);
217
        hfs_put_nl(layout->version, meta->version);
218
        if (layout->version == htonl(HFS_HDR_VERSION_1)) {
219
                memcpy(meta->filler, fstype, 16);
220
        } else {
221
                memset(meta->filler, 0, 16);
222
        }
223
        hfs_put_hs(layout->entries, meta->entries);
224
        memset(meta->descrs, 0, sizeof(meta->descrs));
225
        for (lcv = 0, descr = layout->descr, ptr = meta->descrs;
226
             lcv < layout->entries; ++lcv, ++descr, ptr += 12) {
227
                hfs_put_hl(descr->id,             ptr);
228
                hfs_put_hl(descr->offset,         ptr + 4);
229
                hfs_put_hl(dlength(descr, entry), ptr + 8);
230
        }
231
}
232
 
233
/*
234
 * dup_layout ()
235
 */
236
static struct hfs_hdr_layout *dup_layout(const struct hfs_hdr_layout *old)
237
{
238
        struct hfs_hdr_layout *new;
239
        int lcv;
240
 
241
        if (HFS_NEW(new)) {
242
                memcpy(new, old, sizeof(*new));
243
                for (lcv = 0; lcv < new->entries; ++lcv) {
244
                        (char *)(new->order[lcv]) += (char *)new - (char *)old;
245
                }
246
        }
247
        return new;
248
}
249
 
250
/*
251
 * init_layout()
252
 */
253
static inline void init_layout(struct hfs_hdr_layout *layout,
254
                               const hfs_byte_t *descrs)
255
{
256
        struct hfs_hdr_descr **base, **p, **q, *tmp;
257
        int lcv, entries = layout->entries;
258
 
259
        for (lcv = 0; lcv < entries; ++lcv, descrs += 12) {
260
                layout->order[lcv] = &layout->descr[lcv];
261
                layout->descr[lcv].id     = hfs_get_hl(descrs);
262
                layout->descr[lcv].offset = hfs_get_hl(descrs + 4);
263
                layout->descr[lcv].length = hfs_get_hl(descrs + 8);
264
        }
265
        for (lcv = layout->entries; lcv < HFS_HDR_MAX; ++lcv) {
266
                layout->order[lcv] = NULL;
267
                layout->descr[lcv].id     = 0;
268
                layout->descr[lcv].offset = 0;
269
                layout->descr[lcv].length = 0;
270
        }
271
 
272
        /* Sort the 'order' array using an insertion sort */
273
        base = &layout->order[0];
274
        for (p = (base+1); p < (base+entries); ++p) {
275
                q=p;
276
                while ((*q)->offset < (*(q-1))->offset) {
277
                        tmp = *q;
278
                        *q = *(q-1);
279
                        *(--q) = tmp;
280
                        if (q == base) break;
281
                }
282
        }
283
}
284
 
285
/*
286
 * adjust_forks()
287
 */
288
static inline void adjust_forks(struct hfs_cat_entry *entry,
289
                                const struct hfs_hdr_layout *layout)
290
{
291
        int lcv;
292
 
293
        for (lcv = 0; lcv < layout->entries; ++lcv) {
294
                const struct hfs_hdr_descr *descr = &layout->descr[lcv];
295
 
296
                if ((descr->id == HFS_HDR_DATA) &&
297
                    (descr->length != entry->u.file.data_fork.lsize)) {
298
                        entry->u.file.data_fork.lsize = descr->length;
299
                        hfs_extent_adj(&entry->u.file.data_fork);
300
                } else if ((descr->id == HFS_HDR_RSRC) &&
301
                           (descr->length != entry->u.file.rsrc_fork.lsize)) {
302
                        entry->u.file.rsrc_fork.lsize = descr->length;
303
                        hfs_extent_adj(&entry->u.file.rsrc_fork);
304
                }
305
        }
306
}
307
 
308
/*
309
 * get_dates()
310
 */
311
static void get_dates(const struct hfs_cat_entry *entry,
312
                      const struct inode *inode,  hfs_u32 dates[3])
313
{
314
        dates[0] = hfs_m_to_htime(entry->create_date);
315
        dates[1] = hfs_m_to_htime(entry->modify_date);
316
        dates[2] = hfs_m_to_htime(entry->backup_date);
317
}
318
 
319
/*
320
 * set_dates()
321
 */
322
static void set_dates(struct hfs_cat_entry *entry, struct inode *inode,
323
                      const hfs_u32 *dates)
324
{
325
        hfs_u32 tmp;
326
 
327
        tmp = hfs_h_to_mtime(dates[0]);
328
        if (entry->create_date != tmp) {
329
                entry->create_date = tmp;
330
                hfs_cat_mark_dirty(entry);
331
        }
332
        tmp = hfs_h_to_mtime(dates[1]);
333
        if (entry->modify_date != tmp) {
334
                entry->modify_date = tmp;
335
                inode->i_ctime = inode->i_atime = inode->i_mtime =
336
                        hfs_h_to_utime(dates[1]);
337
                hfs_cat_mark_dirty(entry);
338
        }
339
        tmp = hfs_h_to_mtime(dates[2]);
340
        if (entry->backup_date != tmp) {
341
                entry->backup_date = tmp;
342
                hfs_cat_mark_dirty(entry);
343
        }
344
}
345
 
346
loff_t hdr_llseek(struct file *file, loff_t offset, int origin)
347
{
348
        long long retval;
349
 
350
        switch (origin) {
351
                case 2:
352
                        offset += file->f_dentry->d_inode->i_size;
353
                        break;
354
                case 1:
355
                        offset += file->f_pos;
356
        }
357
        retval = -EINVAL;
358
        if (offset>=0 && offset<file->f_dentry->d_inode->i_size) {
359
                if (offset != file->f_pos) {
360
                        file->f_pos = offset;
361
                        file->f_reada = 0;
362
                        file->f_version = ++event;
363
                }
364
                retval = offset;
365
        }
366
        return retval;
367
}
368
 
369
/*
370
 * hdr_read()
371
 *
372
 * This is the read field in the inode_operations structure for
373
 * header files.  The purpose is to transfer up to 'count' bytes
374
 * from the file corresponding to 'inode', beginning at
375
 * 'filp->offset' bytes into the file.  The data is transferred to
376
 * user-space at the address 'buf'.  Returns the number of bytes
377
 * successfully transferred.
378
 */
379
/* XXX: what about the entry count changing on us? */
380
static hfs_rwret_t hdr_read(struct file * filp, char * buf,
381
                            hfs_rwarg_t count, loff_t *ppos)
382
{
383
        struct inode *inode = filp->f_dentry->d_inode;
384
        struct hfs_cat_entry *entry = HFS_I(inode)->entry;
385
        const struct hfs_hdr_layout *layout;
386
        off_t start, length, offset;
387
        off_t pos = *ppos;
388
        int left, lcv, read = 0;
389
 
390
        if (!S_ISREG(inode->i_mode)) {
391
                hfs_warn("hfs_hdr_read: mode = %07o\n",inode->i_mode);
392
                return -EINVAL;
393
        }
394
 
395
        if (HFS_I(inode)->layout) {
396
                layout = HFS_I(inode)->layout;
397
        } else {
398
                layout = HFS_I(inode)->default_layout;
399
        }
400
 
401
        /* Adjust count to fit within the bounds of the file */
402
        if ((pos >= inode->i_size) || (count <= 0)) {
403
                return 0;
404
        } else if (count > inode->i_size - pos) {
405
                count = inode->i_size - pos;
406
        }
407
 
408
        /* Handle the fixed-location portion */
409
        length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 +
410
                 sizeof(hfs_u16) + layout->entries * (3 * sizeof(hfs_u32));
411
        if (pos < length) {
412
                struct hdr_hdr meta;
413
 
414
                left = length - pos;
415
                if (left > count) {
416
                        left = count;
417
                }
418
 
419
                hdr_build_meta(&meta, layout, entry);
420
                left -= copy_to_user(buf, ((char *)&meta) + pos, left);
421
                count -= left;
422
                read += left;
423
                pos += left;
424
                buf += left;
425
        }
426
        if (!count) {
427
                goto done;
428
        }
429
 
430
        /* Handle the actual data */
431
        for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
432
                const struct hfs_hdr_descr *descr = layout->order[lcv];
433
                struct hfs_fork *fork;
434
                char tmp[16], *p;
435
                off_t limit;
436
 
437
                /* stop reading if we run out of descriptors early */
438
                if (!descr) {
439
                        break;
440
                }
441
 
442
                /* find start and length of this entry */
443
                start = descr->offset;
444
                length = dlength(descr, entry);
445
 
446
                /* Skip to next entry if this one is empty or isn't needed */
447
                if (!length || (pos >= start + length)) {
448
                        continue;
449
                }
450
 
451
                /* Pad with zeros to the start of this entry if needed */
452
                if (pos < start) {
453
                        left = start - pos;
454
                        if (left > count) {
455
                                left = count;
456
                        }
457
                        clear_user(buf, left);
458
                        count -= left;
459
                        read += left;
460
                        pos += left;
461
                        buf += left;
462
                }
463
                if (!count) {
464
                        goto done;
465
                }
466
 
467
                /* locate and/or construct the data for this entry */
468
                fork = NULL;
469
                p = NULL;
470
                switch (descr->id) {
471
                case HFS_HDR_DATA:
472
                        fork = &entry->u.file.data_fork;
473
                        limit = fork->lsize;
474
                        break;
475
 
476
                case HFS_HDR_RSRC:
477
                        fork = &entry->u.file.rsrc_fork;
478
                        limit = fork->lsize;
479
                        break;
480
 
481
                case HFS_HDR_FNAME:
482
                        p = entry->key.CName.Name;
483
                        limit = entry->key.CName.Len;
484
                        break;
485
 
486
                case HFS_HDR_OLDI:
487
                case HFS_HDR_DATES:
488
                        get_dates(entry, inode, (hfs_u32 *)tmp);
489
                        if (descr->id == HFS_HDR_DATES) {
490
                                /* XXX: access date. hfsplus actually
491
                                   has this. */
492
                                memcpy(tmp + 12, tmp + 4, 4);
493
                        } else if ((entry->type == HFS_CDR_FIL) &&
494
                                   (entry->u.file.flags & HFS_FIL_LOCK)) {
495
                                hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
496
                        } else {
497
                                hfs_put_nl(0, tmp + 12);
498
                        }
499
                        p = tmp;
500
                        limit = 16;
501
                        break;
502
 
503
                case HFS_HDR_FINFO:
504
                        p = (char *)&entry->info;
505
                        limit = 32;
506
                        break;
507
 
508
                case HFS_HDR_AFPI:
509
                        /* XXX: this needs to do more mac->afp mappings */
510
                        hfs_put_ns(0, tmp);
511
                        if ((entry->type == HFS_CDR_FIL) &&
512
                            (entry->u.file.flags & HFS_FIL_LOCK)) {
513
                                hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
514
                        } else {
515
                                hfs_put_ns(0, tmp + 2);
516
                        }
517
                        p = tmp;
518
                        limit = 4;
519
                        break;
520
 
521
                case HFS_HDR_PRODOSI:
522
                        /* XXX: this needs to do mac->prodos translations */
523
                        memset(tmp, 0, 8);
524
#if 0
525
                        hfs_put_ns(0, tmp); /* access */
526
                        hfs_put_ns(0, tmp); /* type */
527
                        hfs_put_nl(0, tmp); /* aux type */
528
#endif
529
                        p = tmp;
530
                        limit = 8;
531
                        break;
532
 
533
                case HFS_HDR_MACI:
534
                        hfs_put_ns(0, tmp);
535
                        if (entry->type == HFS_CDR_FIL) {
536
                                hfs_put_hs(entry->u.file.flags, tmp + 2);
537
                        } else {
538
                                hfs_put_ns(entry->u.dir.flags, tmp + 2);
539
                        }
540
                        p = tmp;
541
                        limit = 4;
542
                        break;
543
 
544
                case HFS_HDR_DID:
545
                        /* if it's rootinfo, stick the next available did in
546
                         * the did slot. */
547
                        limit = 4;
548
                        if (entry->cnid == htonl(HFS_ROOT_CNID)) {
549
                                struct hfs_mdb *mdb = entry->mdb;
550
                                const struct hfs_name *reserved =
551
                                HFS_SB(mdb->sys_mdb)->s_reserved2;
552
 
553
                                while (reserved->Len) {
554
                                        if (hfs_streq(reserved->Name,
555
                                                      reserved->Len,
556
                                                      entry->key.CName.Name,
557
                                                      entry->key.CName.Len)) {
558
                                                hfs_put_hl(mdb->next_id, tmp);
559
                                                p = tmp;
560
                                                goto hfs_did_done;
561
                                        }
562
                                        reserved++;
563
                                }
564
                        }
565
                        p = (char *) &entry->cnid;
566
hfs_did_done:
567
                        break;
568
 
569
                case HFS_HDR_SNAME:
570
                default:
571
                        limit = 0;
572
                }
573
 
574
                /* limit the transfer to the available data
575
                   of to the stated length of the entry. */
576
                if (length > limit) {
577
                        length = limit;
578
                }
579
                offset = pos - start;
580
                left = length - offset;
581
                if (left > count) {
582
                        left = count;
583
                }
584
                if (left <= 0) {
585
                        continue;
586
                }
587
 
588
                /* transfer the data */
589
                if (p) {
590
                        left -= copy_to_user(buf, p + offset, left);
591
                } else if (fork) {
592
                        left = hfs_do_read(inode, fork, offset, buf, left,
593
                                           filp->f_reada != 0);
594
                        if (left > 0) {
595
                                filp->f_reada = 1;
596
                        } else if (!read) {
597
                                return left;
598
                        } else {
599
                                goto done;
600
                        }
601
                }
602
                count -= left;
603
                read += left;
604
                pos += left;
605
                buf += left;
606
        }
607
 
608
        /* Pad the file out with zeros */
609
        if (count) {
610
                clear_user(buf, count);
611
                read += count;
612
                pos += count;
613
        }
614
 
615
done:
616
        if (read) {
617
                inode->i_atime = CURRENT_TIME;
618
                *ppos = pos;
619
                mark_inode_dirty(inode);
620
        }
621
        return read;
622
}
623
 
624
/*
625
 * hdr_write()
626
 *
627
 * This is the write() entry in the file_operations structure for
628
 * header files.  The purpose is to transfer up to 'count' bytes
629
 * to the file corresponding to 'inode' beginning at offset
630
 * '*ppos' from user-space at the address 'buf'.
631
 * The return value is the number of bytes actually transferred.
632
 */
633
static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
634
                             hfs_rwarg_t count, loff_t *ppos)
635
{
636
        struct inode *inode = filp->f_dentry->d_inode;
637
        struct hfs_cat_entry *entry = HFS_I(inode)->entry;
638
        struct hfs_hdr_layout *layout;
639
        off_t start, length, offset;
640
        int left, lcv, written = 0;
641
        struct hdr_hdr meta;
642
        int built_meta = 0;
643
        off_t pos;
644
 
645
        if (!S_ISREG(inode->i_mode)) {
646
                hfs_warn("hfs_hdr_write: mode = %07o\n", inode->i_mode);
647
                return -EINVAL;
648
        }
649
        if (count <= 0) {
650
                return 0;
651
        }
652
 
653
        pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
654
 
655
        if (!HFS_I(inode)->layout) {
656
                HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
657
        }
658
        layout = HFS_I(inode)->layout;
659
 
660
        /* Handle the 'magic', 'version', 'filler' and 'entries' fields */
661
        length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + sizeof(hfs_u16);
662
        if (pos < length) {
663
                hdr_build_meta(&meta, layout, entry);
664
                built_meta = 1;
665
 
666
                left = length - pos;
667
                if (left > count) {
668
                        left = count;
669
                }
670
 
671
                left -= copy_from_user(((char *)&meta) + pos, buf, left);
672
                layout->magic   = hfs_get_nl(meta.magic);
673
                layout->version = hfs_get_nl(meta.version);
674
                layout->entries = hfs_get_hs(meta.entries);
675
                if (layout->entries > HFS_HDR_MAX) {
676
                        /* XXX: should allocate slots dynamically */
677
                        hfs_warn("hfs_hdr_write: TRUNCATING TO %d "
678
                                 "DESCRIPTORS\n", HFS_HDR_MAX);
679
                        layout->entries = HFS_HDR_MAX;
680
                }
681
 
682
                count -= left;
683
                written += left;
684
                pos += left;
685
                buf += left;
686
        }
687
        if (!count) {
688
                goto done;
689
        }
690
 
691
        /* We know for certain how many entries we have, so process them */
692
        length += layout->entries * 3 * sizeof(hfs_u32);
693
        if (pos < length) {
694
                if (!built_meta) {
695
                        hdr_build_meta(&meta, layout, entry);
696
                }
697
 
698
                left = length - pos;
699
                if (left > count) {
700
                        left = count;
701
                }
702
 
703
                left -= copy_from_user(((char *)&meta) + pos, buf, left);
704
                init_layout(layout, meta.descrs);
705
 
706
                count -= left;
707
                written += left;
708
                pos += left;
709
                buf += left;
710
 
711
                /* Handle possible size changes for the forks */
712
                if (entry->type == HFS_CDR_FIL) {
713
                        adjust_forks(entry, layout);
714
                        hfs_cat_mark_dirty(entry);
715
                }
716
        }
717
 
718
        /* Handle the actual data */
719
        for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
720
                struct hfs_hdr_descr *descr = layout->order[lcv];
721
                struct hfs_fork *fork;
722
                char tmp[16], *p;
723
                off_t limit;
724
 
725
                /* stop writing if we run out of descriptors early */
726
                if (!descr) {
727
                        break;
728
                }
729
 
730
                /* find start and length of this entry */
731
                start = descr->offset;
732
                if ((descr->id == HFS_HDR_DATA) ||
733
                    (descr->id == HFS_HDR_RSRC)) {
734
                        if (entry->type == HFS_CDR_FIL) {
735
                                length = 0x7fffffff - start;
736
                        } else {
737
                                continue;
738
                        }
739
                } else {
740
                        length = dlength(descr, entry);
741
                }
742
 
743
                /* Trim length to avoid overlap with the next entry */
744
                if (layout->order[lcv+1] &&
745
                    ((start + length) > layout->order[lcv+1]->offset)) {
746
                        length = layout->order[lcv+1]->offset - start;
747
                }
748
 
749
                /* Skip to next entry if this one is empty or isn't needed */
750
                if (!length || (pos >= start + length)) {
751
                        continue;
752
                }
753
 
754
                /* Skip any padding that may exist between entries */
755
                if (pos < start) {
756
                        left = start - pos;
757
                        if (left > count) {
758
                                left = count;
759
                        }
760
                        count -= left;
761
                        written += left;
762
                        pos += left;
763
                        buf += left;
764
                }
765
                if (!count) {
766
                        goto done;
767
                }
768
 
769
                /* locate and/or construct the data for this entry */
770
                fork = NULL;
771
                p = NULL;
772
                switch (descr->id) {
773
                case HFS_HDR_DATA:
774
#if 0
775
/* Can't yet write to the data fork via a header file, since there is the
776
 * possibility to write via the data file, and the only locking is at the
777
 * inode level.
778
 */
779
                        fork = &entry->u.file.data_fork;
780
                        limit = length;
781
#else
782
                        limit = 0;
783
#endif
784
                        break;
785
 
786
                case HFS_HDR_RSRC:
787
                        fork = &entry->u.file.rsrc_fork;
788
                        limit = length;
789
                        break;
790
 
791
                case HFS_HDR_OLDI:
792
                case HFS_HDR_DATES:
793
                        get_dates(entry, inode, (hfs_u32 *)tmp);
794
                        if (descr->id == HFS_HDR_DATES) {
795
                                memcpy(tmp + 12, tmp + 4, 4);
796
                        } else if ((entry->type == HFS_CDR_FIL) &&
797
                                   (entry->u.file.flags & HFS_FIL_LOCK)) {
798
                                hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
799
                        } else {
800
                                hfs_put_nl(0, tmp + 12);
801
                        }
802
                        p = tmp;
803
                        limit = 16;
804
                        break;
805
 
806
                case HFS_HDR_FINFO:
807
                        p = (char *)&entry->info;
808
                        limit = 32;
809
                        break;
810
 
811
                case HFS_HDR_AFPI:
812
                        hfs_put_ns(0, tmp);
813
                        if ((entry->type == HFS_CDR_FIL) &&
814
                            (entry->u.file.flags & HFS_FIL_LOCK)) {
815
                                hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
816
                        } else {
817
                                hfs_put_ns(0, tmp + 2);
818
                        }
819
                        p = tmp;
820
                        limit = 4;
821
                        break;
822
 
823
                case HFS_HDR_PRODOSI:
824
                        /* XXX: this needs to do mac->prodos translations */
825
                        memset(tmp, 0, 8);
826
#if 0
827
                        hfs_put_ns(0, tmp); /* access */
828
                        hfs_put_ns(0, tmp); /* type */
829
                        hfs_put_nl(0, tmp); /* aux type */
830
#endif
831
                        p = tmp;
832
                        limit = 8;
833
                        break;
834
 
835
                case HFS_HDR_MACI:
836
                        hfs_put_ns(0, tmp);
837
                        if (entry->type == HFS_CDR_FIL) {
838
                                hfs_put_hs(entry->u.file.flags, tmp + 2);
839
                        } else {
840
                                hfs_put_ns(entry->u.dir.flags, tmp + 2);
841
                        }
842
                        p = tmp;
843
                        limit = 4;
844
                        break;
845
 
846
                case HFS_HDR_FNAME:     /* Can't rename a file this way */
847
                case HFS_HDR_DID:       /* can't specify a did this way */
848
                default:
849
                        limit = 0;
850
                }
851
 
852
                /* limit the transfer to the available data
853
                   of to the stated length of the entry. */
854
                if (length > limit) {
855
                        length = limit;
856
                }
857
                offset = pos - start;
858
                left = length - offset;
859
                if (left > count) {
860
                        left = count;
861
                }
862
                if (left <= 0) {
863
                        continue;
864
                }
865
 
866
                /* transfer the data from user space */
867
                if (p) {
868
                        left -= copy_from_user(p + offset, buf, left);
869
                } else if (fork) {
870
                        left = hfs_do_write(inode, fork, offset, buf, left);
871
                }
872
 
873
                /* process the data */
874
                switch (descr->id) {
875
                case HFS_HDR_OLDI:
876
                        set_dates(entry, inode, (hfs_u32 *)tmp);
877
                        if (entry->type == HFS_CDR_FIL) {
878
                                hfs_u8 new_flags = entry->u.file.flags;
879
 
880
                                if (hfs_get_nl(tmp+12) & htonl(HFS_AFP_WRI)) {
881
                                        new_flags |= HFS_FIL_LOCK;
882
                                } else {
883
                                        new_flags &= ~HFS_FIL_LOCK;
884
                                }
885
 
886
                                if (new_flags != entry->u.file.flags) {
887
                                        entry->u.file.flags = new_flags;
888
                                        hfs_cat_mark_dirty(entry);
889
                                        hfs_file_fix_mode(entry);
890
                                }
891
                        }
892
                        break;
893
 
894
                case HFS_HDR_DATES:
895
                        set_dates(entry, inode, (hfs_u32 *)tmp);
896
                        break;
897
 
898
                case HFS_HDR_FINFO:
899
                        hfs_cat_mark_dirty(entry);
900
                        break;
901
 
902
                case HFS_HDR_MACI:
903
                        if (entry->type == HFS_CDR_DIR) {
904
                                hfs_u16 new_flags = hfs_get_ns(tmp + 2);
905
 
906
                                if (entry->u.dir.flags != new_flags) {
907
                                        entry->u.dir.flags = new_flags;
908
                                        hfs_cat_mark_dirty(entry);
909
                                }
910
                        } else {
911
                                hfs_u8 new_flags = tmp[3];
912
                                hfs_u8 changed = entry->u.file.flags^new_flags;
913
 
914
                                if (changed) {
915
                                        entry->u.file.flags = new_flags;
916
                                        hfs_cat_mark_dirty(entry);
917
                                        if (changed & HFS_FIL_LOCK) {
918
                                                hfs_file_fix_mode(entry);
919
                                        }
920
                                }
921
                        }
922
                        break;
923
 
924
                case HFS_HDR_DATA:
925
                case HFS_HDR_RSRC:
926
                        if (left <= 0) {
927
                                if (!written) {
928
                                        return left;
929
                                } else {
930
                                        goto done;
931
                                }
932
                        } else if (fork->lsize > descr->length) {
933
                                descr->length = fork->lsize;
934
                        }
935
                        break;
936
 
937
                case HFS_HDR_FNAME:     /* Can't rename a file this way */
938
                case HFS_HDR_DID:       /* Can't specify a did this way */
939
                case HFS_HDR_PRODOSI:   /* not implemented yet */
940
                case HFS_HDR_AFPI:      /* ditto */
941
                default:
942
                        break;
943
                }
944
 
945
                count -= left;
946
                written += left;
947
                pos += left;
948
                buf += left;
949
        }
950
 
951
        /* Skip any padding at the end */
952
        if (count) {
953
                written += count;
954
                pos += count;
955
        }
956
 
957
done:
958
        *ppos = pos;
959
        if (written > 0) {
960
                if (pos > inode->i_size)
961
                        inode->i_size = pos;
962
                inode->i_mtime = inode->i_atime = CURRENT_TIME;
963
                mark_inode_dirty(inode);
964
        }
965
        return written;
966
}
967
 
968
/*
969
 * hdr_truncate()
970
 *
971
 * This is the truncate field in the inode_operations structure for
972
 * header files.  The purpose is to allocate or release blocks as needed
973
 * to satisfy a change in file length.
974
 */
975
void hdr_truncate(struct inode *inode, size_t size)
976
{
977
        struct hfs_cat_entry *entry = HFS_I(inode)->entry;
978
        struct hfs_hdr_layout *layout;
979
        int lcv, last;
980
 
981
        inode->i_size = size;
982
        if (!HFS_I(inode)->layout) {
983
                HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
984
        }
985
        layout = HFS_I(inode)->layout;
986
 
987
        last = layout->entries - 1;
988
        for (lcv = 0; lcv <= last; ++lcv) {
989
                struct hfs_hdr_descr *descr = layout->order[lcv];
990
                struct hfs_fork *fork;
991
                hfs_u32 offset;
992
 
993
                if (!descr) {
994
                        break;
995
                }
996
 
997
                if (descr->id == HFS_HDR_RSRC) {
998
                        fork = &entry->u.file.rsrc_fork;
999
#if 0
1000
/* Can't yet truncate the data fork via a header file, since there is the
1001
 * possibility to truncate via the data file, and the only locking is at
1002
 * the inode level.
1003
 */
1004
                } else if (descr->id == HFS_HDR_DATA) {
1005
                        fork = &entry->u.file.data_fork;
1006
#endif
1007
                } else {
1008
                        continue;
1009
                }
1010
 
1011
                offset = descr->offset;
1012
 
1013
                if ((lcv != last) && ((offset + descr->length) <= size)) {
1014
                        continue;
1015
                }
1016
 
1017
                if (offset < size) {
1018
                        descr->length = size - offset;
1019
                } else {
1020
                        descr->length = 0;
1021
                }
1022
                if (fork->lsize != descr->length) {
1023
                        fork->lsize = descr->length;
1024
                        hfs_extent_adj(fork);
1025
                        hfs_cat_mark_dirty(entry);
1026
                }
1027
        }
1028
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.