~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/hfs/file_hdr.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.