2 * linux/fs/hfs/file_cap.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 CAP representation.
10 * The source code distribution of the Columbia AppleTalk Package for
11 * UNIX, version 6.0, (CAP) was used as a specification of the
12 * location and format of files used by CAP's Aufs. No code from CAP
13 * appears in hfs_fs. hfs_fs is not a work ``derived'' from CAP in
14 * the 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.
24 #include <linux/hfs_fs_sb.h>
25 #include <linux/hfs_fs_i.h>
26 #include <linux/hfs_fs.h>
28 /*================ Forward declarations ================*/
30 static hfs_rwret_t
cap_info_read(struct file
*, char *,
31 hfs_rwarg_t
, loff_t
*);
32 static hfs_rwret_t
cap_info_write(struct file
*, const char *,
33 hfs_rwarg_t
, loff_t
*);
34 /*================ Function-like macros ================*/
39 * Determines if a given range overlaps the specified structure member
41 #define OVERLAPS(START, END, TYPE, MEMB) \
42 ((END > offsetof(TYPE, MEMB)) && \
43 (START < offsetof(TYPE, MEMB) + sizeof(((TYPE *)0)->MEMB)))
45 /*================ Global variables ================*/
47 struct file_operations hfs_cap_info_operations
= {
49 write
: cap_info_write
,
53 struct inode_operations hfs_cap_info_inode_operations
= {
54 setattr
: hfs_notify_change_cap
,
57 /*================ File-local functions ================*/
62 * Build the metadata structure.
64 static void cap_build_meta(struct hfs_cap_info
*meta
,
65 struct hfs_cat_entry
*entry
)
67 memset(meta
, 0, sizeof(*meta
));
68 memcpy(meta
->fi_fndr
, &entry
->info
, 32);
69 if ((entry
->type
== HFS_CDR_FIL
) &&
70 (entry
->u
.file
.flags
& HFS_FIL_LOCK
)) {
71 /* Couple the locked bit of the file to the
72 AFP {write,rename,delete} inhibit bits. */
73 hfs_put_hs(HFS_AFP_RDONLY
, meta
->fi_attr
);
75 meta
->fi_magic1
= HFS_CAP_MAGIC1
;
76 meta
->fi_version
= HFS_CAP_VERSION
;
77 meta
->fi_magic
= HFS_CAP_MAGIC
;
78 meta
->fi_bitmap
= HFS_CAP_LONGNAME
;
79 memcpy(meta
->fi_macfilename
, entry
->key
.CName
.Name
,
80 entry
->key
.CName
.Len
);
81 meta
->fi_datemagic
= HFS_CAP_DMAGIC
;
82 meta
->fi_datevalid
= HFS_CAP_MDATE
| HFS_CAP_CDATE
;
83 hfs_put_nl(hfs_m_to_htime(entry
->create_date
), meta
->fi_ctime
);
84 hfs_put_nl(hfs_m_to_htime(entry
->modify_date
), meta
->fi_mtime
);
85 hfs_put_nl(CURRENT_TIME
, meta
->fi_utime
);
91 * This is the read() entry in the file_operations structure for CAP
92 * metadata files. The purpose is to transfer up to 'count' bytes
93 * from the file corresponding to 'inode' beginning at offset
94 * 'file->f_pos' to user-space at the address 'buf'. The return value
95 * is the number of bytes actually transferred.
97 static hfs_rwret_t
cap_info_read(struct file
*filp
, char *buf
,
98 hfs_rwarg_t count
, loff_t
*ppos
)
100 struct inode
*inode
= filp
->f_dentry
->d_inode
;
101 struct hfs_cat_entry
*entry
= HFS_I(inode
)->entry
;
102 hfs_s32 left
, size
, read
= 0;
105 if (!S_ISREG(inode
->i_mode
)) {
106 hfs_warn("hfs_cap_info_read: mode = %07o\n", inode
->i_mode
);
111 if (pos
> HFS_FORK_MAX
) {
114 size
= inode
->i_size
;
127 if (pos
< sizeof(struct hfs_cap_info
)) {
128 int memcount
= sizeof(struct hfs_cap_info
) - pos
;
129 struct hfs_cap_info meta
;
131 if (memcount
> left
) {
134 cap_build_meta(&meta
, entry
);
135 memcount
-= copy_to_user(buf
, ((char *)&meta
) + pos
, memcount
);
143 clear_user(buf
, left
);
148 inode
->i_atime
= CURRENT_TIME
;
150 mark_inode_dirty(inode
);
159 * This is the write() entry in the file_operations structure for CAP
160 * metadata files. The purpose is to transfer up to 'count' bytes
161 * to the file corresponding to 'inode' beginning at offset
162 * '*ppos' from user-space at the address 'buf'.
163 * The return value is the number of bytes actually transferred.
165 static hfs_rwret_t
cap_info_write(struct file
*filp
, const char *buf
,
166 hfs_rwarg_t count
, loff_t
*ppos
)
168 struct inode
*inode
= filp
->f_dentry
->d_inode
;
171 if (!S_ISREG(inode
->i_mode
)) {
172 hfs_warn("hfs_file_write: mode = %07o\n", inode
->i_mode
);
179 pos
= (filp
->f_flags
& O_APPEND
) ? inode
->i_size
: *ppos
;
181 if (pos
> HFS_FORK_MAX
) {
186 if (*ppos
> HFS_FORK_MAX
) {
187 *ppos
= HFS_FORK_MAX
;
188 count
= HFS_FORK_MAX
- pos
;
191 if (*ppos
> inode
->i_size
)
192 inode
->i_size
= *ppos
;
194 /* Only deal with the part we store in memory */
195 if (pos
< sizeof(struct hfs_cap_info
)) {
197 struct hfs_cat_entry
*entry
= HFS_I(inode
)->entry
;
198 struct hfs_cap_info meta
;
200 mem_count
= sizeof(struct hfs_cap_info
) - pos
;
201 if (mem_count
> count
) {
204 end
= pos
+ mem_count
;
206 cap_build_meta(&meta
, entry
);
207 mem_count
-= copy_from_user(((char *)&meta
) + pos
, buf
, mem_count
);
209 /* Update finder attributes if changed */
210 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_fndr
)) {
211 memcpy(&entry
->info
, meta
.fi_fndr
, 32);
212 hfs_cat_mark_dirty(entry
);
215 /* Update file flags if changed */
216 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_attr
) &&
217 (entry
->type
== HFS_CDR_FIL
)) {
218 int locked
= hfs_get_ns(&meta
.fi_attr
) &
223 new_flags
= entry
->u
.file
.flags
| HFS_FIL_LOCK
;
225 new_flags
= entry
->u
.file
.flags
& ~HFS_FIL_LOCK
;
228 if (new_flags
!= entry
->u
.file
.flags
) {
229 entry
->u
.file
.flags
= new_flags
;
230 hfs_cat_mark_dirty(entry
);
231 hfs_file_fix_mode(entry
);
235 /* Update CrDat if changed */
236 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_ctime
)) {
238 hfs_h_to_mtime(hfs_get_nl(meta
.fi_ctime
));
239 hfs_cat_mark_dirty(entry
);
242 /* Update MdDat if changed */
243 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_mtime
)) {
245 hfs_h_to_mtime(hfs_get_nl(meta
.fi_mtime
));
246 hfs_cat_mark_dirty(entry
);
250 inode
->i_mtime
= inode
->i_ctime
= CURRENT_TIME
;
251 mark_inode_dirty(inode
);