Import 2.2.8pre2
[davej-history.git] / fs / hfs / file_hdr.c
blob9479fab08c90d2cd7a0541e39c02d765c22e3709
1 /*
2 * linux/fs/hfs/file_hdr.c
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU Public License.
7 * This file contains the file_ops and inode_ops for the metadata
8 * files under the AppleDouble and Netatalk representations.
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.
16 * "XXX" in a comment is a note to myself to consider changing something.
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.
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.
28 #include "hfs.h"
29 #include <linux/hfs_fs_sb.h>
30 #include <linux/hfs_fs_i.h>
31 #include <linux/hfs_fs.h>
33 /*================ Forward declarations ================*/
35 static hfs_rwret_t hdr_read(struct file *, char *, hfs_rwarg_t, loff_t *);
36 static hfs_rwret_t hdr_write(struct file *, const char *,
37 hfs_rwarg_t, loff_t *);
38 static void hdr_truncate(struct inode *);
40 /*================ Global variables ================*/
42 static struct file_operations hfs_hdr_operations = {
43 NULL, /* lseek - default */
44 hdr_read, /* read */
45 hdr_write, /* write */
46 NULL, /* readdir - bad */
47 NULL, /* select - default */
48 NULL, /* ioctl - default */
49 NULL, /* mmap - XXX: not yet */
50 NULL, /* no special open code */
51 NULL, /* flush */
52 NULL, /* no special release code */
53 file_fsync, /* fsync - default */
54 NULL, /* fasync - default */
55 NULL, /* check_media_change - none */
56 NULL, /* revalidate - none */
57 NULL /* lock - none */
60 struct inode_operations hfs_hdr_inode_operations = {
61 &hfs_hdr_operations, /* default file operations */
62 NULL, /* create */
63 NULL, /* lookup */
64 NULL, /* link */
65 NULL, /* unlink */
66 NULL, /* symlink */
67 NULL, /* mkdir */
68 NULL, /* rmdir */
69 NULL, /* mknod */
70 NULL, /* rename */
71 NULL, /* readlink */
72 NULL, /* follow_link */
73 NULL, /* readpage */
74 NULL, /* writepage */
75 NULL, /* bmap - XXX: not available since
76 header part has no disk block */
77 hdr_truncate, /* truncate */
78 NULL, /* permission */
79 NULL, /* smap */
80 NULL, /* updatepage */
81 NULL /* revalidate */
84 const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = {
85 __constant_htonl(HFS_DBL_MAGIC), /* magic */
86 __constant_htonl(HFS_HDR_VERSION_2), /* version */
87 5, /* entries */
88 { /* descr[] */
89 {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
90 {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo), 32},
91 {HFS_HDR_MACI, offsetof(struct hfs_dbl_hdr, fileinfo), 4},
92 {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name), ~0},
93 {HFS_HDR_RSRC, HFS_DBL_HDR_LEN, ~0},
95 { /* order[] */
96 (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[0],
97 (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[1],
98 (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[2],
99 (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[3],
100 (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[4],
104 const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout = {
105 __constant_htonl(HFS_DBL_MAGIC), /* magic */
106 __constant_htonl(HFS_HDR_VERSION_2), /* version */
107 4, /* entries */
108 { /* descr[] */
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_MACI, offsetof(struct hfs_dbl_hdr, fileinfo), 4},
112 {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name), ~0},
114 { /* order[] */
115 (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[0],
116 (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[1],
117 (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[2],
118 (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[3],
122 const struct hfs_hdr_layout hfs_nat_hdr_layout = {
123 __constant_htonl(HFS_DBL_MAGIC), /* magic */
124 __constant_htonl(HFS_HDR_VERSION_1), /* version */
125 5, /* entries */
126 { /* descr[] */
127 {HFS_HDR_RSRC, HFS_NAT_HDR_LEN, ~0},
128 {HFS_HDR_FNAME, offsetof(struct hfs_nat_hdr, real_name), ~0},
129 {HFS_HDR_COMNT, offsetof(struct hfs_nat_hdr, comment), 0},
130 {HFS_HDR_OLDI, offsetof(struct hfs_nat_hdr, create_time), 16},
131 {HFS_HDR_FINFO, offsetof(struct hfs_nat_hdr, finderinfo), 32},
133 { /* order[] */
134 (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
135 (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
136 (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
137 (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4],
138 (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
142 /*================ File-local variables ================*/
144 static const char fstype[16] =
145 {'M','a','c','i','n','t','o','s','h',' ',' ',' ',' ',' ',' ',' '};
147 /*================ File-local data types ================*/
149 struct hdr_hdr {
150 hfs_lword_t magic;
151 hfs_lword_t version;
152 hfs_byte_t filler[16];
153 hfs_word_t entries;
154 hfs_byte_t descrs[12*HFS_HDR_MAX];
157 /*================ File-local functions ================*/
160 * dlength()
162 static int dlength(const struct hfs_hdr_descr *descr,
163 const struct hfs_cat_entry *entry)
165 hfs_u32 length = descr->length;
167 /* handle auto-sized entries */
168 if (length == ~0) {
169 switch (descr->id) {
170 case HFS_HDR_DATA:
171 if (entry->type == HFS_CDR_FIL) {
172 length = entry->u.file.data_fork.lsize;
173 } else {
174 length = 0;
176 break;
178 case HFS_HDR_RSRC:
179 if (entry->type == HFS_CDR_FIL) {
180 length = entry->u.file.rsrc_fork.lsize;
181 } else {
182 length = 0;
184 break;
186 case HFS_HDR_FNAME:
187 length = entry->key.CName.Len;
188 break;
190 default:
191 length = 0;
194 return length;
198 * hdr_build_meta()
200 static void hdr_build_meta(struct hdr_hdr *meta,
201 const struct hfs_hdr_layout *layout,
202 const struct hfs_cat_entry *entry)
204 const struct hfs_hdr_descr *descr;
205 hfs_byte_t *ptr;
206 int lcv;
208 hfs_put_nl(layout->magic, meta->magic);
209 hfs_put_nl(layout->version, meta->version);
210 if (layout->version == htonl(HFS_HDR_VERSION_1)) {
211 memcpy(meta->filler, fstype, 16);
212 } else {
213 memset(meta->filler, 0, 16);
215 hfs_put_hs(layout->entries, meta->entries);
216 memset(meta->descrs, 0, sizeof(meta->descrs));
217 for (lcv = 0, descr = layout->descr, ptr = meta->descrs;
218 lcv < layout->entries; ++lcv, ++descr, ptr += 12) {
219 hfs_put_hl(descr->id, ptr);
220 hfs_put_hl(descr->offset, ptr + 4);
221 hfs_put_hl(dlength(descr, entry), ptr + 8);
226 * dup_layout ()
228 static struct hfs_hdr_layout *dup_layout(const struct hfs_hdr_layout *old)
230 struct hfs_hdr_layout *new;
231 int lcv;
233 if (HFS_NEW(new)) {
234 memcpy(new, old, sizeof(*new));
235 for (lcv = 0; lcv < new->entries; ++lcv) {
236 (char *)(new->order[lcv]) += (char *)new - (char *)old;
239 return new;
243 * init_layout()
245 static inline void init_layout(struct hfs_hdr_layout *layout,
246 const hfs_byte_t *descrs)
248 struct hfs_hdr_descr **base, **p, **q, *tmp;
249 int lcv, entries = layout->entries;
251 for (lcv = 0; lcv < entries; ++lcv, descrs += 12) {
252 layout->order[lcv] = &layout->descr[lcv];
253 layout->descr[lcv].id = hfs_get_hl(descrs);
254 layout->descr[lcv].offset = hfs_get_hl(descrs + 4);
255 layout->descr[lcv].length = hfs_get_hl(descrs + 8);
257 for (lcv = layout->entries; lcv < HFS_HDR_MAX; ++lcv) {
258 layout->order[lcv] = NULL;
259 layout->descr[lcv].id = 0;
260 layout->descr[lcv].offset = 0;
261 layout->descr[lcv].length = 0;
264 /* Sort the 'order' array using an insertion sort */
265 base = &layout->order[0];
266 for (p = (base+1); p < (base+entries); ++p) {
267 q=p;
268 while ((*q)->offset < (*(q-1))->offset) {
269 tmp = *q;
270 *q = *(q-1);
271 *(--q) = tmp;
272 if (q == base) break;
278 * adjust_forks()
280 static inline void adjust_forks(struct hfs_cat_entry *entry,
281 const struct hfs_hdr_layout *layout)
283 int lcv;
285 for (lcv = 0; lcv < layout->entries; ++lcv) {
286 const struct hfs_hdr_descr *descr = &layout->descr[lcv];
288 if ((descr->id == HFS_HDR_DATA) &&
289 (descr->length != entry->u.file.data_fork.lsize)) {
290 entry->u.file.data_fork.lsize = descr->length;
291 hfs_extent_adj(&entry->u.file.data_fork);
292 } else if ((descr->id == HFS_HDR_RSRC) &&
293 (descr->length != entry->u.file.rsrc_fork.lsize)) {
294 entry->u.file.rsrc_fork.lsize = descr->length;
295 hfs_extent_adj(&entry->u.file.rsrc_fork);
301 * get_dates()
303 static void get_dates(const struct hfs_cat_entry *entry,
304 const struct inode *inode, hfs_u32 dates[3])
306 dates[0] = hfs_m_to_htime(entry->create_date);
307 dates[1] = hfs_m_to_htime(entry->modify_date);
308 dates[2] = hfs_m_to_htime(entry->backup_date);
312 * set_dates()
314 static void set_dates(struct hfs_cat_entry *entry, struct inode *inode,
315 const hfs_u32 *dates)
317 hfs_u32 tmp;
319 tmp = hfs_h_to_mtime(dates[0]);
320 if (entry->create_date != tmp) {
321 entry->create_date = tmp;
322 hfs_cat_mark_dirty(entry);
324 tmp = hfs_h_to_mtime(dates[1]);
325 if (entry->modify_date != tmp) {
326 entry->modify_date = tmp;
327 inode->i_ctime = inode->i_atime = inode->i_mtime =
328 hfs_h_to_utime(dates[1]);
329 hfs_cat_mark_dirty(entry);
331 tmp = hfs_h_to_mtime(dates[2]);
332 if (entry->backup_date != tmp) {
333 entry->backup_date = tmp;
334 hfs_cat_mark_dirty(entry);
339 * hdr_read()
341 * This is the read field in the inode_operations structure for
342 * header files. The purpose is to transfer up to 'count' bytes
343 * from the file corresponding to 'inode', beginning at
344 * 'filp->offset' bytes into the file. The data is transfered to
345 * user-space at the address 'buf'. Returns the number of bytes
346 * successfully transfered.
348 /* XXX: what about the entry count changing on us? */
349 static hfs_rwret_t hdr_read(struct file * filp, char * buf,
350 hfs_rwarg_t count, loff_t *ppos)
352 struct inode *inode = filp->f_dentry->d_inode;
353 struct hfs_cat_entry *entry = HFS_I(inode)->entry;
354 const struct hfs_hdr_layout *layout;
355 off_t start, length, offset;
356 off_t pos = *ppos;
357 int left, lcv, read = 0;
359 if (!S_ISREG(inode->i_mode)) {
360 hfs_warn("hfs_hdr_read: mode = %07o\n",inode->i_mode);
361 return -EINVAL;
364 if (HFS_I(inode)->layout) {
365 layout = HFS_I(inode)->layout;
366 } else {
367 layout = HFS_I(inode)->default_layout;
370 /* Adjust count to fit within the bounds of the file */
371 if ((pos >= inode->i_size) || (count <= 0)) {
372 return 0;
373 } else if (count > inode->i_size - pos) {
374 count = inode->i_size - pos;
377 /* Handle the fixed-location portion */
378 length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 +
379 sizeof(hfs_u16) + layout->entries * (3 * sizeof(hfs_u32));
380 if (pos < length) {
381 struct hdr_hdr meta;
383 left = length - pos;
384 if (left > count) {
385 left = count;
388 hdr_build_meta(&meta, layout, entry);
389 left -= copy_to_user(buf, ((char *)&meta) + pos, left);
390 count -= left;
391 read += left;
392 pos += left;
393 buf += left;
395 if (!count) {
396 goto done;
399 /* Handle the actual data */
400 for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
401 const struct hfs_hdr_descr *descr = layout->order[lcv];
402 struct hfs_fork *fork;
403 char tmp[16], *p;
404 off_t limit;
406 /* stop reading if we run out of descriptors early */
407 if (!descr) {
408 break;
411 /* find start and length of this entry */
412 start = descr->offset;
413 length = dlength(descr, entry);
415 /* Skip to next entry if this one is empty or isn't needed */
416 if (!length || (pos >= start + length)) {
417 continue;
420 /* Pad with zeros to the start of this entry if needed */
421 if (pos < start) {
422 left = start - pos;
423 if (left > count) {
424 left = count;
426 clear_user(buf, left);
427 count -= left;
428 read += left;
429 pos += left;
430 buf += left;
432 if (!count) {
433 goto done;
436 /* locate and/or construct the data for this entry */
437 fork = NULL;
438 p = NULL;
439 switch (descr->id) {
440 case HFS_HDR_DATA:
441 fork = &entry->u.file.data_fork;
442 limit = fork->lsize;
443 break;
445 case HFS_HDR_RSRC:
446 fork = &entry->u.file.rsrc_fork;
447 limit = fork->lsize;
448 break;
450 case HFS_HDR_FNAME:
451 p = entry->key.CName.Name;
452 limit = entry->key.CName.Len;
453 break;
455 case HFS_HDR_OLDI:
456 case HFS_HDR_DATES:
457 get_dates(entry, inode, (hfs_u32 *)tmp);
458 if (descr->id == HFS_HDR_DATES) {
459 memcpy(tmp + 12, tmp + 4, 4);
460 } else if ((entry->type == HFS_CDR_FIL) &&
461 (entry->u.file.flags & HFS_FIL_LOCK)) {
462 hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
463 } else {
464 hfs_put_nl(0, tmp + 12);
466 p = tmp;
467 limit = 16;
468 break;
470 case HFS_HDR_FINFO:
471 p = (char *)&entry->info;
472 limit = 32;
473 break;
475 case HFS_HDR_MACI:
476 hfs_put_ns(0, tmp);
477 if (entry->type == HFS_CDR_FIL) {
478 hfs_put_hs(entry->u.file.flags, tmp + 2);
479 } else {
480 hfs_put_ns(entry->u.dir.flags, tmp + 2);
482 p = tmp;
483 limit = 4;
484 break;
486 default:
487 limit = 0;
490 /* limit the transfer to the available data
491 of to the stated length of the entry. */
492 if (length > limit) {
493 length = limit;
495 offset = pos - start;
496 left = length - offset;
497 if (left > count) {
498 left = count;
500 if (left <= 0) {
501 continue;
504 /* transfer the data */
505 if (p) {
506 left -= copy_to_user(buf, p + offset, left);
507 } else if (fork) {
508 left = hfs_do_read(inode, fork, offset, buf, left,
509 filp->f_reada != 0);
510 if (left > 0) {
511 filp->f_reada = 1;
512 } else if (!read) {
513 return left;
514 } else {
515 goto done;
518 count -= left;
519 read += left;
520 pos += left;
521 buf += left;
524 /* Pad the file out with zeros */
525 if (count) {
526 clear_user(buf, count);
527 read += count;
528 pos += count;
531 done:
532 if (read) {
533 inode->i_atime = CURRENT_TIME;
534 *ppos = pos;
535 mark_inode_dirty(inode);
537 return read;
541 * hdr_write()
543 * This is the write() entry in the file_operations structure for
544 * header files. The purpose is to transfer up to 'count' bytes
545 * to the file corresponding to 'inode' beginning at offset
546 * '*ppos' from user-space at the address 'buf'.
547 * The return value is the number of bytes actually transferred.
549 static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
550 hfs_rwarg_t count, loff_t *ppos)
552 struct inode *inode = filp->f_dentry->d_inode;
553 struct hfs_cat_entry *entry = HFS_I(inode)->entry;
554 struct hfs_hdr_layout *layout;
555 off_t start, length, offset;
556 int left, lcv, written = 0;
557 struct hdr_hdr meta;
558 int built_meta = 0;
559 off_t pos;
561 if (!S_ISREG(inode->i_mode)) {
562 hfs_warn("hfs_hdr_write: mode = %07o\n", inode->i_mode);
563 return -EINVAL;
565 if (count <= 0) {
566 return 0;
569 pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
571 if (!HFS_I(inode)->layout) {
572 HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
574 layout = HFS_I(inode)->layout;
576 /* Handle the 'magic', 'version', 'filler' and 'entries' fields */
577 length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + sizeof(hfs_u16);
578 if (pos < length) {
579 hdr_build_meta(&meta, layout, entry);
580 built_meta = 1;
582 left = length - pos;
583 if (left > count) {
584 left = count;
587 left -= copy_from_user(((char *)&meta) + pos, buf, left);
588 layout->magic = hfs_get_nl(meta.magic);
589 layout->version = hfs_get_nl(meta.version);
590 layout->entries = hfs_get_hs(meta.entries);
591 if (layout->entries > HFS_HDR_MAX) {
592 /* XXX: should allocate slots dynamically */
593 hfs_warn("hfs_hdr_write: TRUNCATING TO %d "
594 "DESCRIPTORS\n", HFS_HDR_MAX);
595 layout->entries = HFS_HDR_MAX;
598 count -= left;
599 written += left;
600 pos += left;
601 buf += left;
603 if (!count) {
604 goto done;
607 /* We know for certain how many entries we have, so process them */
608 length += layout->entries * 3 * sizeof(hfs_u32);
609 if (pos < length) {
610 if (!built_meta) {
611 hdr_build_meta(&meta, layout, entry);
614 left = length - pos;
615 if (left > count) {
616 left = count;
619 left -= copy_from_user(((char *)&meta) + pos, buf, left);
620 init_layout(layout, meta.descrs);
622 count -= left;
623 written += left;
624 pos += left;
625 buf += left;
627 /* Handle possible size changes for the forks */
628 if (entry->type == HFS_CDR_FIL) {
629 adjust_forks(entry, layout);
630 hfs_cat_mark_dirty(entry);
634 /* Handle the actual data */
635 for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
636 struct hfs_hdr_descr *descr = layout->order[lcv];
637 struct hfs_fork *fork;
638 char tmp[16], *p;
639 off_t limit;
641 /* stop writing if we run out of descriptors early */
642 if (!descr) {
643 break;
646 /* find start and length of this entry */
647 start = descr->offset;
648 if ((descr->id == HFS_HDR_DATA) ||
649 (descr->id == HFS_HDR_RSRC)) {
650 if (entry->type == HFS_CDR_FIL) {
651 length = 0x7fffffff - start;
652 } else {
653 continue;
655 } else {
656 length = dlength(descr, entry);
659 /* Trim length to avoid overlap with the next entry */
660 if (layout->order[lcv+1] &&
661 ((start + length) > layout->order[lcv+1]->offset)) {
662 length = layout->order[lcv+1]->offset - start;
665 /* Skip to next entry if this one is empty or isn't needed */
666 if (!length || (pos >= start + length)) {
667 continue;
670 /* Skip any padding that may exist between entries */
671 if (pos < start) {
672 left = start - pos;
673 if (left > count) {
674 left = count;
676 count -= left;
677 written += left;
678 pos += left;
679 buf += left;
681 if (!count) {
682 goto done;
685 /* locate and/or construct the data for this entry */
686 fork = NULL;
687 p = NULL;
688 switch (descr->id) {
689 case HFS_HDR_DATA:
690 #if 0
691 /* Can't yet write to the data fork via a header file, since there is the
692 * possibility to write via the data file, and the only locking is at the
693 * inode level.
695 fork = &entry->u.file.data_fork;
696 limit = length;
697 #else
698 limit = 0;
699 #endif
700 break;
702 case HFS_HDR_RSRC:
703 fork = &entry->u.file.rsrc_fork;
704 limit = length;
705 break;
707 case HFS_HDR_OLDI:
708 case HFS_HDR_DATES:
709 get_dates(entry, inode, (hfs_u32 *)tmp);
710 if (descr->id == HFS_HDR_DATES) {
711 memcpy(tmp + 12, tmp + 4, 4);
712 } else if ((entry->type == HFS_CDR_FIL) &&
713 (entry->u.file.flags & HFS_FIL_LOCK)) {
714 hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
715 } else {
716 hfs_put_nl(0, tmp + 12);
718 p = tmp;
719 limit = 16;
720 break;
722 case HFS_HDR_FINFO:
723 p = (char *)&entry->info;
724 limit = 32;
725 break;
727 case HFS_HDR_MACI:
728 hfs_put_ns(0, tmp);
729 if (entry->type == HFS_CDR_FIL) {
730 hfs_put_hs(entry->u.file.flags, tmp + 2);
731 } else {
732 hfs_put_ns(entry->u.dir.flags, tmp + 2);
734 p = tmp;
735 limit = 4;
736 break;
738 case HFS_HDR_FNAME: /* Can't rename a file this way */
739 default:
740 limit = 0;
743 /* limit the transfer to the available data
744 of to the stated length of the entry. */
745 if (length > limit) {
746 length = limit;
748 offset = pos - start;
749 left = length - offset;
750 if (left > count) {
751 left = count;
753 if (left <= 0) {
754 continue;
757 /* transfer the data from user space */
758 if (p) {
759 left -= copy_from_user(p + offset, buf, left);
760 } else if (fork) {
761 left = hfs_do_write(inode, fork, offset, buf, left);
764 /* process the data */
765 switch (descr->id) {
766 case HFS_HDR_OLDI:
767 set_dates(entry, inode, (hfs_u32 *)tmp);
768 if (entry->type == HFS_CDR_FIL) {
769 hfs_u8 new_flags = entry->u.file.flags;
771 if (hfs_get_nl(tmp+12) & htonl(HFS_AFP_WRI)) {
772 new_flags |= HFS_FIL_LOCK;
773 } else {
774 new_flags &= ~HFS_FIL_LOCK;
777 if (new_flags != entry->u.file.flags) {
778 entry->u.file.flags = new_flags;
779 hfs_cat_mark_dirty(entry);
780 hfs_file_fix_mode(entry);
783 break;
785 case HFS_HDR_DATES:
786 set_dates(entry, inode, (hfs_u32 *)tmp);
787 break;
789 case HFS_HDR_FINFO:
790 hfs_cat_mark_dirty(entry);
791 break;
793 case HFS_HDR_MACI:
794 if (entry->type == HFS_CDR_DIR) {
795 hfs_u16 new_flags = hfs_get_ns(tmp + 2);
797 if (entry->u.dir.flags != new_flags) {
798 entry->u.dir.flags = new_flags;
799 hfs_cat_mark_dirty(entry);
801 } else {
802 hfs_u8 new_flags = tmp[3];
803 hfs_u8 changed = entry->u.file.flags^new_flags;
805 if (changed) {
806 entry->u.file.flags = new_flags;
807 hfs_cat_mark_dirty(entry);
808 if (changed & HFS_FIL_LOCK) {
809 hfs_file_fix_mode(entry);
813 break;
815 case HFS_HDR_DATA:
816 case HFS_HDR_RSRC:
817 if (left <= 0) {
818 if (!written) {
819 return left;
820 } else {
821 goto done;
823 } else if (fork->lsize > descr->length) {
824 descr->length = fork->lsize;
826 break;
828 case HFS_HDR_FNAME: /* Can't rename a file this way */
829 default:
830 break;
833 count -= left;
834 written += left;
835 pos += left;
836 buf += left;
839 /* Skip any padding at the end */
840 if (count) {
841 written += count;
842 pos += count;
845 done:
846 *ppos = pos;
847 if (written > 0) {
848 if (pos > inode->i_size)
849 inode->i_size = pos;
850 inode->i_mtime = inode->i_atime = CURRENT_TIME;
851 mark_inode_dirty(inode);
853 return written;
857 * hdr_truncate()
859 * This is the truncate field in the inode_operations structure for
860 * header files. The purpose is to allocate or release blocks as needed
861 * to satisfy a change in file length.
863 static void hdr_truncate(struct inode *inode)
865 struct hfs_cat_entry *entry = HFS_I(inode)->entry;
866 struct hfs_hdr_layout *layout;
867 size_t size = inode->i_size;
868 int lcv, last;
870 if (!HFS_I(inode)->layout) {
871 HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
873 layout = HFS_I(inode)->layout;
875 last = layout->entries - 1;
876 for (lcv = 0; lcv <= last; ++lcv) {
877 struct hfs_hdr_descr *descr = layout->order[lcv];
878 struct hfs_fork *fork;
879 hfs_u32 offset;
881 if (!descr) {
882 break;
885 if (descr->id == HFS_HDR_RSRC) {
886 fork = &entry->u.file.rsrc_fork;
887 #if 0
888 /* Can't yet truncate the data fork via a header file, since there is the
889 * possibility to truncate via the data file, and the only locking is at
890 * the inode level.
892 } else if (descr->id == HFS_HDR_DATA) {
893 fork = &entry->u.file.data_fork;
894 #endif
895 } else {
896 continue;
899 offset = descr->offset;
901 if ((lcv != last) && ((offset + descr->length) <= size)) {
902 continue;
905 if (offset < size) {
906 descr->length = size - offset;
907 } else {
908 descr->length = 0;
910 if (fork->lsize != descr->length) {
911 fork->lsize = descr->length;
912 hfs_extent_adj(fork);
913 hfs_cat_mark_dirty(entry);