1
2
3#include "hfs.h"
4#include <linux/hfs_fs_sb.h>
5#include <linux/hfs_fs_i.h>
6#include <linux/hfs_fs.h>
7
8/* prodos types */
9#define PRODOSI_FTYPE_DIR   0x0F
10#define PRODOSI_FTYPE_TEXT  0x04
11#define PRODOSI_FTYPE_8BIT  0xFF
12#define PRODOSI_FTYPE_16BIT 0xB3
13
14#define PRODOSI_AUXTYPE_DIR 0x0200
15
16/*================ Forward declarations ================*/
17static loff_t      hdr_llseek(struct file *, loff_t, int);
18static hfs_rwret_t hdr_read(struct file *, char *, hfs_rwarg_t, loff_t *);
19static hfs_rwret_t hdr_write(struct file *, const char *,
20			     hfs_rwarg_t, loff_t *);
21/*================ Global variables ================*/
22
23struct file_operations hfs_hdr_operations = {
24	llseek:		hdr_llseek,
25	read:		hdr_read,
26	write:		hdr_write,
27	fsync:		file_fsync,
28};
29
30struct inode_operations hfs_hdr_inode_operations = {
31	setattr:	hfs_notify_change_hdr,
32};
33
34const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = {
35	__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
36	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
37	6,					/* entries */
38	{					/* descr[] */
39		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
40		{HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
41		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
42		{HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
43		{HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4},
44		{HFS_HDR_RSRC,  HFS_DBL_HDR_LEN,                           ~0}
45	},
46	{					/* order[] */
47		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[0],
48		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[1],
49		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[2],
50		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[3],
51		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[4],
52		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[5]
53	}
54};
55
56const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout = {
57	__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
58	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
59	5,					/* entries */
60	{					/* descr[] */
61		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
62		{HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
63		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
64		{HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
65		{HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4}
66	},
67	{					/* order[] */
68		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[0],
69		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[1],
70		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[2],
71		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[3],
72		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[4]
73	}
74};
75
76const struct hfs_hdr_layout hfs_nat2_hdr_layout = {
77	__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
78	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
79	9,					/* entries */
80	{					/* descr[] */
81		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
82		{HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
83		{HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
84		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
85		{HFS_HDR_AFPI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
86		{HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4},
87		{HFS_HDR_SNAME,  offsetof(struct hfs_dbl_hdr, short_name), ~0},
88		{HFS_HDR_PRODOSI,  offsetof(struct hfs_dbl_hdr, prodosi),   8},
89		{HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0}
90	},
91	{					/* order[] */
92		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
93		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
94		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
95		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
96		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4],
97		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[5],
98		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[6],
99		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[7],
100		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[8]
101	}
102};
103
104const struct hfs_hdr_layout hfs_nat_hdr_layout = {
105	__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
106	__constant_htonl(HFS_HDR_VERSION_1),	/* version */
107	5,					/* entries */
108	{					/* descr[] */
109		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
110		{HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
111		{HFS_HDR_OLDI,  offsetof(struct hfs_dbl_hdr, create_time), 16},
112		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
113		{HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0},
114	},
115	{					/* order[] */
116		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
117		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
118		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
119		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
120		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4]
121	}
122};
123
124/*================ File-local variables ================*/
125
126static const char fstype[16] =
127	{'M','a','c','i','n','t','o','s','h',' ',' ',' ',' ',' ',' ',' '};
128
129/*================ File-local data types ================*/
130
131struct hdr_hdr {
132        hfs_lword_t	magic;
133        hfs_lword_t	version;
134        hfs_byte_t	filler[16];
135        hfs_word_t	entries;
136        hfs_byte_t	descrs[12*HFS_HDR_MAX];
137}  __attribute__((packed));
138
139/*================ File-local functions ================*/
140
141/*
142 * dlength()
143 */
144static int dlength(const struct hfs_hdr_descr *descr,
145		   const struct hfs_cat_entry *entry)
146{
147	hfs_u32 length = descr->length;
148
149	/* handle auto-sized entries */
150	if (length == ~0) {
151		switch (descr->id) {
152		case HFS_HDR_DATA:
153			if (entry->type == HFS_CDR_FIL) {
154				length = entry->u.file.data_fork.lsize;
155			} else {
156				length = 0;
157			}
158			break;
159
160		case HFS_HDR_RSRC:
161			if (entry->type == HFS_CDR_FIL) {
162				length = entry->u.file.rsrc_fork.lsize;
163			} else {
164				length = 0;
165			}
166			break;
167
168		case HFS_HDR_FNAME:
169			length = entry->key.CName.Len;
170			break;
171
172		case HFS_HDR_SNAME:
173		default:
174			length = 0;
175		}
176	}
177	return length;
178}
179
180/*
181 * hdr_build_meta()
182 */
183static void hdr_build_meta(struct hdr_hdr *meta,
184			   const struct hfs_hdr_layout *layout,
185			   const struct hfs_cat_entry *entry)
186{
187	const struct hfs_hdr_descr *descr;
188	hfs_byte_t *ptr;
189	int lcv;
190
191	hfs_put_nl(layout->magic,   meta->magic);
192	hfs_put_nl(layout->version, meta->version);
193	if (layout->version == htonl(HFS_HDR_VERSION_1)) {
194		memcpy(meta->filler, fstype, 16);
195	} else {
196		memset(meta->filler, 0, 16);
197	}
198	hfs_put_hs(layout->entries, meta->entries);
199	memset(meta->descrs, 0, sizeof(meta->descrs));
200	for (lcv = 0, descr = layout->descr, ptr = meta->descrs;
201	     lcv < layout->entries; ++lcv, ++descr, ptr += 12) {
202		hfs_put_hl(descr->id,             ptr);
203		hfs_put_hl(descr->offset,         ptr + 4);
204		hfs_put_hl(dlength(descr, entry), ptr + 8);
205	}
206}
207
208/*
209 * dup_layout ()
210 */
211static struct hfs_hdr_layout *dup_layout(const struct hfs_hdr_layout *old)
212{
213	struct hfs_hdr_layout *new;
214	int lcv;
215
216	if (HFS_NEW(new)) {
217		memcpy(new, old, sizeof(*new));
218		for (lcv = 0; lcv < new->entries; ++lcv) {
219			(char *)(new->order[lcv]) += (char *)new - (char *)old;
220		}
221	}
222	return new;
223}
224
225/*
226 * init_layout()
227 */
228static inline void init_layout(struct hfs_hdr_layout *layout,
229			       const hfs_byte_t *descrs)
230{
231	struct hfs_hdr_descr **base, **p, **q, *tmp;
232	int lcv, entries = layout->entries;
233
234	for (lcv = 0; lcv < entries; ++lcv, descrs += 12) {
235		layout->order[lcv] = &layout->descr[lcv];
236		layout->descr[lcv].id     = hfs_get_hl(descrs);
237		layout->descr[lcv].offset = hfs_get_hl(descrs + 4);
238		layout->descr[lcv].length = hfs_get_hl(descrs + 8);
239	}
240	for (lcv = layout->entries; lcv < HFS_HDR_MAX; ++lcv) {
241		layout->order[lcv] = NULL;
242		layout->descr[lcv].id     = 0;
243		layout->descr[lcv].offset = 0;
244		layout->descr[lcv].length = 0;
245	}
246
247	/* Sort the 'order' array using an insertion sort */
248	base = &layout->order[0];
249	for (p = (base+1); p < (base+entries); ++p) {
250		q=p;
251		while ((*q)->offset < (*(q-1))->offset) {
252			tmp = *q;
253			*q = *(q-1);
254			*(--q) = tmp;
255			if (q == base) break;
256		}
257	}
258}
259
260/*
261 * adjust_forks()
262 */
263static inline void adjust_forks(struct hfs_cat_entry *entry,
264				const struct hfs_hdr_layout *layout)
265{
266	int lcv;
267
268	for (lcv = 0; lcv < layout->entries; ++lcv) {
269		const struct hfs_hdr_descr *descr = &layout->descr[lcv];
270
271		if ((descr->id == HFS_HDR_DATA) &&
272		    (descr->length != entry->u.file.data_fork.lsize)) {
273			entry->u.file.data_fork.lsize = descr->length;
274			hfs_extent_adj(&entry->u.file.data_fork);
275		} else if ((descr->id == HFS_HDR_RSRC) &&
276			   (descr->length != entry->u.file.rsrc_fork.lsize)) {
277			entry->u.file.rsrc_fork.lsize = descr->length;
278			hfs_extent_adj(&entry->u.file.rsrc_fork);
279		}
280	}
281}
282
283/*
284 * get_dates()
285 */
286static void get_dates(const struct hfs_cat_entry *entry,
287		      const struct inode *inode,  hfs_u32 dates[3])
288{
289	dates[0] = hfs_m_to_htime(entry->create_date);
290	dates[1] = hfs_m_to_htime(entry->modify_date);
291	dates[2] = hfs_m_to_htime(entry->backup_date);
292}
293
294/*
295 * set_dates()
296 */
297static void set_dates(struct hfs_cat_entry *entry, struct inode *inode,
298		      const hfs_u32 *dates)
299{
300	hfs_u32 tmp;
301
302	tmp = hfs_h_to_mtime(dates[0]);
303	if (entry->create_date != tmp) {
304		entry->create_date = tmp;
305		hfs_cat_mark_dirty(entry);
306	}
307	tmp = hfs_h_to_mtime(dates[1]);
308	if (entry->modify_date != tmp) {
309		entry->modify_date = tmp;
310		inode->i_ctime = inode->i_atime = inode->i_mtime =
311			hfs_h_to_utime(dates[1]);
312		hfs_cat_mark_dirty(entry);
313	}
314	tmp = hfs_h_to_mtime(dates[2]);
315	if (entry->backup_date != tmp) {
316		entry->backup_date = tmp;
317		hfs_cat_mark_dirty(entry);
318	}
319}
320
321loff_t hdr_llseek(struct file *file, loff_t offset, int origin)
322{
323	long long retval;
324
325	switch (origin) {
326		case 2:
327			offset += file->f_dentry->d_inode->i_size;
328			break;
329		case 1:
330			offset += file->f_pos;
331	}
332	retval = -EINVAL;
333	if (offset>=0 && offset<file->f_dentry->d_inode->i_size) {
334		if (offset != file->f_pos) {
335			file->f_pos = offset;
336			file->f_reada = 0;
337			file->f_version = ++event;
338		}
339		retval = offset;
340	}
341	return retval;
342}
343
344/*
345 * hdr_read()
346 *
347 * This is the read field in the inode_operations structure for
348 * header files.  The purpose is to transfer up to 'count' bytes
349 * from the file corresponding to 'inode', beginning at
350 * 'filp->offset' bytes into the file.	The data is transferred to
351 * user-space at the address 'buf'.  Returns the number of bytes
352 * successfully transferred.
353 */
354static hfs_rwret_t hdr_read(struct file * filp, char * buf,
355			    hfs_rwarg_t count, loff_t *ppos)
356{
357	struct inode *inode = filp->f_dentry->d_inode;
358	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
359	const struct hfs_hdr_layout *layout;
360	off_t start, length, offset;
361	off_t pos = *ppos;
362	int left, lcv, read = 0;
363
364	if (!S_ISREG(inode->i_mode)) {
365		hfs_warn("hfs_hdr_read: mode = %07o\n",inode->i_mode);
366		return -EINVAL;
367	}
368
369	if (HFS_I(inode)->layout) {
370		layout = HFS_I(inode)->layout;
371	} else {
372		layout = HFS_I(inode)->default_layout;
373	}
374
375	/* Adjust count to fit within the bounds of the file */
376	if ((pos >= inode->i_size) || (count <= 0)) {
377		return 0;
378	} else if (count > inode->i_size - pos) {
379		count = inode->i_size - pos;
380	}
381
382	/* Handle the fixed-location portion */
383	length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 +
384		 sizeof(hfs_u16) + layout->entries * (3 * sizeof(hfs_u32));
385	if (pos < length) {
386		struct hdr_hdr meta;
387
388		left = length - pos;
389		if (left > count) {
390			left = count;
391		}
392
393		hdr_build_meta(&meta, layout, entry);
394		left -= copy_to_user(buf, ((char *)&meta) + pos, left);
395		count -= left;
396		read += left;
397		pos += left;
398		buf += left;
399	}
400	if (!count) {
401		goto done;
402	}
403
404	/* Handle the actual data */
405	for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
406		const struct hfs_hdr_descr *descr = layout->order[lcv];
407		struct hfs_fork *fork;
408		char tmp[16], *p;
409		off_t limit;
410
411		/* stop reading if we run out of descriptors early */
412		if (!descr) {
413			break;
414		}
415
416		/* find start and length of this entry */
417		start = descr->offset;
418		length = dlength(descr, entry);
419
420		/* Skip to next entry if this one is empty or isn't needed */
421		if (!length || (pos >= start + length)) {
422			continue;
423		}
424
425		/* Pad with zeros to the start of this entry if needed */
426		if (pos < start) {
427			left = start - pos;
428			if (left > count) {
429				left = count;
430			}
431			clear_user(buf, left);
432			count -= left;
433			read += left;
434			pos += left;
435			buf += left;
436		}
437		if (!count) {
438			goto done;
439		}
440
441		/* locate and/or construct the data for this entry */
442		fork = NULL;
443		p = NULL;
444		switch (descr->id) {
445		case HFS_HDR_DATA:
446			fork = &entry->u.file.data_fork;
447			limit = fork->lsize;
448			break;
449
450		case HFS_HDR_RSRC:
451			fork = &entry->u.file.rsrc_fork;
452			limit = fork->lsize;
453			break;
454
455		case HFS_HDR_FNAME:
456			p = entry->key.CName.Name;
457			limit = entry->key.CName.Len;
458			break;
459
460		case HFS_HDR_OLDI:
461		case HFS_HDR_DATES:
462			get_dates(entry, inode, (hfs_u32 *)tmp);
463			if (descr->id == HFS_HDR_DATES) {
464				memcpy(tmp + 12, tmp + 4, 4);
465			} else if ((entry->type == HFS_CDR_FIL) &&
466				   (entry->u.file.flags & HFS_FIL_LOCK)) {
467				hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
468			} else {
469				hfs_put_nl(0, tmp + 12);
470			}
471			p = tmp;
472			limit = 16;
473			break;
474
475		case HFS_HDR_FINFO:
476			p = (char *)&entry->info;
477			limit = 32;
478			break;
479
480		case HFS_HDR_AFPI:
481			hfs_put_ns(0, tmp);
482			if ((entry->type == HFS_CDR_FIL) &&
483			    (entry->u.file.flags & HFS_FIL_LOCK)) {
484				hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
485			} else {
486				hfs_put_ns(0, tmp + 2);
487			}
488			p = tmp;
489			limit = 4;
490		        break;
491
492		case HFS_HDR_PRODOSI:
493			memset(tmp, 0, 8);
494			p = tmp;
495			limit = 8;
496		        break;
497
498		case HFS_HDR_MACI:
499			hfs_put_ns(0, tmp);
500			if (entry->type == HFS_CDR_FIL) {
501				hfs_put_hs(entry->u.file.flags, tmp + 2);
502			} else {
503				hfs_put_ns(entry->u.dir.flags, tmp + 2);
504			}
505			p = tmp;
506			limit = 4;
507			break;
508
509		case HFS_HDR_DID:
510		        /* if it's rootinfo, stick the next available did in
511			 * the did slot. */
512			limit = 4;
513			if (entry->cnid == htonl(HFS_ROOT_CNID)) {
514				struct hfs_mdb *mdb = entry->mdb;
515				const struct hfs_name *reserved =
516				HFS_SB(mdb->sys_mdb)->s_reserved2;
517
518				while (reserved->Len) {
519					if (hfs_streq(reserved->Name,
520						      reserved->Len,
521						      entry->key.CName.Name,
522						      entry->key.CName.Len)) {
523						hfs_put_hl(mdb->next_id, tmp);
524						p = tmp;
525						goto hfs_did_done;
526					}
527					reserved++;
528				}
529			}
530			p = (char *) &entry->cnid;
531hfs_did_done:
532			break;
533
534		case HFS_HDR_SNAME:
535		default:
536			limit = 0;
537		}
538
539		/* limit the transfer to the available data
540		   of to the stated length of the entry. */
541		if (length > limit) {
542			length = limit;
543		}
544		offset = pos - start;
545		left = length - offset;
546		if (left > count) {
547			left = count;
548		}
549		if (left <= 0) {
550			continue;
551		}
552
553		/* transfer the data */
554		if (p) {
555			left -= copy_to_user(buf, p + offset, left);
556		} else if (fork) {
557			left = hfs_do_read(inode, fork, offset, buf, left,
558					   filp->f_reada != 0);
559			if (left > 0) {
560				filp->f_reada = 1;
561			} else if (!read) {
562				return left;
563			} else {
564				goto done;
565			}
566		}
567		count -= left;
568		read += left;
569		pos += left;
570		buf += left;
571	}
572
573	/* Pad the file out with zeros */
574	if (count) {
575		clear_user(buf, count);
576		read += count;
577		pos += count;
578	}
579
580done:
581	if (read) {
582		inode->i_atime = CURRENT_TIME;
583		*ppos = pos;
584		mark_inode_dirty(inode);
585	}
586	return read;
587}
588
589/*
590 * hdr_write()
591 *
592 * This is the write() entry in the file_operations structure for
593 * header files.  The purpose is to transfer up to 'count' bytes
594 * to the file corresponding to 'inode' beginning at offset
595 * '*ppos' from user-space at the address 'buf'.
596 * The return value is the number of bytes actually transferred.
597 */
598static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
599			     hfs_rwarg_t count, loff_t *ppos)
600{
601	struct inode *inode = filp->f_dentry->d_inode;
602        struct hfs_cat_entry *entry = HFS_I(inode)->entry;
603        struct hfs_hdr_layout *layout;
604        off_t start, length, offset;
605        int left, lcv, written = 0;
606	struct hdr_hdr meta;
607	int built_meta = 0;
608        off_t pos;
609
610	if (!S_ISREG(inode->i_mode)) {
611		hfs_warn("hfs_hdr_write: mode = %07o\n", inode->i_mode);
612		return -EINVAL;
613	}
614	if (count <= 0) {
615		return 0;
616	}
617
618	pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
619
620	if (!HFS_I(inode)->layout) {
621		HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
622	}
623	layout = HFS_I(inode)->layout;
624
625	/* Handle the 'magic', 'version', 'filler' and 'entries' fields */
626	length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + sizeof(hfs_u16);
627	if (pos < length) {
628		hdr_build_meta(&meta, layout, entry);
629		built_meta = 1;
630
631		left = length - pos;
632		if (left > count) {
633			left = count;
634		}
635
636		left -= copy_from_user(((char *)&meta) + pos, buf, left);
637		layout->magic   = hfs_get_nl(meta.magic);
638		layout->version = hfs_get_nl(meta.version);
639		layout->entries = hfs_get_hs(meta.entries);
640		if (layout->entries > HFS_HDR_MAX) {
641			hfs_warn("hfs_hdr_write: TRUNCATING TO %d "
642				 "DESCRIPTORS\n", HFS_HDR_MAX);
643			layout->entries = HFS_HDR_MAX;
644		}
645
646		count -= left;
647		written += left;
648		pos += left;
649		buf += left;
650	}
651	if (!count) {
652		goto done;
653	}
654
655	/* We know for certain how many entries we have, so process them */
656	length += layout->entries * 3 * sizeof(hfs_u32);
657	if (pos < length) {
658		if (!built_meta) {
659			hdr_build_meta(&meta, layout, entry);
660		}
661
662		left = length - pos;
663		if (left > count) {
664			left = count;
665		}
666
667		left -= copy_from_user(((char *)&meta) + pos, buf, left);
668		init_layout(layout, meta.descrs);
669
670		count -= left;
671		written += left;
672		pos += left;
673		buf += left;
674
675		/* Handle possible size changes for the forks */
676		if (entry->type == HFS_CDR_FIL) {
677			adjust_forks(entry, layout);
678			hfs_cat_mark_dirty(entry);
679		}
680	}
681
682	/* Handle the actual data */
683	for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
684		struct hfs_hdr_descr *descr = layout->order[lcv];
685		struct hfs_fork *fork;
686		char tmp[16], *p;
687		off_t limit;
688
689		/* stop writing if we run out of descriptors early */
690		if (!descr) {
691			break;
692		}
693
694		/* find start and length of this entry */
695		start = descr->offset;
696		if ((descr->id == HFS_HDR_DATA) ||
697		    (descr->id == HFS_HDR_RSRC)) {
698			if (entry->type == HFS_CDR_FIL) {
699				length = 0x7fffffff - start;
700			} else {
701				continue;
702			}
703		} else {
704			length = dlength(descr, entry);
705		}
706
707		/* Trim length to avoid overlap with the next entry */
708		if (layout->order[lcv+1] &&
709		    ((start + length) > layout->order[lcv+1]->offset)) {
710			length = layout->order[lcv+1]->offset - start;
711		}
712
713		/* Skip to next entry if this one is empty or isn't needed */
714		if (!length || (pos >= start + length)) {
715			continue;
716		}
717
718		/* Skip any padding that may exist between entries */
719		if (pos < start) {
720			left = start - pos;
721			if (left > count) {
722				left = count;
723			}
724			count -= left;
725			written += left;
726			pos += left;
727			buf += left;
728		}
729		if (!count) {
730			goto done;
731		}
732
733		/* locate and/or construct the data for this entry */
734		fork = NULL;
735		p = NULL;
736		switch (descr->id) {
737		case HFS_HDR_DATA:
738			limit = 0;
739			break;
740
741		case HFS_HDR_RSRC:
742			fork = &entry->u.file.rsrc_fork;
743			limit = length;
744			break;
745
746		case HFS_HDR_OLDI:
747		case HFS_HDR_DATES:
748			get_dates(entry, inode, (hfs_u32 *)tmp);
749			if (descr->id == HFS_HDR_DATES) {
750				memcpy(tmp + 12, tmp + 4, 4);
751			} else if ((entry->type == HFS_CDR_FIL) &&
752				   (entry->u.file.flags & HFS_FIL_LOCK)) {
753				hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
754			} else {
755				hfs_put_nl(0, tmp + 12);
756			}
757			p = tmp;
758			limit = 16;
759			break;
760
761		case HFS_HDR_FINFO:
762			p = (char *)&entry->info;
763			limit = 32;
764			break;
765
766		case HFS_HDR_AFPI:
767			hfs_put_ns(0, tmp);
768			if ((entry->type == HFS_CDR_FIL) &&
769			    (entry->u.file.flags & HFS_FIL_LOCK)) {
770				hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
771			} else {
772				hfs_put_ns(0, tmp + 2);
773			}
774			p = tmp;
775			limit = 4;
776			break;
777
778		case HFS_HDR_PRODOSI:
779			memset(tmp, 0, 8);
780			p = tmp;
781			limit = 8;
782		        break;
783
784		case HFS_HDR_MACI:
785			hfs_put_ns(0, tmp);
786			if (entry->type == HFS_CDR_FIL) {
787				hfs_put_hs(entry->u.file.flags, tmp + 2);
788			} else {
789				hfs_put_ns(entry->u.dir.flags, tmp + 2);
790			}
791			p = tmp;
792			limit = 4;
793			break;
794
795		case HFS_HDR_FNAME:	/* Can't rename a file this way */
796		case HFS_HDR_DID:       /* can't specify a did this way */
797		default:
798			limit = 0;
799		}
800
801		/* limit the transfer to the available data
802		   of to the stated length of the entry. */
803		if (length > limit) {
804			length = limit;
805		}
806		offset = pos - start;
807		left = length - offset;
808		if (left > count) {
809			left = count;
810		}
811		if (left <= 0) {
812			continue;
813		}
814
815		/* transfer the data from user space */
816		if (p) {
817			left -= copy_from_user(p + offset, buf, left);
818		} else if (fork) {
819			left = hfs_do_write(inode, fork, offset, buf, left);
820		}
821
822		/* process the data */
823		switch (descr->id) {
824		case HFS_HDR_OLDI:
825			set_dates(entry, inode, (hfs_u32 *)tmp);
826			if (entry->type == HFS_CDR_FIL) {
827				hfs_u8 new_flags = entry->u.file.flags;
828
829				if (hfs_get_nl(tmp+12) & htonl(HFS_AFP_WRI)) {
830					new_flags |= HFS_FIL_LOCK;
831				} else {
832					new_flags &= ~HFS_FIL_LOCK;
833				}
834
835				if (new_flags != entry->u.file.flags) {
836					entry->u.file.flags = new_flags;
837					hfs_cat_mark_dirty(entry);
838					hfs_file_fix_mode(entry);
839				}
840			}
841			break;
842
843		case HFS_HDR_DATES:
844			set_dates(entry, inode, (hfs_u32 *)tmp);
845			break;
846
847		case HFS_HDR_FINFO:
848			hfs_cat_mark_dirty(entry);
849			break;
850
851		case HFS_HDR_MACI:
852			if (entry->type == HFS_CDR_DIR) {
853				hfs_u16 new_flags = hfs_get_ns(tmp + 2);
854
855				if (entry->u.dir.flags != new_flags) {
856					entry->u.dir.flags = new_flags;
857					hfs_cat_mark_dirty(entry);
858				}
859			} else {
860				hfs_u8 new_flags = tmp[3];
861				hfs_u8 changed = entry->u.file.flags^new_flags;
862
863				if (changed) {
864					entry->u.file.flags = new_flags;
865					hfs_cat_mark_dirty(entry);
866					if (changed & HFS_FIL_LOCK) {
867						hfs_file_fix_mode(entry);
868					}
869				}
870			}
871			break;
872
873		case HFS_HDR_DATA:
874		case HFS_HDR_RSRC:
875			if (left <= 0) {
876				if (!written) {
877					return left;
878				} else {
879					goto done;
880				}
881			} else if (fork->lsize > descr->length) {
882				descr->length = fork->lsize;
883			}
884			break;
885
886		case HFS_HDR_FNAME:	/* Can't rename a file this way */
887		case HFS_HDR_DID:       /* Can't specify a did this way */
888		case HFS_HDR_PRODOSI:   /* not implemented yet */
889		case HFS_HDR_AFPI:      /* ditto */
890		default:
891			break;
892		}
893
894		count -= left;
895		written += left;
896		pos += left;
897		buf += left;
898	}
899
900	/* Skip any padding at the end */
901	if (count) {
902		written += count;
903		pos += count;
904	}
905
906done:
907	*ppos = pos;
908	if (written > 0) {
909	        if (pos > inode->i_size)
910		        inode->i_size = pos;
911	        inode->i_mtime = inode->i_atime = CURRENT_TIME;
912		mark_inode_dirty(inode);
913	}
914	return written;
915}
916
917/*
918 * hdr_truncate()
919 *
920 * This is the truncate field in the inode_operations structure for
921 * header files.  The purpose is to allocate or release blocks as needed
922 * to satisfy a change in file length.
923 */
924void hdr_truncate(struct inode *inode, size_t size)
925{
926	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
927	struct hfs_hdr_layout *layout;
928	int lcv, last;
929
930	inode->i_size = size;
931	if (!HFS_I(inode)->layout) {
932		HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
933	}
934	layout = HFS_I(inode)->layout;
935
936	last = layout->entries - 1;
937	for (lcv = 0; lcv <= last; ++lcv) {
938		struct hfs_hdr_descr *descr = layout->order[lcv];
939		struct hfs_fork *fork;
940		hfs_u32 offset;
941
942		if (!descr) {
943			break;
944		}
945
946		if (descr->id == HFS_HDR_RSRC) {
947			fork = &entry->u.file.rsrc_fork;
948		} else {
949			continue;
950		}
951
952		offset = descr->offset;
953
954		if ((lcv != last) && ((offset + descr->length) <= size)) {
955			continue;
956		}
957
958		if (offset < size) {
959			descr->length = size - offset;
960		} else {
961			descr->length = 0;
962		}
963		if (fork->lsize != descr->length) {
964			fork->lsize = descr->length;
965			hfs_extent_adj(fork);
966			hfs_cat_mark_dirty(entry);
967		}
968	}
969}
970