more changes on original files
[linux-2.4.git] / fs / hfs / file_hdr.c
1 /*
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                         new->order[lcv] = (struct hfs_hdr_descr *)
245                                           ((char *)(new->order[lcv]) +
246                                            ((char *)new - (char *)old));
247                 }
248         }
249         return new;
250 }
251
252 /*
253  * init_layout()
254  */
255 static inline void init_layout(struct hfs_hdr_layout *layout,
256                                const hfs_byte_t *descrs)
257 {
258         struct hfs_hdr_descr **base, **p, **q, *tmp;
259         int lcv, entries = layout->entries;
260
261         for (lcv = 0; lcv < entries; ++lcv, descrs += 12) {
262                 layout->order[lcv] = &layout->descr[lcv];
263                 layout->descr[lcv].id     = hfs_get_hl(descrs);
264                 layout->descr[lcv].offset = hfs_get_hl(descrs + 4);
265                 layout->descr[lcv].length = hfs_get_hl(descrs + 8);
266         }
267         for (lcv = layout->entries; lcv < HFS_HDR_MAX; ++lcv) {
268                 layout->order[lcv] = NULL;
269                 layout->descr[lcv].id     = 0;
270                 layout->descr[lcv].offset = 0;
271                 layout->descr[lcv].length = 0;
272         }
273
274         /* Sort the 'order' array using an insertion sort */
275         base = &layout->order[0];
276         for (p = (base+1); p < (base+entries); ++p) {
277                 q=p;
278                 while ((*q)->offset < (*(q-1))->offset) {
279                         tmp = *q;
280                         *q = *(q-1);
281                         *(--q) = tmp;
282                         if (q == base) break;
283                 }
284         }
285 }
286
287 /*
288  * adjust_forks()
289  */
290 static inline void adjust_forks(struct hfs_cat_entry *entry,
291                                 const struct hfs_hdr_layout *layout)
292 {
293         int lcv;
294
295         for (lcv = 0; lcv < layout->entries; ++lcv) {
296                 const struct hfs_hdr_descr *descr = &layout->descr[lcv];
297
298                 if ((descr->id == HFS_HDR_DATA) &&
299                     (descr->length != entry->u.file.data_fork.lsize)) {
300                         entry->u.file.data_fork.lsize = descr->length;
301                         hfs_extent_adj(&entry->u.file.data_fork);
302                 } else if ((descr->id == HFS_HDR_RSRC) &&
303                            (descr->length != entry->u.file.rsrc_fork.lsize)) {
304                         entry->u.file.rsrc_fork.lsize = descr->length;
305                         hfs_extent_adj(&entry->u.file.rsrc_fork);
306                 }
307         }
308 }
309
310 /*
311  * get_dates()
312  */
313 static void get_dates(const struct hfs_cat_entry *entry,
314                       const struct inode *inode,  hfs_u32 dates[3])
315 {
316         dates[0] = hfs_m_to_htime(entry->create_date);
317         dates[1] = hfs_m_to_htime(entry->modify_date);
318         dates[2] = hfs_m_to_htime(entry->backup_date);
319 }
320
321 /*
322  * set_dates()
323  */
324 static void set_dates(struct hfs_cat_entry *entry, struct inode *inode,
325                       const hfs_u32 *dates)
326 {
327         hfs_u32 tmp;
328
329         tmp = hfs_h_to_mtime(dates[0]);
330         if (entry->create_date != tmp) {
331                 entry->create_date = tmp;
332                 hfs_cat_mark_dirty(entry);
333         }
334         tmp = hfs_h_to_mtime(dates[1]);
335         if (entry->modify_date != tmp) {
336                 entry->modify_date = tmp;
337                 inode->i_ctime = inode->i_atime = inode->i_mtime = 
338                         hfs_h_to_utime(dates[1]);
339                 hfs_cat_mark_dirty(entry);
340         }
341         tmp = hfs_h_to_mtime(dates[2]);
342         if (entry->backup_date != tmp) {
343                 entry->backup_date = tmp;
344                 hfs_cat_mark_dirty(entry);
345         }
346 }
347
348 loff_t hdr_llseek(struct file *file, loff_t offset, int origin)
349 {
350         long long retval;
351
352         switch (origin) {
353                 case 2:
354                         offset += file->f_dentry->d_inode->i_size;
355                         break;
356                 case 1:
357                         offset += file->f_pos;
358         }
359         retval = -EINVAL;
360         if (offset>=0 && offset<file->f_dentry->d_inode->i_size) {
361                 if (offset != file->f_pos) {
362                         file->f_pos = offset;
363                         file->f_reada = 0;
364                         file->f_version = ++event;
365                 }
366                 retval = offset;
367         }
368         return retval;
369 }
370
371 /*
372  * hdr_read()
373  *
374  * This is the read field in the inode_operations structure for
375  * header files.  The purpose is to transfer up to 'count' bytes
376  * from the file corresponding to 'inode', beginning at
377  * 'filp->offset' bytes into the file.  The data is transferred to
378  * user-space at the address 'buf'.  Returns the number of bytes
379  * successfully transferred.
380  */
381 /* XXX: what about the entry count changing on us? */
382 static hfs_rwret_t hdr_read(struct file * filp, char * buf, 
383                             hfs_rwarg_t count, loff_t *ppos)
384 {
385         struct inode *inode = filp->f_dentry->d_inode;
386         struct hfs_cat_entry *entry = HFS_I(inode)->entry;
387         const struct hfs_hdr_layout *layout;
388         off_t start, length, offset;
389         loff_t pos = *ppos;
390         int left, lcv, read = 0;
391
392         if (!S_ISREG(inode->i_mode)) {
393                 hfs_warn("hfs_hdr_read: mode = %07o\n",inode->i_mode);
394                 return -EINVAL;
395         }
396
397         if (HFS_I(inode)->layout) {
398                 layout = HFS_I(inode)->layout;
399         } else {
400                 layout = HFS_I(inode)->default_layout;
401         }
402
403         /* Adjust count to fit within the bounds of the file */
404         if (pos != (unsigned)pos || pos >= inode->i_size || count <= 0) {
405                 return 0;
406         } else if (count > inode->i_size - pos) {
407                 count = inode->i_size - pos;
408         }
409
410         /* Handle the fixed-location portion */
411         length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 +
412                  sizeof(hfs_u16) + layout->entries * (3 * sizeof(hfs_u32));
413         if (pos < length) {
414                 struct hdr_hdr meta;
415
416                 left = length - pos;
417                 if (left > count) {
418                         left = count;
419                 }
420
421                 hdr_build_meta(&meta, layout, entry);
422                 left -= copy_to_user(buf, ((char *)&meta) + pos, left);
423                 count -= left;
424                 read += left;
425                 pos += left;
426                 buf += left;
427         }
428         if (!count) {
429                 goto done;
430         }
431
432         /* Handle the actual data */
433         for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
434                 const struct hfs_hdr_descr *descr = layout->order[lcv];
435                 struct hfs_fork *fork;
436                 char tmp[16], *p;
437                 off_t limit;
438
439                 /* stop reading if we run out of descriptors early */
440                 if (!descr) {
441                         break;
442                 }
443
444                 /* find start and length of this entry */
445                 start = descr->offset;
446                 length = dlength(descr, entry);
447
448                 /* Skip to next entry if this one is empty or isn't needed */
449                 if (!length || (pos >= start + length)) {
450                         continue;
451                 }
452
453                 /* Pad with zeros to the start of this entry if needed */
454                 if (pos < start) {
455                         left = start - pos;
456                         if (left > count) {
457                                 left = count;
458                         }
459                         clear_user(buf, left);
460                         count -= left;
461                         read += left;
462                         pos += left;
463                         buf += left;
464                 }
465                 if (!count) {
466                         goto done;
467                 }
468
469                 /* locate and/or construct the data for this entry */
470                 fork = NULL;
471                 p = NULL;
472                 switch (descr->id) {
473                 case HFS_HDR_DATA:
474                         fork = &entry->u.file.data_fork;
475                         limit = fork->lsize;
476                         break;
477
478                 case HFS_HDR_RSRC:
479                         fork = &entry->u.file.rsrc_fork;
480                         limit = fork->lsize;
481                         break;
482
483                 case HFS_HDR_FNAME:
484                         p = entry->key.CName.Name;
485                         limit = entry->key.CName.Len;
486                         break;
487
488                 case HFS_HDR_OLDI:
489                 case HFS_HDR_DATES:
490                         get_dates(entry, inode, (hfs_u32 *)tmp);
491                         if (descr->id == HFS_HDR_DATES) {
492                                 /* XXX: access date. hfsplus actually
493                                    has this. */
494                                 memcpy(tmp + 12, tmp + 4, 4);
495                         } else if ((entry->type == HFS_CDR_FIL) &&
496                                    (entry->u.file.flags & HFS_FIL_LOCK)) {
497                                 hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
498                         } else {
499                                 hfs_put_nl(0, tmp + 12);
500                         }
501                         p = tmp;
502                         limit = 16;
503                         break;
504
505                 case HFS_HDR_FINFO:
506                         p = (char *)&entry->info;
507                         limit = 32;
508                         break;
509
510                 case HFS_HDR_AFPI:
511                         /* XXX: this needs to do more mac->afp mappings */
512                         hfs_put_ns(0, tmp);
513                         if ((entry->type == HFS_CDR_FIL) &&
514                             (entry->u.file.flags & HFS_FIL_LOCK)) {
515                                 hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
516                         } else {
517                                 hfs_put_ns(0, tmp + 2);
518                         }
519                         p = tmp;
520                         limit = 4;
521                         break;
522
523                 case HFS_HDR_PRODOSI:
524                         /* XXX: this needs to do mac->prodos translations */
525                         memset(tmp, 0, 8);
526 #if 0
527                         hfs_put_ns(0, tmp); /* access */
528                         hfs_put_ns(0, tmp); /* type */
529                         hfs_put_nl(0, tmp); /* aux type */
530 #endif
531                         p = tmp;
532                         limit = 8;
533                         break;
534
535                 case HFS_HDR_MACI:
536                         hfs_put_ns(0, tmp);
537                         if (entry->type == HFS_CDR_FIL) {
538                                 hfs_put_hs(entry->u.file.flags, tmp + 2);
539                         } else {
540                                 hfs_put_ns(entry->u.dir.flags, tmp + 2);
541                         }
542                         p = tmp;
543                         limit = 4;
544                         break;
545
546                 case HFS_HDR_DID:
547                         /* if it's rootinfo, stick the next available did in
548                          * the did slot. */
549                         limit = 4;
550                         if (entry->cnid == htonl(HFS_ROOT_CNID)) {
551                                 struct hfs_mdb *mdb = entry->mdb;
552                                 const struct hfs_name *reserved = 
553                                 HFS_SB(mdb->sys_mdb)->s_reserved2;
554                                 
555                                 while (reserved->Len) {
556                                         if (hfs_streq(reserved->Name,
557                                                       reserved->Len,
558                                                       entry->key.CName.Name,
559                                                       entry->key.CName.Len)) {
560                                                 hfs_put_hl(mdb->next_id, tmp);
561                                                 p = tmp;
562                                                 goto hfs_did_done;
563                                         }
564                                         reserved++;
565                                 }
566                         }
567                         p = (char *) &entry->cnid;
568 hfs_did_done:
569                         break;
570
571                 case HFS_HDR_SNAME:
572                 default:
573                         limit = 0;
574                 }
575                 
576                 /* limit the transfer to the available data
577                    of to the stated length of the entry. */
578                 if (length > limit) {
579                         length = limit;
580                 }
581                 offset = pos - start;
582                 left = length - offset;
583                 if (left > count) {
584                         left = count;
585                 }
586                 if (left <= 0) {
587                         continue;
588                 }
589
590                 /* transfer the data */
591                 if (p) {
592                         left -= copy_to_user(buf, p + offset, left);
593                 } else if (fork) {
594                         left = hfs_do_read(inode, fork, offset, buf, left,
595                                            filp->f_reada != 0);
596                         if (left > 0) {
597                                 filp->f_reada = 1;
598                         } else if (!read) {
599                                 return left;
600                         } else {
601                                 goto done;
602                         }
603                 }
604                 count -= left;
605                 read += left;
606                 pos += left;
607                 buf += left;
608         }
609
610         /* Pad the file out with zeros */
611         if (count) {
612                 clear_user(buf, count);
613                 read += count;
614                 pos += count;
615         }
616                 
617 done:
618         if (read) {
619                 inode->i_atime = CURRENT_TIME;
620                 *ppos = pos;
621                 mark_inode_dirty(inode);
622         }
623         return read;
624 }
625
626 /*
627  * hdr_write()
628  *
629  * This is the write() entry in the file_operations structure for
630  * header files.  The purpose is to transfer up to 'count' bytes
631  * to the file corresponding to 'inode' beginning at offset
632  * '*ppos' from user-space at the address 'buf'.
633  * The return value is the number of bytes actually transferred.
634  */
635 static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
636                              hfs_rwarg_t count, loff_t *ppos)
637 {
638         struct inode *inode = filp->f_dentry->d_inode;
639         struct hfs_cat_entry *entry = HFS_I(inode)->entry;
640         struct hfs_hdr_layout *layout;
641         off_t start, length, offset;
642         int left, lcv, written = 0;
643         struct hdr_hdr meta;
644         int built_meta = 0;
645         loff_t pos;
646
647         if (!S_ISREG(inode->i_mode)) {
648                 hfs_warn("hfs_hdr_write: mode = %07o\n", inode->i_mode);
649                 return -EINVAL;
650         }
651
652         pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
653
654         if (count <= 0 || pos != (unsigned)pos) {
655                 return 0;
656         }
657
658         if (!HFS_I(inode)->layout) {
659                 HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
660         }
661         layout = HFS_I(inode)->layout;
662
663         /* Handle the 'magic', 'version', 'filler' and 'entries' fields */
664         length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + sizeof(hfs_u16);
665         if (pos < length) {
666                 hdr_build_meta(&meta, layout, entry);
667                 built_meta = 1;
668
669                 left = length - pos;
670                 if (left > count) {
671                         left = count;
672                 }
673
674                 left -= copy_from_user(((char *)&meta) + pos, buf, left);
675                 layout->magic   = hfs_get_nl(meta.magic);
676                 layout->version = hfs_get_nl(meta.version);
677                 layout->entries = hfs_get_hs(meta.entries);
678                 if (layout->entries > HFS_HDR_MAX) {
679                         /* XXX: should allocate slots dynamically */
680                         hfs_warn("hfs_hdr_write: TRUNCATING TO %d "
681                                  "DESCRIPTORS\n", HFS_HDR_MAX);
682                         layout->entries = HFS_HDR_MAX;
683                 }
684
685                 count -= left;
686                 written += left;
687                 pos += left;
688                 buf += left;
689         }
690         if (!count) {
691                 goto done;
692         }
693
694         /* We know for certain how many entries we have, so process them */
695         length += layout->entries * 3 * sizeof(hfs_u32);
696         if (pos < length) {
697                 if (!built_meta) {
698                         hdr_build_meta(&meta, layout, entry);
699                 }
700
701                 left = length - pos;
702                 if (left > count) {
703                         left = count;
704                 }
705
706                 left -= copy_from_user(((char *)&meta) + pos, buf, left);
707                 init_layout(layout, meta.descrs);
708
709                 count -= left;
710                 written += left;
711                 pos += left;
712                 buf += left;
713
714                 /* Handle possible size changes for the forks */
715                 if (entry->type == HFS_CDR_FIL) {
716                         adjust_forks(entry, layout);
717                         hfs_cat_mark_dirty(entry);
718                 }
719         }
720
721         /* Handle the actual data */
722         for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
723                 struct hfs_hdr_descr *descr = layout->order[lcv];
724                 struct hfs_fork *fork;
725                 char tmp[16], *p;
726                 off_t limit;
727
728                 /* stop writing if we run out of descriptors early */
729                 if (!descr) {
730                         break;
731                 }
732
733                 /* find start and length of this entry */
734                 start = descr->offset;
735                 if ((descr->id == HFS_HDR_DATA) ||
736                     (descr->id == HFS_HDR_RSRC)) {
737                         if (entry->type == HFS_CDR_FIL) {
738                                 length = 0x7fffffff - start;
739                         } else {
740                                 continue;
741                         }
742                 } else {
743                         length = dlength(descr, entry);
744                 }
745
746                 /* Trim length to avoid overlap with the next entry */
747                 if (layout->order[lcv+1] &&
748                     ((start + length) > layout->order[lcv+1]->offset)) {
749                         length = layout->order[lcv+1]->offset - start;
750                 }
751
752                 /* Skip to next entry if this one is empty or isn't needed */
753                 if (!length || (pos >= start + length)) {
754                         continue;
755                 }
756
757                 /* Skip any padding that may exist between entries */
758                 if (pos < start) {
759                         left = start - pos;
760                         if (left > count) {
761                                 left = count;
762                         }
763                         count -= left;
764                         written += left;
765                         pos += left;
766                         buf += left;
767                 }
768                 if (!count) {
769                         goto done;
770                 }
771
772                 /* locate and/or construct the data for this entry */
773                 fork = NULL;
774                 p = NULL;
775                 switch (descr->id) {
776                 case HFS_HDR_DATA:
777 #if 0
778 /* Can't yet write to the data fork via a header file, since there is the
779  * possibility to write via the data file, and the only locking is at the
780  * inode level.
781  */
782                         fork = &entry->u.file.data_fork;
783                         limit = length;
784 #else
785                         limit = 0;
786 #endif
787                         break;
788
789                 case HFS_HDR_RSRC:
790                         fork = &entry->u.file.rsrc_fork;
791                         limit = length;
792                         break;
793
794                 case HFS_HDR_OLDI:
795                 case HFS_HDR_DATES:
796                         get_dates(entry, inode, (hfs_u32 *)tmp);
797                         if (descr->id == HFS_HDR_DATES) {
798                                 memcpy(tmp + 12, tmp + 4, 4);
799                         } else if ((entry->type == HFS_CDR_FIL) &&
800                                    (entry->u.file.flags & HFS_FIL_LOCK)) {
801                                 hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
802                         } else {
803                                 hfs_put_nl(0, tmp + 12);
804                         }
805                         p = tmp;
806                         limit = 16;
807                         break;
808
809                 case HFS_HDR_FINFO:
810                         p = (char *)&entry->info;
811                         limit = 32;
812                         break;
813
814                 case HFS_HDR_AFPI:
815                         hfs_put_ns(0, tmp);
816                         if ((entry->type == HFS_CDR_FIL) &&
817                             (entry->u.file.flags & HFS_FIL_LOCK)) {
818                                 hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
819                         } else {
820                                 hfs_put_ns(0, tmp + 2);
821                         }                       
822                         p = tmp;
823                         limit = 4;
824                         break;
825
826                 case HFS_HDR_PRODOSI:
827                         /* XXX: this needs to do mac->prodos translations */
828                         memset(tmp, 0, 8); 
829 #if 0
830                         hfs_put_ns(0, tmp); /* access */
831                         hfs_put_ns(0, tmp); /* type */
832                         hfs_put_nl(0, tmp); /* aux type */
833 #endif
834                         p = tmp;
835                         limit = 8;
836                         break;
837
838                 case HFS_HDR_MACI:
839                         hfs_put_ns(0, tmp);
840                         if (entry->type == HFS_CDR_FIL) {
841                                 hfs_put_hs(entry->u.file.flags, tmp + 2);
842                         } else {
843                                 hfs_put_ns(entry->u.dir.flags, tmp + 2);
844                         }
845                         p = tmp;
846                         limit = 4;
847                         break;
848
849                 case HFS_HDR_FNAME:     /* Can't rename a file this way */
850                 case HFS_HDR_DID:       /* can't specify a did this way */
851                 default:
852                         limit = 0;
853                 }
854                 
855                 /* limit the transfer to the available data
856                    of to the stated length of the entry. */
857                 if (length > limit) {
858                         length = limit;
859                 }
860                 offset = pos - start;
861                 left = length - offset;
862                 if (left > count) {
863                         left = count;
864                 }
865                 if (left <= 0) {
866                         continue;
867                 }
868
869                 /* transfer the data from user space */
870                 if (p) {
871                         left -= copy_from_user(p + offset, buf, left);
872                 } else if (fork) {
873                         left = hfs_do_write(inode, fork, offset, buf, left);
874                 }
875
876                 /* process the data */
877                 switch (descr->id) {
878                 case HFS_HDR_OLDI:
879                         set_dates(entry, inode, (hfs_u32 *)tmp);
880                         if (entry->type == HFS_CDR_FIL) {
881                                 hfs_u8 new_flags = entry->u.file.flags;
882
883                                 if (hfs_get_nl(tmp+12) & htonl(HFS_AFP_WRI)) {
884                                         new_flags |= HFS_FIL_LOCK;
885                                 } else {
886                                         new_flags &= ~HFS_FIL_LOCK;
887                                 }
888
889                                 if (new_flags != entry->u.file.flags) {
890                                         entry->u.file.flags = new_flags;
891                                         hfs_cat_mark_dirty(entry);
892                                         hfs_file_fix_mode(entry);
893                                 }
894                         }
895                         break;
896
897                 case HFS_HDR_DATES:
898                         set_dates(entry, inode, (hfs_u32 *)tmp);
899                         break;
900
901                 case HFS_HDR_FINFO:
902                         hfs_cat_mark_dirty(entry);
903                         break;
904
905                 case HFS_HDR_MACI:
906                         if (entry->type == HFS_CDR_DIR) {
907                                 hfs_u16 new_flags = hfs_get_ns(tmp + 2);
908
909                                 if (entry->u.dir.flags != new_flags) {
910                                         entry->u.dir.flags = new_flags;
911                                         hfs_cat_mark_dirty(entry);
912                                 }
913                         } else {
914                                 hfs_u8 new_flags = tmp[3];
915                                 hfs_u8 changed = entry->u.file.flags^new_flags;
916                                 
917                                 if (changed) {
918                                         entry->u.file.flags = new_flags;
919                                         hfs_cat_mark_dirty(entry);
920                                         if (changed & HFS_FIL_LOCK) {
921                                                 hfs_file_fix_mode(entry);
922                                         }
923                                 }
924                         }
925                         break;
926
927                 case HFS_HDR_DATA:
928                 case HFS_HDR_RSRC:
929                         if (left <= 0) {
930                                 if (!written) {
931                                         return left;
932                                 } else {
933                                         goto done;
934                                 }
935                         } else if (fork->lsize > descr->length) {
936                                 descr->length = fork->lsize;
937                         }
938                         break;
939
940                 case HFS_HDR_FNAME:     /* Can't rename a file this way */
941                 case HFS_HDR_DID:       /* Can't specify a did this way */
942                 case HFS_HDR_PRODOSI:   /* not implemented yet */
943                 case HFS_HDR_AFPI:      /* ditto */
944                 default:
945                         break;
946                 }
947
948                 count -= left;
949                 written += left;
950                 pos += left;
951                 buf += left;
952         }
953
954         /* Skip any padding at the end */
955         if (count) {
956                 written += count;
957                 pos += count;
958         }
959                 
960 done:
961         *ppos = pos;
962         if (written > 0) {
963                 if (pos > inode->i_size)
964                         inode->i_size = pos;
965                 inode->i_mtime = inode->i_atime = CURRENT_TIME;
966                 mark_inode_dirty(inode);
967         }
968         return written;
969 }
970
971 /*
972  * hdr_truncate()
973  *
974  * This is the truncate field in the inode_operations structure for
975  * header files.  The purpose is to allocate or release blocks as needed
976  * to satisfy a change in file length.
977  */
978 void hdr_truncate(struct inode *inode, size_t size)
979 {
980         struct hfs_cat_entry *entry = HFS_I(inode)->entry;
981         struct hfs_hdr_layout *layout;
982         int lcv, last;
983
984         inode->i_size = size;
985         if (!HFS_I(inode)->layout) {
986                 HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
987         }
988         layout = HFS_I(inode)->layout;
989
990         last = layout->entries - 1;
991         for (lcv = 0; lcv <= last; ++lcv) {
992                 struct hfs_hdr_descr *descr = layout->order[lcv];
993                 struct hfs_fork *fork;
994                 hfs_u32 offset;
995
996                 if (!descr) {
997                         break;
998                 }
999
1000                 if (descr->id == HFS_HDR_RSRC) {
1001                         fork = &entry->u.file.rsrc_fork;
1002 #if 0
1003 /* Can't yet truncate the data fork via a header file, since there is the
1004  * possibility to truncate via the data file, and the only locking is at
1005  * the inode level.
1006  */
1007                 } else if (descr->id == HFS_HDR_DATA) {
1008                         fork = &entry->u.file.data_fork;
1009 #endif
1010                 } else {
1011                         continue;
1012                 }
1013
1014                 offset = descr->offset;
1015
1016                 if ((lcv != last) && ((offset + descr->length) <= size)) {
1017                         continue;
1018                 }
1019
1020                 if (offset < size) {
1021                         descr->length = size - offset;
1022                 } else {
1023                         descr->length = 0;
1024                 }
1025                 if (fork->lsize != descr->length) {
1026                         fork->lsize = descr->length;
1027                         hfs_extent_adj(fork);
1028                         hfs_cat_mark_dirty(entry);
1029                 }
1030         }
1031 }