patch-2.1.78 linux/fs/hfs/file_cap.c

Next file: linux/fs/hfs/file_hdr.c
Previous file: linux/fs/hfs/file.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.77/linux/fs/hfs/file_cap.c linux/fs/hfs/file_cap.c
@@ -0,0 +1,297 @@
+/*
+ * linux/fs/hfs/file_cap.c
+ *
+ * Copyright (C) 1995-1997  Paul H. Hargrove
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ * This file contains the file_ops and inode_ops for the metadata
+ * files under the CAP representation.
+ *
+ * The source code distribution of the Columbia AppleTalk Package for
+ * UNIX, version 6.0, (CAP) was used as a specification of the
+ * location and format of files used by CAP's Aufs.  No code from CAP
+ * appears in hfs_fs.  hfs_fs is not a work ``derived'' from CAP in
+ * the sense of intellectual property law.
+ *
+ * "XXX" in a comment is a note to myself to consider changing something.
+ *
+ * In function preconditions the term "valid" applied to a pointer to
+ * a structure means that the pointer is non-NULL and the structure it
+ * points to has all fields initialized to consistent values.
+ */
+
+#include "hfs.h"
+#include <linux/hfs_fs_sb.h>
+#include <linux/hfs_fs_i.h>
+#include <linux/hfs_fs.h>
+
+/*================ Forward declarations ================*/
+
+static hfs_rwret_t cap_info_read(struct file *, char *,
+				 hfs_rwarg_t, loff_t *);
+static hfs_rwret_t cap_info_write(struct file *, const char *,
+				  hfs_rwarg_t, loff_t *);
+static void cap_info_truncate(struct inode *);
+
+/*================ Function-like macros ================*/
+
+/*
+ * OVERLAPS()
+ *
+ * Determines if a given range overlaps the specified structure member
+ */
+#define OVERLAPS(START, END, TYPE, MEMB) \
+	((END > offsetof(TYPE, MEMB)) && \
+	 (START < offsetof(TYPE, MEMB) + sizeof(((TYPE *)0)->MEMB)))
+
+/*================ Global variables ================*/
+
+static struct file_operations hfs_cap_info_operations = {
+	NULL,			/* lseek - default */
+	cap_info_read,		/* read */
+	cap_info_write,		/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap - not yet */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	file_fsync,		/* fsync - default */
+	NULL,			/* fasync - default */
+	NULL,			/* check_media_change - none */
+	NULL,			/* revalidate - none */
+	NULL			/* lock - none */
+};
+
+struct inode_operations hfs_cap_info_inode_operations = {
+	&hfs_cap_info_operations,	/* default file operations */
+	NULL,				/* create */
+	NULL,				/* lookup */
+	NULL,				/* link */
+	NULL,				/* unlink */
+	NULL,				/* symlink */
+	NULL,				/* mkdir */
+	NULL,				/* rmdir */
+	NULL,				/* mknod */
+	NULL,				/* rename */
+	NULL,				/* readlink */
+	NULL,				/* follow_link */
+	NULL,				/* readpage */
+	NULL,				/* writepage */
+	NULL,				/* bmap - none */
+	cap_info_truncate,		/* truncate */
+	NULL,				/* permission */
+	NULL,				/* smap */
+	NULL,				/* updatepage */
+	NULL				/* revalidata */
+};
+
+/*================ File-local functions ================*/
+
+/*
+ * cap_build_meta()
+ *
+ * Build the metadata structure.
+ */
+static void cap_build_meta(struct hfs_cap_info *meta,
+			   struct hfs_cat_entry *entry)
+{
+	memset(meta, 0, sizeof(*meta));
+	memcpy(meta->fi_fndr, &entry->info, 32);
+	if ((entry->type == HFS_CDR_FIL) &&
+	    (entry->u.file.flags & HFS_FIL_LOCK)) {
+		/* Couple the locked bit of the file to the
+		   AFP {write,rename,delete} inhibit bits. */
+		hfs_put_hs(HFS_AFP_RDONLY, meta->fi_attr);
+	}
+	meta->fi_magic1 = HFS_CAP_MAGIC1;
+	meta->fi_version = HFS_CAP_VERSION;
+	meta->fi_magic = HFS_CAP_MAGIC;
+	meta->fi_bitmap = HFS_CAP_LONGNAME;
+	memcpy(meta->fi_macfilename, entry->key.CName.Name,
+	       entry->key.CName.Len);
+	meta->fi_datemagic = HFS_CAP_DMAGIC;
+	meta->fi_datevalid = HFS_CAP_MDATE | HFS_CAP_CDATE;
+	hfs_put_nl(hfs_m_to_htime(entry->create_date), meta->fi_ctime);
+	hfs_put_nl(hfs_m_to_htime(entry->modify_date), meta->fi_mtime);
+	hfs_put_nl(CURRENT_TIME,                       meta->fi_utime);
+}
+
+/*
+ * cap_info_read()
+ *
+ * This is the read() entry in the file_operations structure for CAP
+ * metadata files.  The purpose is to transfer up to 'count' bytes
+ * from the file corresponding to 'inode' beginning at offset
+ * 'file->f_pos' to user-space at the address 'buf'.  The return value
+ * is the number of bytes actually transferred.
+ */
+static hfs_rwret_t cap_info_read(struct file *filp, char *buf,
+				 hfs_rwarg_t count, loff_t *ppos)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
+	hfs_s32 left, size, read = 0;
+	hfs_u32 pos;
+
+	if (!S_ISREG(inode->i_mode)) {
+		hfs_warn("hfs_cap_info_read: mode = %07o\n", inode->i_mode);
+		return -EINVAL;
+	}
+
+	pos = *ppos;
+	if (pos > HFS_FORK_MAX) {
+		return 0;
+	}
+	size = inode->i_size;
+	if (pos > size) {
+		left = 0;
+	} else {
+		left = size - pos;
+	}
+	if (left > count) {
+		left = count;
+	}
+	if (left <= 0) {
+		return 0;
+	}
+
+	if (pos < sizeof(struct hfs_cap_info)) {
+		int memcount = sizeof(struct hfs_cap_info) - pos;
+		struct hfs_cap_info meta;
+
+		if (memcount > left) {
+			memcount = left;
+		}
+		cap_build_meta(&meta, entry);
+		/* is copy_to_user guaranteed to write memcount? */
+		copy_to_user(buf, ((char *)&meta) + pos, memcount);
+		left -= memcount;
+		read += memcount;
+		pos += memcount;
+		buf += memcount;
+	}
+
+	if (left > 0) {
+		clear_user(buf, left);
+	        pos += left;
+	}
+
+	if (read) {
+		inode->i_atime = CURRENT_TIME;
+		*ppos = pos;
+	}
+
+	return read;
+}
+
+/*
+ * cap_info_write()
+ *
+ * This is the write() entry in the file_operations structure for CAP
+ * metadata files.  The purpose is to transfer up to 'count' bytes
+ * to the file corresponding to 'inode' beginning at offset
+ * '*ppos' from user-space at the address 'buf'.
+ * The return value is the number of bytes actually transferred.
+ */
+static hfs_rwret_t cap_info_write(struct file *filp, const char *buf, 
+				  hfs_rwarg_t count, loff_t *ppos)
+{
+        struct inode *inode = filp->f_dentry->d_inode;
+	hfs_u32 pos;
+
+	if (!S_ISREG(inode->i_mode)) {
+		hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
+		return -EINVAL;
+	}
+	if (count <= 0) {
+		return 0;
+	}
+	
+	pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
+
+	if (pos > HFS_FORK_MAX) {
+		return 0;
+	}
+
+	*ppos += count;
+	if (*ppos > HFS_FORK_MAX) {
+		*ppos = HFS_FORK_MAX;
+		count = HFS_FORK_MAX - pos;
+	}
+
+	if (*ppos > inode->i_size)
+	        inode->i_size = *ppos;
+
+	/* Only deal with the part we store in memory */
+	if (pos < sizeof(struct hfs_cap_info)) {
+		int end, mem_count;
+		struct hfs_cat_entry *entry = HFS_I(inode)->entry;
+		struct hfs_cap_info meta;
+
+		mem_count = sizeof(struct hfs_cap_info) - pos;
+		if (mem_count > count) {
+			mem_count = count;
+		}
+		end = pos + mem_count;
+
+		cap_build_meta(&meta, entry);
+		copy_from_user(((char *)&meta) + pos, buf, mem_count);
+
+		/* Update finder attributes if changed */
+		if (OVERLAPS(pos, end, struct hfs_cap_info, fi_fndr)) {
+			memcpy(&entry->info, meta.fi_fndr, 32);
+			entry->dirt = 1;
+		}
+
+		/* Update file flags if changed */
+		if (OVERLAPS(pos, end, struct hfs_cap_info, fi_attr) &&
+		    (entry->type == HFS_CDR_FIL)) {
+			int locked = hfs_get_ns(&meta.fi_attr) &
+							htons(HFS_AFP_WRI);
+			hfs_u8 new_flags;
+
+			if (locked) {
+				new_flags = entry->u.file.flags | HFS_FIL_LOCK;
+			} else {
+				new_flags = entry->u.file.flags & ~HFS_FIL_LOCK;
+			}
+
+			if (new_flags != entry->u.file.flags) {
+				entry->u.file.flags = new_flags;
+				entry->dirt = 1;
+				hfs_file_fix_mode(entry);
+			}
+		}
+
+		/* Update CrDat if changed */
+		if (OVERLAPS(pos, end, struct hfs_cap_info, fi_ctime)) {
+			entry->create_date =
+				hfs_h_to_mtime(hfs_get_nl(meta.fi_ctime));
+			entry->dirt = 1;
+		}
+
+		/* Update MdDat if changed */
+		if (OVERLAPS(pos, end, struct hfs_cap_info, fi_mtime)) {
+			entry->modify_date =
+				hfs_h_to_mtime(hfs_get_nl(meta.fi_mtime));
+			entry->dirt = 1;
+		}
+	}
+
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	return count;
+}
+
+/*
+ * cap_info_truncate()
+ *
+ * This is the truncate field in the inode_operations structure for
+ * CAP metadata files.
+ */
+static void cap_info_truncate(struct inode *inode)
+{
+	if (inode->i_size > HFS_FORK_MAX) {
+		inode->i_size = HFS_FORK_MAX;
+	}
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov