Merge with 2.3.48.
[linux-2.6/linux-mips.git] / fs / hfs / file_cap.c
blob2268185e6301c87ef1dbced3988b28eb8344df6e
1 /*
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.
23 #include "hfs.h"
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 ================*/
37 * OVERLAPS()
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 = {
48 read: cap_info_read,
49 write: cap_info_write,
50 fsync: file_fsync,
53 struct inode_operations hfs_cap_info_inode_operations = {
54 setattr: hfs_notify_change_cap,
57 /*================ File-local functions ================*/
60 * cap_build_meta()
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);
89 * cap_info_read()
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;
103 hfs_u32 pos;
105 if (!S_ISREG(inode->i_mode)) {
106 hfs_warn("hfs_cap_info_read: mode = %07o\n", inode->i_mode);
107 return -EINVAL;
110 pos = *ppos;
111 if (pos > HFS_FORK_MAX) {
112 return 0;
114 size = inode->i_size;
115 if (pos > size) {
116 left = 0;
117 } else {
118 left = size - pos;
120 if (left > count) {
121 left = count;
123 if (left <= 0) {
124 return 0;
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) {
132 memcount = left;
134 cap_build_meta(&meta, entry);
135 memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount);
136 left -= memcount;
137 read += memcount;
138 pos += memcount;
139 buf += memcount;
142 if (left > 0) {
143 clear_user(buf, left);
144 pos += left;
147 if (read) {
148 inode->i_atime = CURRENT_TIME;
149 *ppos = pos;
150 mark_inode_dirty(inode);
153 return read;
157 * cap_info_write()
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;
169 hfs_u32 pos;
171 if (!S_ISREG(inode->i_mode)) {
172 hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
173 return -EINVAL;
175 if (count <= 0) {
176 return 0;
179 pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
181 if (pos > HFS_FORK_MAX) {
182 return 0;
185 *ppos += count;
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)) {
196 int end, mem_count;
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) {
202 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) &
219 htons(HFS_AFP_WRI);
220 hfs_u8 new_flags;
222 if (locked) {
223 new_flags = entry->u.file.flags | HFS_FIL_LOCK;
224 } else {
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)) {
237 entry->create_date =
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)) {
244 entry->modify_date =
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);
252 return count;