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 General 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 ================*/
29 static loff_t cap_info_llseek(struct file *, loff_t,
31 static hfs_rwret_t cap_info_read(struct file *, char *,
32 hfs_rwarg_t, loff_t *);
33 static hfs_rwret_t cap_info_write(struct file *, const char *,
34 hfs_rwarg_t, loff_t *);
35 /*================ Function-like macros ================*/
40 * Determines if a given range overlaps the specified structure member
42 #define OVERLAPS(START, END, TYPE, MEMB) \
43 ((END > offsetof(TYPE, MEMB)) && \
44 (START < offsetof(TYPE, MEMB) + sizeof(((TYPE *)0)->MEMB)))
46 /*================ Global variables ================*/
48 struct file_operations hfs_cap_info_operations = {
49 llseek: cap_info_llseek,
51 write: cap_info_write,
55 struct inode_operations hfs_cap_info_inode_operations = {
56 setattr: hfs_notify_change_cap,
59 /*================ File-local functions ================*/
64 * Build the metadata structure.
66 static void cap_build_meta(struct hfs_cap_info *meta,
67 struct hfs_cat_entry *entry)
69 memset(meta, 0, sizeof(*meta));
70 memcpy(meta->fi_fndr, &entry->info, 32);
71 if ((entry->type == HFS_CDR_FIL) &&
72 (entry->u.file.flags & HFS_FIL_LOCK)) {
73 /* Couple the locked bit of the file to the
74 AFP {write,rename,delete} inhibit bits. */
75 hfs_put_hs(HFS_AFP_RDONLY, meta->fi_attr);
77 meta->fi_magic1 = HFS_CAP_MAGIC1;
78 meta->fi_version = HFS_CAP_VERSION;
79 meta->fi_magic = HFS_CAP_MAGIC;
80 meta->fi_bitmap = HFS_CAP_LONGNAME;
81 memcpy(meta->fi_macfilename, entry->key.CName.Name,
82 entry->key.CName.Len);
83 meta->fi_datemagic = HFS_CAP_DMAGIC;
84 meta->fi_datevalid = HFS_CAP_MDATE | HFS_CAP_CDATE;
85 hfs_put_nl(hfs_m_to_htime(entry->create_date), meta->fi_ctime);
86 hfs_put_nl(hfs_m_to_htime(entry->modify_date), meta->fi_mtime);
87 hfs_put_nl(CURRENT_TIME, meta->fi_utime);
90 static loff_t cap_info_llseek(struct file *file, loff_t offset, int origin)
96 offset += file->f_dentry->d_inode->i_size;
99 offset += file->f_pos;
102 if (offset>=0 && offset<=HFS_FORK_MAX) {
103 if (offset != file->f_pos) {
104 file->f_pos = offset;
106 file->f_version = ++event;
116 * This is the read() entry in the file_operations structure for CAP
117 * metadata files. The purpose is to transfer up to 'count' bytes
118 * from the file corresponding to 'inode' beginning at offset
119 * 'file->f_pos' to user-space at the address 'buf'. The return value
120 * is the number of bytes actually transferred.
122 static hfs_rwret_t cap_info_read(struct file *filp, char *buf,
123 hfs_rwarg_t count, loff_t *ppos)
125 struct inode *inode = filp->f_dentry->d_inode;
126 struct hfs_cat_entry *entry = HFS_I(inode)->entry;
127 hfs_s32 left, size, read = 0;
130 if (!S_ISREG(inode->i_mode)) {
131 hfs_warn("hfs_cap_info_read: mode = %07o\n", inode->i_mode);
136 if (pos > HFS_FORK_MAX) {
139 size = inode->i_size;
152 if (pos < sizeof(struct hfs_cap_info)) {
153 int memcount = sizeof(struct hfs_cap_info) - pos;
154 struct hfs_cap_info meta;
156 if (memcount > left) {
159 cap_build_meta(&meta, entry);
160 memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount);
168 clear_user(buf, left);
173 inode->i_atime = CURRENT_TIME;
175 mark_inode_dirty(inode);
184 * This is the write() entry in the file_operations structure for CAP
185 * metadata files. The purpose is to transfer up to 'count' bytes
186 * to the file corresponding to 'inode' beginning at offset
187 * '*ppos' from user-space at the address 'buf'.
188 * The return value is the number of bytes actually transferred.
190 static hfs_rwret_t cap_info_write(struct file *filp, const char *buf,
191 hfs_rwarg_t count, loff_t *ppos)
193 struct inode *inode = filp->f_dentry->d_inode;
196 if (!S_ISREG(inode->i_mode)) {
197 hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
204 pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
206 if (pos > HFS_FORK_MAX) {
211 if (last > HFS_FORK_MAX) {
213 count = HFS_FORK_MAX - pos;
216 if (last > inode->i_size)
217 inode->i_size = last;
219 /* Only deal with the part we store in memory */
220 if (pos < sizeof(struct hfs_cap_info)) {
222 struct hfs_cat_entry *entry = HFS_I(inode)->entry;
223 struct hfs_cap_info meta;
225 mem_count = sizeof(struct hfs_cap_info) - pos;
226 if (mem_count > count) {
229 end = pos + mem_count;
231 cap_build_meta(&meta, entry);
232 mem_count -= copy_from_user(((char *)&meta) + pos, buf, mem_count);
234 /* Update finder attributes if changed */
235 if (OVERLAPS(pos, end, struct hfs_cap_info, fi_fndr)) {
236 memcpy(&entry->info, meta.fi_fndr, 32);
237 hfs_cat_mark_dirty(entry);
240 /* Update file flags if changed */
241 if (OVERLAPS(pos, end, struct hfs_cap_info, fi_attr) &&
242 (entry->type == HFS_CDR_FIL)) {
243 int locked = hfs_get_ns(&meta.fi_attr) &
248 new_flags = entry->u.file.flags | HFS_FIL_LOCK;
250 new_flags = entry->u.file.flags & ~HFS_FIL_LOCK;
253 if (new_flags != entry->u.file.flags) {
254 entry->u.file.flags = new_flags;
255 hfs_cat_mark_dirty(entry);
256 hfs_file_fix_mode(entry);
260 /* Update CrDat if changed */
261 if (OVERLAPS(pos, end, struct hfs_cap_info, fi_ctime)) {
263 hfs_h_to_mtime(hfs_get_nl(meta.fi_ctime));
264 hfs_cat_mark_dirty(entry);
267 /* Update MdDat if changed */
268 if (OVERLAPS(pos, end, struct hfs_cap_info, fi_mtime)) {
270 hfs_h_to_mtime(hfs_get_nl(meta.fi_mtime));
271 hfs_cat_mark_dirty(entry);
276 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
277 mark_inode_dirty(inode);