File: /usr/src/linux/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 (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 }
1029