1 /*
2 * linux/fs/hfs/file_cap.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU General Public License.
6 *
7 * This file contains the file_ops and inode_ops for the metadata
8 * files under the CAP representation.
9 *
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.
15 *
16 * "XXX" in a comment is a note to myself to consider changing something.
17 *
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.
21 */
22
23 #include "hfs.h"
24 #include <linux/hfs_fs_sb.h>
25 #include <linux/hfs_fs_i.h>
26 #include <linux/hfs_fs.h>
27
28 /*================ Forward declarations ================*/
29 static loff_t cap_info_llseek(struct file *, loff_t,
30 int);
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 ================*/
36
37 /*
38 * OVERLAPS()
39 *
40 * Determines if a given range overlaps the specified structure member
41 */
42 #define OVERLAPS(START, END, TYPE, MEMB) \
43 ((END > offsetof(TYPE, MEMB)) && \
44 (START < offsetof(TYPE, MEMB) + sizeof(((TYPE *)0)->MEMB)))
45
46 /*================ Global variables ================*/
47
48 struct file_operations hfs_cap_info_operations = {
49 llseek: cap_info_llseek,
50 read: cap_info_read,
51 write: cap_info_write,
52 fsync: file_fsync,
53 };
54
55 struct inode_operations hfs_cap_info_inode_operations = {
56 setattr: hfs_notify_change_cap,
57 };
58
59 /*================ File-local functions ================*/
60
61 /*
62 * cap_build_meta()
63 *
64 * Build the metadata structure.
65 */
cap_build_meta(struct hfs_cap_info * meta,struct hfs_cat_entry * entry)66 static void cap_build_meta(struct hfs_cap_info *meta,
67 struct hfs_cat_entry *entry)
68 {
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);
76 }
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);
88 }
89
cap_info_llseek(struct file * file,loff_t offset,int origin)90 static loff_t cap_info_llseek(struct file *file, loff_t offset, int origin)
91 {
92 long long retval;
93
94 switch (origin) {
95 case 2:
96 offset += file->f_dentry->d_inode->i_size;
97 break;
98 case 1:
99 offset += file->f_pos;
100 }
101 retval = -EINVAL;
102 if (offset>=0 && offset<=HFS_FORK_MAX) {
103 if (offset != file->f_pos) {
104 file->f_pos = offset;
105 file->f_reada = 0;
106 file->f_version = ++event;
107 }
108 retval = offset;
109 }
110 return retval;
111 }
112
113 /*
114 * cap_info_read()
115 *
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.
121 */
cap_info_read(struct file * filp,char * buf,hfs_rwarg_t count,loff_t * ppos)122 static hfs_rwret_t cap_info_read(struct file *filp, char *buf,
123 hfs_rwarg_t count, loff_t *ppos)
124 {
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;
128 hfs_u32 pos;
129
130 if (!S_ISREG(inode->i_mode)) {
131 hfs_warn("hfs_cap_info_read: mode = %07o\n", inode->i_mode);
132 return -EINVAL;
133 }
134
135 pos = *ppos;
136 if (pos > HFS_FORK_MAX) {
137 return 0;
138 }
139 size = inode->i_size;
140 if (pos > size) {
141 left = 0;
142 } else {
143 left = size - pos;
144 }
145 if (left > count) {
146 left = count;
147 }
148 if (left <= 0) {
149 return 0;
150 }
151
152 if (pos < sizeof(struct hfs_cap_info)) {
153 int memcount = sizeof(struct hfs_cap_info) - pos;
154 struct hfs_cap_info meta;
155
156 if (memcount > left) {
157 memcount = left;
158 }
159 cap_build_meta(&meta, entry);
160 memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount);
161 left -= memcount;
162 read += memcount;
163 pos += memcount;
164 buf += memcount;
165 }
166
167 if (left > 0) {
168 clear_user(buf, left);
169 pos += left;
170 }
171
172 if (read) {
173 inode->i_atime = CURRENT_TIME;
174 *ppos = pos;
175 mark_inode_dirty(inode);
176 }
177
178 return read;
179 }
180
181 /*
182 * cap_info_write()
183 *
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.
189 */
cap_info_write(struct file * filp,const char * buf,hfs_rwarg_t count,loff_t * ppos)190 static hfs_rwret_t cap_info_write(struct file *filp, const char *buf,
191 hfs_rwarg_t count, loff_t *ppos)
192 {
193 struct inode *inode = filp->f_dentry->d_inode;
194 hfs_u32 pos, last;
195
196 if (!S_ISREG(inode->i_mode)) {
197 hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
198 return -EINVAL;
199 }
200 if (count <= 0) {
201 return 0;
202 }
203
204 pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
205
206 if (pos > HFS_FORK_MAX) {
207 return 0;
208 }
209
210 last = pos + count;
211 if (last > HFS_FORK_MAX) {
212 last = HFS_FORK_MAX;
213 count = HFS_FORK_MAX - pos;
214 }
215
216 if (last > inode->i_size)
217 inode->i_size = last;
218
219 /* Only deal with the part we store in memory */
220 if (pos < sizeof(struct hfs_cap_info)) {
221 int end, mem_count;
222 struct hfs_cat_entry *entry = HFS_I(inode)->entry;
223 struct hfs_cap_info meta;
224
225 mem_count = sizeof(struct hfs_cap_info) - pos;
226 if (mem_count > count) {
227 mem_count = count;
228 }
229 end = pos + mem_count;
230
231 cap_build_meta(&meta, entry);
232 mem_count -= copy_from_user(((char *)&meta) + pos, buf, mem_count);
233
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);
238 }
239
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) &
244 htons(HFS_AFP_WRI);
245 hfs_u8 new_flags;
246
247 if (locked) {
248 new_flags = entry->u.file.flags | HFS_FIL_LOCK;
249 } else {
250 new_flags = entry->u.file.flags & ~HFS_FIL_LOCK;
251 }
252
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);
257 }
258 }
259
260 /* Update CrDat if changed */
261 if (OVERLAPS(pos, end, struct hfs_cap_info, fi_ctime)) {
262 entry->create_date =
263 hfs_h_to_mtime(hfs_get_nl(meta.fi_ctime));
264 hfs_cat_mark_dirty(entry);
265 }
266
267 /* Update MdDat if changed */
268 if (OVERLAPS(pos, end, struct hfs_cap_info, fi_mtime)) {
269 entry->modify_date =
270 hfs_h_to_mtime(hfs_get_nl(meta.fi_mtime));
271 hfs_cat_mark_dirty(entry);
272 }
273 }
274
275 *ppos = last;
276 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
277 mark_inode_dirty(inode);
278 return count;
279 }
280