📄 file_hdr.c
字号:
/* * linux/fs/hfs/file_hdr.c * * Copyright (C) 1995-1997 Paul H. Hargrove * This file may be distributed under the terms of the GNU General Public License. * * This file contains the file_ops and inode_ops for the metadata * files under the AppleDouble and Netatalk representations. * * The source code distributions of Netatalk, versions 1.3.3b2 and * 1.4b2, were used as a specification of the location and format of * files used by Netatalk's afpd. No code from Netatalk appears in * hfs_fs. hfs_fs is not a work ``derived'' from Netatalk 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. * * XXX: Note the reason that there is not bmap() for AppleDouble * header files is that dynamic nature of their structure make it * very difficult to safely mmap them. Maybe in the distant future * I'll get bored enough to implement it. */#include "hfs.h"#include <linux/hfs_fs_sb.h>#include <linux/hfs_fs_i.h>#include <linux/hfs_fs.h>/* prodos types */#define PRODOSI_FTYPE_DIR 0x0F#define PRODOSI_FTYPE_TEXT 0x04#define PRODOSI_FTYPE_8BIT 0xFF#define PRODOSI_FTYPE_16BIT 0xB3#define PRODOSI_AUXTYPE_DIR 0x0200/*================ Forward declarations ================*/static loff_t hdr_llseek(struct file *, loff_t, int);static hfs_rwret_t hdr_read(struct file *, char *, hfs_rwarg_t, loff_t *);static hfs_rwret_t hdr_write(struct file *, const char *, hfs_rwarg_t, loff_t *);/*================ Global variables ================*/struct file_operations hfs_hdr_operations = { llseek: hdr_llseek, read: hdr_read, write: hdr_write, fsync: file_fsync,};struct inode_operations hfs_hdr_inode_operations = { setattr: hfs_notify_change_hdr,};const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = { __constant_htonl(HFS_DBL_MAGIC), /* magic */ __constant_htonl(HFS_HDR_VERSION_2), /* version */ 6, /* entries */ { /* descr[] */ {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name), ~0}, {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16}, {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo), 32}, {HFS_HDR_MACI, offsetof(struct hfs_dbl_hdr, fileinfo), 4}, {HFS_HDR_DID, offsetof(struct hfs_dbl_hdr, cnid), 4}, {HFS_HDR_RSRC, HFS_DBL_HDR_LEN, ~0} }, { /* order[] */ (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[0], (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[1], (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[2], (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[3], (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[4], (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[5] }};const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout = { __constant_htonl(HFS_DBL_MAGIC), /* magic */ __constant_htonl(HFS_HDR_VERSION_2), /* version */ 5, /* entries */ { /* descr[] */ {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name), ~0}, {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16}, {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo), 32}, {HFS_HDR_MACI, offsetof(struct hfs_dbl_hdr, fileinfo), 4}, {HFS_HDR_DID, offsetof(struct hfs_dbl_hdr, cnid), 4} }, { /* order[] */ (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[0], (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[1], (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[2], (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[3], (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[4] }};const struct hfs_hdr_layout hfs_nat2_hdr_layout = { __constant_htonl(HFS_DBL_MAGIC), /* magic */ __constant_htonl(HFS_HDR_VERSION_2), /* version */ 9, /* entries */ { /* descr[] */ {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name), ~0}, {HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment), 0}, {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16}, {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo), 32}, {HFS_HDR_AFPI, offsetof(struct hfs_dbl_hdr, fileinfo), 4}, {HFS_HDR_DID, offsetof(struct hfs_dbl_hdr, cnid), 4}, {HFS_HDR_SNAME, offsetof(struct hfs_dbl_hdr, short_name), ~0}, {HFS_HDR_PRODOSI, offsetof(struct hfs_dbl_hdr, prodosi), 8}, {HFS_HDR_RSRC, HFS_NAT_HDR_LEN, ~0} }, { /* order[] */ (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[5], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[6], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[7], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[8] }};const struct hfs_hdr_layout hfs_nat_hdr_layout = { __constant_htonl(HFS_DBL_MAGIC), /* magic */ __constant_htonl(HFS_HDR_VERSION_1), /* version */ 5, /* entries */ { /* descr[] */ {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name), ~0}, {HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment), 0}, {HFS_HDR_OLDI, offsetof(struct hfs_dbl_hdr, create_time), 16}, {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo), 32}, {HFS_HDR_RSRC, HFS_NAT_HDR_LEN, ~0}, }, { /* order[] */ (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3], (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4] }};/*================ File-local variables ================*/static const char fstype[16] = {'M','a','c','i','n','t','o','s','h',' ',' ',' ',' ',' ',' ',' '};/*================ File-local data types ================*/struct hdr_hdr { hfs_lword_t magic; hfs_lword_t version; hfs_byte_t filler[16]; hfs_word_t entries; hfs_byte_t descrs[12*HFS_HDR_MAX];} __attribute__((packed));/*================ File-local functions ================*//* * dlength() */static int dlength(const struct hfs_hdr_descr *descr, const struct hfs_cat_entry *entry){ hfs_u32 length = descr->length; /* handle auto-sized entries */ if (length == ~0) { switch (descr->id) { case HFS_HDR_DATA: if (entry->type == HFS_CDR_FIL) { length = entry->u.file.data_fork.lsize; } else { length = 0; } break; case HFS_HDR_RSRC: if (entry->type == HFS_CDR_FIL) { length = entry->u.file.rsrc_fork.lsize; } else { length = 0; } break; case HFS_HDR_FNAME: length = entry->key.CName.Len; break; case HFS_HDR_SNAME: default: length = 0; } } return length;}/* * hdr_build_meta() */static void hdr_build_meta(struct hdr_hdr *meta, const struct hfs_hdr_layout *layout, const struct hfs_cat_entry *entry){ const struct hfs_hdr_descr *descr; hfs_byte_t *ptr; int lcv; hfs_put_nl(layout->magic, meta->magic); hfs_put_nl(layout->version, meta->version); if (layout->version == htonl(HFS_HDR_VERSION_1)) { memcpy(meta->filler, fstype, 16); } else { memset(meta->filler, 0, 16); } hfs_put_hs(layout->entries, meta->entries); memset(meta->descrs, 0, sizeof(meta->descrs)); for (lcv = 0, descr = layout->descr, ptr = meta->descrs; lcv < layout->entries; ++lcv, ++descr, ptr += 12) { hfs_put_hl(descr->id, ptr); hfs_put_hl(descr->offset, ptr + 4); hfs_put_hl(dlength(descr, entry), ptr + 8); }}/* * dup_layout () */static struct hfs_hdr_layout *dup_layout(const struct hfs_hdr_layout *old){ struct hfs_hdr_layout *new; int lcv; if (HFS_NEW(new)) { memcpy(new, old, sizeof(*new)); for (lcv = 0; lcv < new->entries; ++lcv) { (char *)(new->order[lcv]) += (char *)new - (char *)old; } } return new;}/* * init_layout() */static inline void init_layout(struct hfs_hdr_layout *layout, const hfs_byte_t *descrs){ struct hfs_hdr_descr **base, **p, **q, *tmp; int lcv, entries = layout->entries; for (lcv = 0; lcv < entries; ++lcv, descrs += 12) { layout->order[lcv] = &layout->descr[lcv]; layout->descr[lcv].id = hfs_get_hl(descrs); layout->descr[lcv].offset = hfs_get_hl(descrs + 4); layout->descr[lcv].length = hfs_get_hl(descrs + 8); } for (lcv = layout->entries; lcv < HFS_HDR_MAX; ++lcv) { layout->order[lcv] = NULL; layout->descr[lcv].id = 0; layout->descr[lcv].offset = 0; layout->descr[lcv].length = 0; } /* Sort the 'order' array using an insertion sort */ base = &layout->order[0]; for (p = (base+1); p < (base+entries); ++p) { q=p; while ((*q)->offset < (*(q-1))->offset) { tmp = *q; *q = *(q-1); *(--q) = tmp; if (q == base) break; } }}/* * adjust_forks() */static inline void adjust_forks(struct hfs_cat_entry *entry, const struct hfs_hdr_layout *layout){ int lcv; for (lcv = 0; lcv < layout->entries; ++lcv) { const struct hfs_hdr_descr *descr = &layout->descr[lcv]; if ((descr->id == HFS_HDR_DATA) && (descr->length != entry->u.file.data_fork.lsize)) { entry->u.file.data_fork.lsize = descr->length; hfs_extent_adj(&entry->u.file.data_fork); } else if ((descr->id == HFS_HDR_RSRC) && (descr->length != entry->u.file.rsrc_fork.lsize)) { entry->u.file.rsrc_fork.lsize = descr->length; hfs_extent_adj(&entry->u.file.rsrc_fork); } }}/* * get_dates() */static void get_dates(const struct hfs_cat_entry *entry, const struct inode *inode, hfs_u32 dates[3]){ dates[0] = hfs_m_to_htime(entry->create_date); dates[1] = hfs_m_to_htime(entry->modify_date); dates[2] = hfs_m_to_htime(entry->backup_date);}/* * set_dates() */static void set_dates(struct hfs_cat_entry *entry, struct inode *inode, const hfs_u32 *dates){ hfs_u32 tmp; tmp = hfs_h_to_mtime(dates[0]); if (entry->create_date != tmp) { entry->create_date = tmp; hfs_cat_mark_dirty(entry); } tmp = hfs_h_to_mtime(dates[1]); if (entry->modify_date != tmp) { entry->modify_date = tmp; inode->i_ctime = inode->i_atime = inode->i_mtime = hfs_h_to_utime(dates[1]); hfs_cat_mark_dirty(entry); } tmp = hfs_h_to_mtime(dates[2]); if (entry->backup_date != tmp) { entry->backup_date = tmp; hfs_cat_mark_dirty(entry); }}loff_t hdr_llseek(struct file *file, loff_t offset, int origin){ long long retval; switch (origin) { case 2: offset += file->f_dentry->d_inode->i_size; break; case 1: offset += file->f_pos; } retval = -EINVAL; if (offset>=0 && offset<file->f_dentry->d_inode->i_size) { if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; file->f_version = ++event; } retval = offset; } return retval;}/* * hdr_read() * * This is the read field in the inode_operations structure for * header files. The purpose is to transfer up to 'count' bytes * from the file corresponding to 'inode', beginning at * 'filp->offset' bytes into the file. The data is transferred to * user-space at the address 'buf'. Returns the number of bytes * successfully transferred. *//* XXX: what about the entry count changing on us? */static hfs_rwret_t hdr_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; const struct hfs_hdr_layout *layout; off_t start, length, offset; off_t pos = *ppos; int left, lcv, read = 0; if (!S_ISREG(inode->i_mode)) { hfs_warn("hfs_hdr_read: mode = %07o\n",inode->i_mode); return -EINVAL; } if (HFS_I(inode)->layout) { layout = HFS_I(inode)->layout; } else { layout = HFS_I(inode)->default_layout; } /* Adjust count to fit within the bounds of the file */ if ((pos >= inode->i_size) || (count <= 0)) { return 0; } else if (count > inode->i_size - pos) { count = inode->i_size - pos; } /* Handle the fixed-location portion */ length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + sizeof(hfs_u16) + layout->entries * (3 * sizeof(hfs_u32)); if (pos < length) { struct hdr_hdr meta; left = length - pos; if (left > count) { left = count; } hdr_build_meta(&meta, layout, entry); left -= copy_to_user(buf, ((char *)&meta) + pos, left); count -= left; read += left; pos += left; buf += left; } if (!count) { goto done; } /* Handle the actual data */ for (lcv = 0; count && (lcv < layout->entries); ++lcv) { const struct hfs_hdr_descr *descr = layout->order[lcv]; struct hfs_fork *fork; char tmp[16], *p; off_t limit; /* stop reading if we run out of descriptors early */ if (!descr) { break; } /* find start and length of this entry */ start = descr->offset; length = dlength(descr, entry); /* Skip to next entry if this one is empty or isn't needed */ if (!length || (pos >= start + length)) { continue; } /* Pad with zeros to the start of this entry if needed */ if (pos < start) { left = start - pos; if (left > count) { left = count; } clear_user(buf, left); count -= left; read += left; pos += left; buf += left; } if (!count) { goto done; } /* locate and/or construct the data for this entry */ fork = NULL; p = NULL; switch (descr->id) { case HFS_HDR_DATA: fork = &entry->u.file.data_fork; limit = fork->lsize; break; case HFS_HDR_RSRC: fork = &entry->u.file.rsrc_fork; limit = fork->lsize; break; case HFS_HDR_FNAME: p = entry->key.CName.Name; limit = entry->key.CName.Len; break; case HFS_HDR_OLDI: case HFS_HDR_DATES: get_dates(entry, inode, (hfs_u32 *)tmp); if (descr->id == HFS_HDR_DATES) { /* XXX: access date. hfsplus actually has this. */ memcpy(tmp + 12, tmp + 4, 4); } else if ((entry->type == HFS_CDR_FIL) && (entry->u.file.flags & HFS_FIL_LOCK)) { hfs_put_hl(HFS_AFP_RDONLY, tmp + 12); } else { hfs_put_nl(0, tmp + 12); } p = tmp; limit = 16; break; case HFS_HDR_FINFO: p = (char *)&entry->info; limit = 32; break; case HFS_HDR_AFPI: /* XXX: this needs to do more mac->afp mappings */ hfs_put_ns(0, tmp); if ((entry->type == HFS_CDR_FIL) && (entry->u.file.flags & HFS_FIL_LOCK)) { hfs_put_hs(HFS_AFP_RDONLY, tmp + 2); } else { hfs_put_ns(0, tmp + 2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -