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 static void cap_info_truncate(struct inode
*);
36 /*================ Function-like macros ================*/
41 * Determines if a given range overlaps the specified structure member
43 #define OVERLAPS(START, END, TYPE, MEMB) \
44 ((END > offsetof(TYPE, MEMB)) && \
45 (START < offsetof(TYPE, MEMB) + sizeof(((TYPE *)0)->MEMB)))
47 /*================ Global variables ================*/
49 static struct file_operations hfs_cap_info_operations
= {
50 NULL
, /* lseek - default */
51 cap_info_read
, /* read */
52 cap_info_write
, /* write */
53 NULL
, /* readdir - bad */
54 NULL
, /* select - default */
55 NULL
, /* ioctl - default */
56 NULL
, /* mmap - not yet */
57 NULL
, /* no special open code */
59 NULL
, /* no special release code */
60 file_fsync
, /* fsync - default */
61 NULL
, /* fasync - default */
62 NULL
, /* check_media_change - none */
63 NULL
, /* revalidate - none */
64 NULL
/* lock - none */
67 struct inode_operations hfs_cap_info_inode_operations
= {
68 &hfs_cap_info_operations
, /* default file operations */
79 NULL
, /* follow_link */
80 NULL
, /* get_block - none */
84 cap_info_truncate
, /* truncate */
85 NULL
, /* permission */
90 /*================ File-local functions ================*/
95 * Build the metadata structure.
97 static void cap_build_meta(struct hfs_cap_info
*meta
,
98 struct hfs_cat_entry
*entry
)
100 memset(meta
, 0, sizeof(*meta
));
101 memcpy(meta
->fi_fndr
, &entry
->info
, 32);
102 if ((entry
->type
== HFS_CDR_FIL
) &&
103 (entry
->u
.file
.flags
& HFS_FIL_LOCK
)) {
104 /* Couple the locked bit of the file to the
105 AFP {write,rename,delete} inhibit bits. */
106 hfs_put_hs(HFS_AFP_RDONLY
, meta
->fi_attr
);
108 meta
->fi_magic1
= HFS_CAP_MAGIC1
;
109 meta
->fi_version
= HFS_CAP_VERSION
;
110 meta
->fi_magic
= HFS_CAP_MAGIC
;
111 meta
->fi_bitmap
= HFS_CAP_LONGNAME
;
112 memcpy(meta
->fi_macfilename
, entry
->key
.CName
.Name
,
113 entry
->key
.CName
.Len
);
114 meta
->fi_datemagic
= HFS_CAP_DMAGIC
;
115 meta
->fi_datevalid
= HFS_CAP_MDATE
| HFS_CAP_CDATE
;
116 hfs_put_nl(hfs_m_to_htime(entry
->create_date
), meta
->fi_ctime
);
117 hfs_put_nl(hfs_m_to_htime(entry
->modify_date
), meta
->fi_mtime
);
118 hfs_put_nl(CURRENT_TIME
, meta
->fi_utime
);
124 * This is the read() entry in the file_operations structure for CAP
125 * metadata files. The purpose is to transfer up to 'count' bytes
126 * from the file corresponding to 'inode' beginning at offset
127 * 'file->f_pos' to user-space at the address 'buf'. The return value
128 * is the number of bytes actually transferred.
130 static hfs_rwret_t
cap_info_read(struct file
*filp
, char *buf
,
131 hfs_rwarg_t count
, loff_t
*ppos
)
133 struct inode
*inode
= filp
->f_dentry
->d_inode
;
134 struct hfs_cat_entry
*entry
= HFS_I(inode
)->entry
;
135 hfs_s32 left
, size
, read
= 0;
138 if (!S_ISREG(inode
->i_mode
)) {
139 hfs_warn("hfs_cap_info_read: mode = %07o\n", inode
->i_mode
);
144 if (pos
> HFS_FORK_MAX
) {
147 size
= inode
->i_size
;
160 if (pos
< sizeof(struct hfs_cap_info
)) {
161 int memcount
= sizeof(struct hfs_cap_info
) - pos
;
162 struct hfs_cap_info meta
;
164 if (memcount
> left
) {
167 cap_build_meta(&meta
, entry
);
168 memcount
-= copy_to_user(buf
, ((char *)&meta
) + pos
, memcount
);
176 clear_user(buf
, left
);
181 inode
->i_atime
= CURRENT_TIME
;
183 mark_inode_dirty(inode
);
192 * This is the write() entry in the file_operations structure for CAP
193 * metadata files. The purpose is to transfer up to 'count' bytes
194 * to the file corresponding to 'inode' beginning at offset
195 * '*ppos' from user-space at the address 'buf'.
196 * The return value is the number of bytes actually transferred.
198 static hfs_rwret_t
cap_info_write(struct file
*filp
, const char *buf
,
199 hfs_rwarg_t count
, loff_t
*ppos
)
201 struct inode
*inode
= filp
->f_dentry
->d_inode
;
204 if (!S_ISREG(inode
->i_mode
)) {
205 hfs_warn("hfs_file_write: mode = %07o\n", inode
->i_mode
);
212 pos
= (filp
->f_flags
& O_APPEND
) ? inode
->i_size
: *ppos
;
214 if (pos
> HFS_FORK_MAX
) {
219 if (*ppos
> HFS_FORK_MAX
) {
220 *ppos
= HFS_FORK_MAX
;
221 count
= HFS_FORK_MAX
- pos
;
224 if (*ppos
> inode
->i_size
)
225 inode
->i_size
= *ppos
;
227 /* Only deal with the part we store in memory */
228 if (pos
< sizeof(struct hfs_cap_info
)) {
230 struct hfs_cat_entry
*entry
= HFS_I(inode
)->entry
;
231 struct hfs_cap_info meta
;
233 mem_count
= sizeof(struct hfs_cap_info
) - pos
;
234 if (mem_count
> count
) {
237 end
= pos
+ mem_count
;
239 cap_build_meta(&meta
, entry
);
240 mem_count
-= copy_from_user(((char *)&meta
) + pos
, buf
, mem_count
);
242 /* Update finder attributes if changed */
243 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_fndr
)) {
244 memcpy(&entry
->info
, meta
.fi_fndr
, 32);
245 hfs_cat_mark_dirty(entry
);
248 /* Update file flags if changed */
249 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_attr
) &&
250 (entry
->type
== HFS_CDR_FIL
)) {
251 int locked
= hfs_get_ns(&meta
.fi_attr
) &
256 new_flags
= entry
->u
.file
.flags
| HFS_FIL_LOCK
;
258 new_flags
= entry
->u
.file
.flags
& ~HFS_FIL_LOCK
;
261 if (new_flags
!= entry
->u
.file
.flags
) {
262 entry
->u
.file
.flags
= new_flags
;
263 hfs_cat_mark_dirty(entry
);
264 hfs_file_fix_mode(entry
);
268 /* Update CrDat if changed */
269 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_ctime
)) {
271 hfs_h_to_mtime(hfs_get_nl(meta
.fi_ctime
));
272 hfs_cat_mark_dirty(entry
);
275 /* Update MdDat if changed */
276 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_mtime
)) {
278 hfs_h_to_mtime(hfs_get_nl(meta
.fi_mtime
));
279 hfs_cat_mark_dirty(entry
);
283 inode
->i_mtime
= inode
->i_ctime
= CURRENT_TIME
;
284 mark_inode_dirty(inode
);
289 * cap_info_truncate()
291 * This is the truncate field in the inode_operations structure for
292 * CAP metadata files.
294 static void cap_info_truncate(struct inode
*inode
)
296 if (inode
->i_size
> HFS_FORK_MAX
) {
297 inode
->i_size
= HFS_FORK_MAX
;
298 mark_inode_dirty(inode
);