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