📄 file_hdr.c
字号:
} p = tmp; limit = 4; break; case HFS_HDR_PRODOSI: /* XXX: this needs to do mac->prodos translations */ memset(tmp, 0, 8);#if 0 hfs_put_ns(0, tmp); /* access */ hfs_put_ns(0, tmp); /* type */ hfs_put_nl(0, tmp); /* aux type */#endif p = tmp; limit = 8; break; case HFS_HDR_MACI: hfs_put_ns(0, tmp); if (entry->type == HFS_CDR_FIL) { hfs_put_hs(entry->u.file.flags, tmp + 2); } else { hfs_put_ns(entry->u.dir.flags, tmp + 2); } p = tmp; limit = 4; break; case HFS_HDR_DID: /* if it's rootinfo, stick the next available did in * the did slot. */ limit = 4; if (entry->cnid == htonl(HFS_ROOT_CNID)) { struct hfs_mdb *mdb = entry->mdb; const struct hfs_name *reserved = HFS_SB(mdb->sys_mdb)->s_reserved2; while (reserved->Len) { if (hfs_streq(reserved->Name, reserved->Len, entry->key.CName.Name, entry->key.CName.Len)) { hfs_put_hl(mdb->next_id, tmp); p = tmp; goto hfs_did_done; } reserved++; } } p = (char *) &entry->cnid;hfs_did_done: break; case HFS_HDR_SNAME: default: limit = 0; } /* limit the transfer to the available data of to the stated length of the entry. */ if (length > limit) { length = limit; } offset = pos - start; left = length - offset; if (left > count) { left = count; } if (left <= 0) { continue; } /* transfer the data */ if (p) { left -= copy_to_user(buf, p + offset, left); } else if (fork) { left = hfs_do_read(inode, fork, offset, buf, left, filp->f_reada != 0); if (left > 0) { filp->f_reada = 1; } else if (!read) { return left; } else { goto done; } } count -= left; read += left; pos += left; buf += left; } /* Pad the file out with zeros */ if (count) { clear_user(buf, count); read += count; pos += count; } done: if (read) { inode->i_atime = CURRENT_TIME; *ppos = pos; mark_inode_dirty(inode); } return read;}/* * hdr_write() * * This is the write() entry in the file_operations structure for * header 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 hdr_write(struct file *filp, const 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; struct hfs_hdr_layout *layout; off_t start, length, offset; int left, lcv, written = 0; struct hdr_hdr meta; int built_meta = 0; off_t pos; if (!S_ISREG(inode->i_mode)) { hfs_warn("hfs_hdr_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 (!HFS_I(inode)->layout) { HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout); } layout = HFS_I(inode)->layout; /* Handle the 'magic', 'version', 'filler' and 'entries' fields */ length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + sizeof(hfs_u16); if (pos < length) { hdr_build_meta(&meta, layout, entry); built_meta = 1; left = length - pos; if (left > count) { left = count; } left -= copy_from_user(((char *)&meta) + pos, buf, left); layout->magic = hfs_get_nl(meta.magic); layout->version = hfs_get_nl(meta.version); layout->entries = hfs_get_hs(meta.entries); if (layout->entries > HFS_HDR_MAX) { /* XXX: should allocate slots dynamically */ hfs_warn("hfs_hdr_write: TRUNCATING TO %d " "DESCRIPTORS\n", HFS_HDR_MAX); layout->entries = HFS_HDR_MAX; } count -= left; written += left; pos += left; buf += left; } if (!count) { goto done; } /* We know for certain how many entries we have, so process them */ length += layout->entries * 3 * sizeof(hfs_u32); if (pos < length) { if (!built_meta) { hdr_build_meta(&meta, layout, entry); } left = length - pos; if (left > count) { left = count; } left -= copy_from_user(((char *)&meta) + pos, buf, left); init_layout(layout, meta.descrs); count -= left; written += left; pos += left; buf += left; /* Handle possible size changes for the forks */ if (entry->type == HFS_CDR_FIL) { adjust_forks(entry, layout); hfs_cat_mark_dirty(entry); } } /* Handle the actual data */ for (lcv = 0; count && (lcv < layout->entries); ++lcv) { struct hfs_hdr_descr *descr = layout->order[lcv]; struct hfs_fork *fork; char tmp[16], *p; off_t limit; /* stop writing if we run out of descriptors early */ if (!descr) { break; } /* find start and length of this entry */ start = descr->offset; if ((descr->id == HFS_HDR_DATA) || (descr->id == HFS_HDR_RSRC)) { if (entry->type == HFS_CDR_FIL) { length = 0x7fffffff - start; } else { continue; } } else { length = dlength(descr, entry); } /* Trim length to avoid overlap with the next entry */ if (layout->order[lcv+1] && ((start + length) > layout->order[lcv+1]->offset)) { length = layout->order[lcv+1]->offset - start; } /* Skip to next entry if this one is empty or isn't needed */ if (!length || (pos >= start + length)) { continue; } /* Skip any padding that may exist between entries */ if (pos < start) { left = start - pos; if (left > count) { left = count; } count -= left; written += 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:#if 0/* Can't yet write to the data fork via a header file, since there is the * possibility to write via the data file, and the only locking is at the * inode level. */ fork = &entry->u.file.data_fork; limit = length;#else limit = 0;#endif break; case HFS_HDR_RSRC: fork = &entry->u.file.rsrc_fork; limit = length; break; case HFS_HDR_OLDI: case HFS_HDR_DATES: get_dates(entry, inode, (hfs_u32 *)tmp); if (descr->id == HFS_HDR_DATES) { 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: 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); } p = tmp; limit = 4; break; case HFS_HDR_PRODOSI: /* XXX: this needs to do mac->prodos translations */ memset(tmp, 0, 8); #if 0 hfs_put_ns(0, tmp); /* access */ hfs_put_ns(0, tmp); /* type */ hfs_put_nl(0, tmp); /* aux type */#endif p = tmp; limit = 8; break; case HFS_HDR_MACI: hfs_put_ns(0, tmp); if (entry->type == HFS_CDR_FIL) { hfs_put_hs(entry->u.file.flags, tmp + 2); } else { hfs_put_ns(entry->u.dir.flags, tmp + 2); } p = tmp; limit = 4; break; case HFS_HDR_FNAME: /* Can't rename a file this way */ case HFS_HDR_DID: /* can't specify a did this way */ default: limit = 0; } /* limit the transfer to the available data of to the stated length of the entry. */ if (length > limit) { length = limit; } offset = pos - start; left = length - offset; if (left > count) { left = count; } if (left <= 0) { continue; } /* transfer the data from user space */ if (p) { left -= copy_from_user(p + offset, buf, left); } else if (fork) { left = hfs_do_write(inode, fork, offset, buf, left); } /* process the data */ switch (descr->id) { case HFS_HDR_OLDI: set_dates(entry, inode, (hfs_u32 *)tmp); if (entry->type == HFS_CDR_FIL) { hfs_u8 new_flags = entry->u.file.flags; if (hfs_get_nl(tmp+12) & htonl(HFS_AFP_WRI)) { new_flags |= HFS_FIL_LOCK; } else { new_flags &= ~HFS_FIL_LOCK; } if (new_flags != entry->u.file.flags) { entry->u.file.flags = new_flags; hfs_cat_mark_dirty(entry); hfs_file_fix_mode(entry); } } break; case HFS_HDR_DATES: set_dates(entry, inode, (hfs_u32 *)tmp); break; case HFS_HDR_FINFO: hfs_cat_mark_dirty(entry); break; case HFS_HDR_MACI: if (entry->type == HFS_CDR_DIR) { hfs_u16 new_flags = hfs_get_ns(tmp + 2); if (entry->u.dir.flags != new_flags) { entry->u.dir.flags = new_flags; hfs_cat_mark_dirty(entry); } } else { hfs_u8 new_flags = tmp[3]; hfs_u8 changed = entry->u.file.flags^new_flags; if (changed) { entry->u.file.flags = new_flags; hfs_cat_mark_dirty(entry); if (changed & HFS_FIL_LOCK) { hfs_file_fix_mode(entry); } } } break; case HFS_HDR_DATA: case HFS_HDR_RSRC: if (left <= 0) { if (!written) { return left; } else { goto done; } } else if (fork->lsize > descr->length) { descr->length = fork->lsize; } break; case HFS_HDR_FNAME: /* Can't rename a file this way */ case HFS_HDR_DID: /* Can't specify a did this way */ case HFS_HDR_PRODOSI: /* not implemented yet */ case HFS_HDR_AFPI: /* ditto */ default: break; } count -= left; written += left; pos += left; buf += left; } /* Skip any padding at the end */ if (count) { written += count; pos += count; } done: *ppos = pos; if (written > 0) { if (pos > inode->i_size) inode->i_size = pos; inode->i_mtime = inode->i_atime = CURRENT_TIME; mark_inode_dirty(inode); } return written;}/* * hdr_truncate() * * This is the truncate field in the inode_operations structure for * header files. The purpose is to allocate or release blocks as needed * to satisfy a change in file length. */void hdr_truncate(struct inode *inode, size_t size){ struct hfs_cat_entry *entry = HFS_I(inode)->entry; struct hfs_hdr_layout *layout; int lcv, last; inode->i_size = size; if (!HFS_I(inode)->layout) { HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout); } layout = HFS_I(inode)->layout; last = layout->entries - 1; for (lcv = 0; lcv <= last; ++lcv) { struct hfs_hdr_descr *descr = layout->order[lcv]; struct hfs_fork *fork; hfs_u32 offset; if (!descr) { break; } if (descr->id == HFS_HDR_RSRC) { fork = &entry->u.file.rsrc_fork;#if 0/* Can't yet truncate the data fork via a header file, since there is the * possibility to truncate via the data file, and the only locking is at * the inode level. */ } else if (descr->id == HFS_HDR_DATA) { fork = &entry->u.file.data_fork;#endif } else { continue; } offset = descr->offset; if ((lcv != last) && ((offset + descr->length) <= size)) { continue; } if (offset < size) { descr->length = size - offset; } else { descr->length = 0; } if (fork->lsize != descr->length) { fork->lsize = descr->length; hfs_extent_adj(fork); hfs_cat_mark_dirty(entry); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -