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 */
82 NULL
, /* bmap - none */
83 cap_info_truncate
, /* truncate */
84 NULL
, /* permission */
86 NULL
, /* updatepage */
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
;
191 * This is the write() entry in the file_operations structure for CAP
192 * metadata files. The purpose is to transfer up to 'count' bytes
193 * to the file corresponding to 'inode' beginning at offset
194 * '*ppos' from user-space at the address 'buf'.
195 * The return value is the number of bytes actually transferred.
197 static hfs_rwret_t
cap_info_write(struct file
*filp
, const char *buf
,
198 hfs_rwarg_t count
, loff_t
*ppos
)
200 struct inode
*inode
= filp
->f_dentry
->d_inode
;
203 if (!S_ISREG(inode
->i_mode
)) {
204 hfs_warn("hfs_file_write: mode = %07o\n", inode
->i_mode
);
211 pos
= (filp
->f_flags
& O_APPEND
) ? inode
->i_size
: *ppos
;
213 if (pos
> HFS_FORK_MAX
) {
218 if (*ppos
> HFS_FORK_MAX
) {
219 *ppos
= HFS_FORK_MAX
;
220 count
= HFS_FORK_MAX
- pos
;
223 if (*ppos
> inode
->i_size
)
224 inode
->i_size
= *ppos
;
226 /* Only deal with the part we store in memory */
227 if (pos
< sizeof(struct hfs_cap_info
)) {
229 struct hfs_cat_entry
*entry
= HFS_I(inode
)->entry
;
230 struct hfs_cap_info meta
;
232 mem_count
= sizeof(struct hfs_cap_info
) - pos
;
233 if (mem_count
> count
) {
236 end
= pos
+ mem_count
;
238 cap_build_meta(&meta
, entry
);
239 copy_from_user(((char *)&meta
) + pos
, buf
, mem_count
);
241 /* Update finder attributes if changed */
242 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_fndr
)) {
243 memcpy(&entry
->info
, meta
.fi_fndr
, 32);
244 hfs_cat_mark_dirty(entry
);
247 /* Update file flags if changed */
248 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_attr
) &&
249 (entry
->type
== HFS_CDR_FIL
)) {
250 int locked
= hfs_get_ns(&meta
.fi_attr
) &
255 new_flags
= entry
->u
.file
.flags
| HFS_FIL_LOCK
;
257 new_flags
= entry
->u
.file
.flags
& ~HFS_FIL_LOCK
;
260 if (new_flags
!= entry
->u
.file
.flags
) {
261 entry
->u
.file
.flags
= new_flags
;
262 hfs_cat_mark_dirty(entry
);
263 hfs_file_fix_mode(entry
);
267 /* Update CrDat if changed */
268 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_ctime
)) {
270 hfs_h_to_mtime(hfs_get_nl(meta
.fi_ctime
));
271 hfs_cat_mark_dirty(entry
);
274 /* Update MdDat if changed */
275 if (OVERLAPS(pos
, end
, struct hfs_cap_info
, fi_mtime
)) {
277 hfs_h_to_mtime(hfs_get_nl(meta
.fi_mtime
));
278 hfs_cat_mark_dirty(entry
);
282 inode
->i_mtime
= inode
->i_ctime
= CURRENT_TIME
;
287 * cap_info_truncate()
289 * This is the truncate field in the inode_operations structure for
290 * CAP metadata files.
292 static void cap_info_truncate(struct inode
*inode
)
294 /*struct inode *inode = dentry->d_inode;*/
296 if (inode
->i_size
> HFS_FORK_MAX
) {
297 inode
->i_size
= HFS_FORK_MAX
;