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.
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 */
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 */
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 */
72 NULL
, /* follow_link */
75 NULL
, /* bmap - XXX: not available since
76 header part has no disk block */
77 hdr_truncate
, /* truncate */
78 NULL
, /* permission */
80 NULL
, /* updatepage */
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 */
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},
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 */
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},
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 */
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},
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 ================*/
152 hfs_byte_t filler
[16];
154 hfs_byte_t descrs
[12*HFS_HDR_MAX
];
157 /*================ File-local functions ================*/
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 */
171 if (entry
->type
== HFS_CDR_FIL
) {
172 length
= entry
->u
.file
.data_fork
.lsize
;
179 if (entry
->type
== HFS_CDR_FIL
) {
180 length
= entry
->u
.file
.rsrc_fork
.lsize
;
187 length
= entry
->key
.CName
.Len
;
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
;
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);
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);
228 static struct hfs_hdr_layout
*dup_layout(const struct hfs_hdr_layout
*old
)
230 struct hfs_hdr_layout
*new;
234 memcpy(new, old
, sizeof(*new));
235 for (lcv
= 0; lcv
< new->entries
; ++lcv
) {
236 (char *)(new->order
[lcv
]) += (char *)new - (char *)old
;
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
) {
268 while ((*q
)->offset
< (*(q
-1))->offset
) {
272 if (q
== base
) break;
280 static inline void adjust_forks(struct hfs_cat_entry
*entry
,
281 const struct hfs_hdr_layout
*layout
)
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
);
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
);
314 static void set_dates(struct hfs_cat_entry
*entry
, struct inode
*inode
,
315 const hfs_u32
*dates
)
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
);
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
;
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
);
364 if (HFS_I(inode
)->layout
) {
365 layout
= HFS_I(inode
)->layout
;
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)) {
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
));
388 hdr_build_meta(&meta
, layout
, entry
);
389 left
-= copy_to_user(buf
, ((char *)&meta
) + pos
, left
);
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
;
406 /* stop reading if we run out of descriptors early */
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
)) {
420 /* Pad with zeros to the start of this entry if needed */
426 clear_user(buf
, left
);
436 /* locate and/or construct the data for this entry */
441 fork
= &entry
->u
.file
.data_fork
;
446 fork
= &entry
->u
.file
.rsrc_fork
;
451 p
= entry
->key
.CName
.Name
;
452 limit
= entry
->key
.CName
.Len
;
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);
464 hfs_put_nl(0, tmp
+ 12);
471 p
= (char *)&entry
->info
;
477 if (entry
->type
== HFS_CDR_FIL
) {
478 hfs_put_hs(entry
->u
.file
.flags
, tmp
+ 2);
480 hfs_put_ns(entry
->u
.dir
.flags
, tmp
+ 2);
490 /* limit the transfer to the available data
491 of to the stated length of the entry. */
492 if (length
> limit
) {
495 offset
= pos
- start
;
496 left
= length
- offset
;
504 /* transfer the data */
506 left
-= copy_to_user(buf
, p
+ offset
, left
);
508 left
= hfs_do_read(inode
, fork
, offset
, buf
, left
,
524 /* Pad the file out with zeros */
526 clear_user(buf
, count
);
533 inode
->i_atime
= CURRENT_TIME
;
535 mark_inode_dirty(inode
);
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;
561 if (!S_ISREG(inode
->i_mode
)) {
562 hfs_warn("hfs_hdr_write: mode = %07o\n", inode
->i_mode
);
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
);
579 hdr_build_meta(&meta
, layout
, entry
);
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
;
607 /* We know for certain how many entries we have, so process them */
608 length
+= layout
->entries
* 3 * sizeof(hfs_u32
);
611 hdr_build_meta(&meta
, layout
, entry
);
619 left
-= copy_from_user(((char *)&meta
) + pos
, buf
, left
);
620 init_layout(layout
, meta
.descrs
);
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
;
641 /* stop writing if we run out of descriptors early */
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
;
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
)) {
670 /* Skip any padding that may exist between entries */
685 /* locate and/or construct the data for this entry */
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
695 fork
= &entry
->u
.file
.data_fork
;
703 fork
= &entry
->u
.file
.rsrc_fork
;
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);
716 hfs_put_nl(0, tmp
+ 12);
723 p
= (char *)&entry
->info
;
729 if (entry
->type
== HFS_CDR_FIL
) {
730 hfs_put_hs(entry
->u
.file
.flags
, tmp
+ 2);
732 hfs_put_ns(entry
->u
.dir
.flags
, tmp
+ 2);
738 case HFS_HDR_FNAME
: /* Can't rename a file this way */
743 /* limit the transfer to the available data
744 of to the stated length of the entry. */
745 if (length
> limit
) {
748 offset
= pos
- start
;
749 left
= length
- offset
;
757 /* transfer the data from user space */
759 left
-= copy_from_user(p
+ offset
, buf
, left
);
761 left
= hfs_do_write(inode
, fork
, offset
, buf
, left
);
764 /* process the data */
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
;
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
);
786 set_dates(entry
, inode
, (hfs_u32
*)tmp
);
790 hfs_cat_mark_dirty(entry
);
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
);
802 hfs_u8 new_flags
= tmp
[3];
803 hfs_u8 changed
= entry
->u
.file
.flags
^new_flags
;
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
);
823 } else if (fork
->lsize
> descr
->length
) {
824 descr
->length
= fork
->lsize
;
828 case HFS_HDR_FNAME
: /* Can't rename a file this way */
839 /* Skip any padding at the end */
848 if (pos
> inode
->i_size
)
850 inode
->i_mtime
= inode
->i_atime
= CURRENT_TIME
;
851 mark_inode_dirty(inode
);
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
;
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
;
885 if (descr
->id
== HFS_HDR_RSRC
) {
886 fork
= &entry
->u
.file
.rsrc_fork
;
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
892 } else if (descr
->id
== HFS_HDR_DATA
) {
893 fork
= &entry
->u
.file
.data_fork
;
899 offset
= descr
->offset
;
901 if ((lcv
!= last
) && ((offset
+ descr
->length
) <= size
)) {
906 descr
->length
= size
- offset
;
910 if (fork
->lsize
!= descr
->length
) {
911 fork
->lsize
= descr
->length
;
912 hfs_extent_adj(fork
);
913 hfs_cat_mark_dirty(entry
);