File: /usr/src/linux/fs/isofs/rock.c

1     /*
2      *  linux/fs/isofs/rock.c
3      *
4      *  (C) 1992, 1993  Eric Youngdale
5      *
6      *  Rock Ridge Extensions to iso9660
7      */
8     
9     #include <linux/stat.h>
10     #include <linux/sched.h>
11     #include <linux/iso_fs.h>
12     #include <linux/string.h>
13     #include <linux/mm.h>
14     #include <linux/slab.h>
15     #include <linux/pagemap.h>
16     #include <linux/smp_lock.h>
17     
18     #include "rock.h"
19     
20     /* These functions are designed to read the system areas of a directory record
21      * and extract relevant information.  There are different functions provided
22      * depending upon what information we need at the time.  One function fills
23      * out an inode structure, a second one extracts a filename, a third one
24      * returns a symbolic link name, and a fourth one returns the extent number
25      * for the file. */
26     
27     #define SIG(A,B) ((A << 8) | B)
28     
29     
30     /* This is a way of ensuring that we have something in the system
31        use fields that is compatible with Rock Ridge */
32     #define CHECK_SP(FAIL)	       			\
33           if(rr->u.SP.magic[0] != 0xbe) FAIL;	\
34           if(rr->u.SP.magic[1] != 0xef) FAIL;       \
35           inode->i_sb->u.isofs_sb.s_rock_offset=rr->u.SP.skip;
36     /* We define a series of macros because each function must do exactly the
37        same thing in certain places.  We use the macros to ensure that everything
38        is done correctly */
39     
40     #define CONTINUE_DECLS \
41       int cont_extent = 0, cont_offset = 0, cont_size = 0;   \
42       void * buffer = 0
43     
44     #define CHECK_CE	       			\
45           {cont_extent = isonum_733(rr->u.CE.extent); \
46           cont_offset = isonum_733(rr->u.CE.offset); \
47           cont_size = isonum_733(rr->u.CE.size);}
48     
49     #define SETUP_ROCK_RIDGE(DE,CHR,LEN)	      		      	\
50       {LEN= sizeof(struct iso_directory_record) + DE->name_len[0];	\
51       if(LEN & 1) LEN++;						\
52       CHR = ((unsigned char *) DE) + LEN;				\
53       LEN = *((unsigned char *) DE) - LEN;                          \
54       if (inode->i_sb->u.isofs_sb.s_rock_offset!=-1)                \
55       {                                                             \
56          LEN-=inode->i_sb->u.isofs_sb.s_rock_offset;                \
57          CHR+=inode->i_sb->u.isofs_sb.s_rock_offset;                \
58          if (LEN<0) LEN=0;                                          \
59       }                                                             \
60     }                                     
61     
62     #define MAYBE_CONTINUE(LABEL,DEV) \
63       {if (buffer) kfree(buffer); \
64       if (cont_extent){ \
65         int block, offset, offset1; \
66         struct buffer_head * pbh; \
67         buffer = kmalloc(cont_size,GFP_KERNEL); \
68         if (!buffer) goto out; \
69         block = cont_extent; \
70         offset = cont_offset; \
71         offset1 = 0; \
72         pbh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
73         if(pbh){       \
74           memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \
75           brelse(pbh); \
76           chr = (unsigned char *) buffer; \
77           len = cont_size; \
78           cont_extent = 0; \
79           cont_size = 0; \
80           cont_offset = 0; \
81           goto LABEL; \
82         }    \
83         printk("Unable to read rock-ridge attributes\n");    \
84       }}
85     
86     /* This is the inner layer of the get filename routine, and is called
87        for each system area and continuation record related to the file */
88     
89     int find_rock_ridge_relocation(struct iso_directory_record * de, 
90     			       struct inode * inode) {
91       int flag;
92       int len;
93       int retval;
94       unsigned char * chr;
95       CONTINUE_DECLS;
96       flag = 0;
97       
98       /* If this is a '..' then we are looking for the parent, otherwise we
99          are looking for the child */
100       
101       if (de->name[0]==1 && de->name_len[0]==1) flag = 1;
102       /* Return value if we do not find appropriate record. */
103       retval = isonum_733 (de->extent);
104       
105       if (!inode->i_sb->u.isofs_sb.s_rock) return retval;
106     
107       SETUP_ROCK_RIDGE(de, chr, len);
108      repeat:
109       {
110         int rrflag, sig;
111         struct rock_ridge * rr;
112         
113         while (len > 1){ /* There may be one byte for padding somewhere */
114           rr = (struct rock_ridge *) chr;
115           if (rr->len == 0) goto out; /* Something got screwed up here */
116           sig = (chr[0] << 8) + chr[1];
117           chr += rr->len; 
118           len -= rr->len;
119     
120           switch(sig){
121           case SIG('R','R'):
122     	rrflag = rr->u.RR.flags[0];
123     	if (flag && !(rrflag & RR_PL)) goto out;
124     	if (!flag && !(rrflag & RR_CL)) goto out;
125     	break;
126           case SIG('S','P'):
127     	CHECK_SP(goto out);
128     	break;
129           case SIG('C','L'):
130     	if (flag == 0) {
131     	  retval = isonum_733(rr->u.CL.location);
132     	  goto out;
133     	}
134     	break;
135           case SIG('P','L'):
136     	if (flag != 0) {
137     	  retval = isonum_733(rr->u.PL.location);
138     	  goto out;
139     	}
140     	break;
141           case SIG('C','E'):
142     	CHECK_CE; /* This tells is if there is a continuation record */
143     	break;
144           default:
145     	break;
146           }
147         }
148       }
149       MAYBE_CONTINUE(repeat, inode);
150       return retval;
151      out:
152       if(buffer) kfree(buffer);
153       return retval;
154     }
155     
156     /* return length of name field; 0: not found, -1: to be ignored */
157     int get_rock_ridge_filename(struct iso_directory_record * de,
158     			    char * retname, struct inode * inode)
159     {
160       int len;
161       unsigned char * chr;
162       CONTINUE_DECLS;
163       int retnamlen = 0, truncate=0;
164      
165       if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
166       *retname = 0;
167     
168       SETUP_ROCK_RIDGE(de, chr, len);
169      repeat:
170       {
171         struct rock_ridge * rr;
172         int sig;
173         
174         while (len > 1){ /* There may be one byte for padding somewhere */
175           rr = (struct rock_ridge *) chr;
176           if (rr->len == 0) goto out; /* Something got screwed up here */
177           sig = (chr[0] << 8) + chr[1];
178           chr += rr->len; 
179           len -= rr->len;
180     
181           switch(sig){
182           case SIG('R','R'):
183     	if((rr->u.RR.flags[0] & RR_NM) == 0) goto out;
184     	break;
185           case SIG('S','P'):
186     	CHECK_SP(goto out);
187     	break;
188           case SIG('C','E'):
189     	CHECK_CE;
190     	break;
191           case SIG('N','M'):
192     	if (truncate) break;
193             /*
194     	 * If the flags are 2 or 4, this indicates '.' or '..'.
195     	 * We don't want to do anything with this, because it
196     	 * screws up the code that calls us.  We don't really
197     	 * care anyways, since we can just use the non-RR
198     	 * name.
199     	 */
200     	if (rr->u.NM.flags & 6) {
201     	  break;
202     	}
203     
204     	if (rr->u.NM.flags & ~1) {
205     	  printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
206     	  break;
207     	}
208     	if((strlen(retname) + rr->len - 5) >= 254) {
209     	  truncate = 1;
210     	  break;
211     	}
212     	strncat(retname, rr->u.NM.name, rr->len - 5);
213     	retnamlen += rr->len - 5;
214     	break;
215           case SIG('R','E'):
216     	if (buffer) kfree(buffer);
217     	return -1;
218           default:
219     	break;
220           }
221         }
222       }
223       MAYBE_CONTINUE(repeat,inode);
224       return retnamlen; /* If 0, this file did not have a NM field */
225      out:
226       if(buffer) kfree(buffer);
227       return 0;
228     }
229     
230     int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
231     			            struct inode * inode,int regard_xa){
232       int len;
233       unsigned char * chr;
234       int symlink_len = 0;
235       CONTINUE_DECLS;
236     
237       if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
238     
239       SETUP_ROCK_RIDGE(de, chr, len);
240       if (regard_xa)
241        {
242          chr+=14;
243          len-=14;
244          if (len<0) len=0;
245        };
246        
247      repeat:
248       {
249         int cnt, sig;
250         struct inode * reloc;
251         struct rock_ridge * rr;
252         int rootflag;
253         
254         while (len > 1){ /* There may be one byte for padding somewhere */
255           rr = (struct rock_ridge *) chr;
256           if (rr->len == 0) goto out; /* Something got screwed up here */
257           sig = (chr[0] << 8) + chr[1];
258           chr += rr->len; 
259           len -= rr->len;
260           
261           switch(sig){
262           case SIG('R','R'):
263     	if((rr->u.RR.flags[0] & 
264      	    (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out;
265     	break;
266           case SIG('S','P'):
267     	CHECK_SP(goto out);
268     	break;
269           case SIG('C','E'):
270     	CHECK_CE;
271     	break;
272           case SIG('E','R'):
273     	inode->i_sb->u.isofs_sb.s_rock = 1;
274     	printk(KERN_DEBUG "ISO 9660 Extensions: ");
275     	{ int p;
276     	  for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
277     	}
278     	  printk("\n");
279     	break;
280           case SIG('P','X'):
281     	inode->i_mode  = isonum_733(rr->u.PX.mode);
282     	inode->i_nlink = isonum_733(rr->u.PX.n_links);
283     	inode->i_uid   = isonum_733(rr->u.PX.uid);
284     	inode->i_gid   = isonum_733(rr->u.PX.gid);
285     	break;
286           case SIG('P','N'):
287     	{ int high, low;
288     	  high = isonum_733(rr->u.PN.dev_high);
289     	  low = isonum_733(rr->u.PN.dev_low);
290     	  /*
291     	   * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4,
292     	   * then the high field is unused, and the device number is completely
293     	   * stored in the low field.  Some writers may ignore this subtlety,
294     	   * and as a result we test to see if the entire device number is
295     	   * stored in the low field, and use that.
296     	   */
297     	  if((low & ~0xff) && high == 0) {
298     	    inode->i_rdev = MKDEV(low >> 8, low & 0xff);
299     	  } else {
300     	    inode->i_rdev = MKDEV(high, low);
301     	  }
302     	}
303     	break;
304           case SIG('T','F'):
305     	/* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
306     	   Try to handle this correctly for either case. */
307     	cnt = 0; /* Rock ridge never appears on a High Sierra disk */
308     	if(rr->u.TF.flags & TF_CREATE) 
309     	  inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
310     	if(rr->u.TF.flags & TF_MODIFY) 
311     	  inode->i_mtime = iso_date(rr->u.TF.times[cnt++].time, 0);
312     	if(rr->u.TF.flags & TF_ACCESS) 
313     	  inode->i_atime = iso_date(rr->u.TF.times[cnt++].time, 0);
314     	if(rr->u.TF.flags & TF_ATTRIBUTES) 
315     	  inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
316     	break;
317           case SIG('S','L'):
318     	{int slen;
319     	 struct SL_component * slp;
320     	 struct SL_component * oldslp;
321     	 slen = rr->len - 5;
322     	 slp = &rr->u.SL.link;
323     	 inode->i_size = symlink_len;
324     	 while (slen > 1){
325     	   rootflag = 0;
326     	   switch(slp->flags &~1){
327     	   case 0:
328     	     inode->i_size += slp->len;
329     	     break;
330     	   case 2:
331     	     inode->i_size += 1;
332     	     break;
333     	   case 4:
334     	     inode->i_size += 2;
335     	     break;
336     	   case 8:
337     	     rootflag = 1;
338     	     inode->i_size += 1;
339     	     break;
340     	   default:
341     	     printk("Symlink component flag not implemented\n");
342     	   }
343     	   slen -= slp->len + 2;
344     	   oldslp = slp;
345     	   slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
346     
347     	   if(slen < 2) {
348     	     if(    ((rr->u.SL.flags & 1) != 0) 
349     		    && ((oldslp->flags & 1) == 0) ) inode->i_size += 1;
350     	     break;
351     	   }
352     
353     	   /*
354     	    * If this component record isn't continued, then append a '/'.
355     	    */
356     	   if (!rootflag && (oldslp->flags & 1) == 0)
357     		   inode->i_size += 1;
358     	 }
359     	}
360     	symlink_len = inode->i_size;
361     	break;
362           case SIG('R','E'):
363     	printk(KERN_WARNING "Attempt to read inode for relocated directory\n");
364     	goto out;
365           case SIG('C','L'):
366     	inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location);
367     	reloc = iget(inode->i_sb,
368     		     (inode->u.isofs_i.i_first_extent <<
369     		      inode -> i_sb -> u.isofs_sb.s_log_zone_size));
370     	if (!reloc)
371     		goto out;
372     	inode->i_mode = reloc->i_mode;
373     	inode->i_nlink = reloc->i_nlink;
374     	inode->i_uid = reloc->i_uid;
375     	inode->i_gid = reloc->i_gid;
376     	inode->i_rdev = reloc->i_rdev;
377     	inode->i_size = reloc->i_size;
378     	inode->i_atime = reloc->i_atime;
379     	inode->i_ctime = reloc->i_ctime;
380     	inode->i_mtime = reloc->i_mtime;
381     	iput(reloc);
382     	break;
383           default:
384     	break;
385           }
386         }
387       }
388       MAYBE_CONTINUE(repeat,inode);
389       return 0;
390      out:
391       if(buffer) kfree(buffer);
392       return 0;
393     }
394     
395     static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr)
396     {
397     	int slen;
398     	int rootflag;
399     	struct SL_component *oldslp;
400     	struct SL_component *slp;
401     	slen = rr->len - 5;
402     	slp = &rr->u.SL.link;
403     	while (slen > 1) {
404     		rootflag = 0;
405     		switch (slp->flags & ~1) {
406     		case 0:
407     			memcpy(rpnt, slp->text, slp->len);
408     			rpnt+=slp->len;
409     			break;
410     		case 4:
411     			*rpnt++='.';
412     			/* fallthru */
413     		case 2:
414     			*rpnt++='.';
415     			break;
416     		case 8:
417     			rootflag = 1;
418     			*rpnt++='/';
419     			break;
420     		default:
421     			printk("Symlink component flag not implemented (%d)\n",
422     			     slp->flags);
423     		}
424     		slen -= slp->len + 2;
425     		oldslp = slp;
426     		slp = (struct SL_component *) ((char *) slp + slp->len + 2);
427     
428     		if (slen < 2) {
429     			/*
430     			 * If there is another SL record, and this component
431     			 * record isn't continued, then add a slash.
432     			 */
433     			if ((!rootflag) && (rr->u.SL.flags & 1) && !(oldslp->flags & 1))
434     				*rpnt++='/';
435     			break;
436     		}
437     
438     		/*
439     		 * If this component record isn't continued, then append a '/'.
440     		 */
441     		if (!rootflag && !(oldslp->flags & 1))
442     			*rpnt++='/';
443     
444     	}
445     	return rpnt;
446     }
447     
448     int parse_rock_ridge_inode(struct iso_directory_record * de,
449     			   struct inode * inode)
450     {
451        int result=parse_rock_ridge_inode_internal(de,inode,0);
452        /* if rockridge flag was reset and we didn't look for attributes
453         * behind eventual XA attributes, have a look there */
454        if ((inode->i_sb->u.isofs_sb.s_rock_offset==-1)
455            &&(inode->i_sb->u.isofs_sb.s_rock==2))
456          {
457     	result=parse_rock_ridge_inode_internal(de,inode,14);
458          };
459        return result;
460     };
461     
462     /* readpage() for symlinks: reads symlink contents into the page and either
463        makes it uptodate and returns 0 or returns error (-EIO) */
464     
465     static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
466     {
467     	struct inode *inode = page->mapping->host;
468     	char *link = kmap(page);
469     	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
470     	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
471     	struct buffer_head *bh;
472     	char *rpnt = link;
473     	unsigned char *pnt;
474     	struct iso_directory_record *raw_inode;
475     	CONTINUE_DECLS;
476     	int block;
477     	int sig;
478     	int len;
479     	unsigned char *chr;
480     	struct rock_ridge *rr;
481     
482     	if (!inode->i_sb->u.isofs_sb.s_rock)
483     		panic ("Cannot have symlink with high sierra variant of iso filesystem\n");
484     
485     	block = inode->i_ino >> bufbits;
486     	lock_kernel();
487     	bh = bread(inode->i_dev, block, bufsize);
488     	if (!bh)
489     		goto out_noread;
490     
491     	pnt = (unsigned char *) bh->b_data + (inode->i_ino & (bufsize - 1));
492     
493     	raw_inode = (struct iso_directory_record *) pnt;
494     
495     	/*
496     	 * If we go past the end of the buffer, there is some sort of error.
497     	 */
498     	if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize)
499     		goto out_bad_span;
500     
501     	/* Now test for possible Rock Ridge extensions which will override
502     	   some of these numbers in the inode structure. */
503     
504     	SETUP_ROCK_RIDGE(raw_inode, chr, len);
505     
506           repeat:
507     	while (len > 1) { /* There may be one byte for padding somewhere */
508     		rr = (struct rock_ridge *) chr;
509     		if (rr->len == 0)
510     			goto out;	/* Something got screwed up here */
511     		sig = (chr[0] << 8) + chr[1];
512     		chr += rr->len;
513     		len -= rr->len;
514     
515     		switch (sig) {
516     		case SIG('R', 'R'):
517     			if ((rr->u.RR.flags[0] & RR_SL) == 0)
518     				goto out;
519     			break;
520     		case SIG('S', 'P'):
521     			CHECK_SP(goto out);
522     			break;
523     		case SIG('S', 'L'):
524     			rpnt = get_symlink_chunk(rpnt, rr);
525     			break;
526     		case SIG('C', 'E'):
527     			/* This tells is if there is a continuation record */
528     			CHECK_CE;
529     		default:
530     			break;
531     		}
532     	}
533     	MAYBE_CONTINUE(repeat, inode);
534     
535     	if (rpnt == link)
536     		goto fail;
537     	brelse(bh);
538     	*rpnt = '\0';
539     	unlock_kernel();
540     	SetPageUptodate(page);
541     	kunmap(page);
542     	UnlockPage(page);
543     	return 0;
544     
545     	/* error exit from macro */
546           out:
547     	if (buffer)
548     		kfree(buffer);
549     	goto fail;
550           out_noread:
551     	printk("unable to read i-node block");
552     	goto fail;
553           out_bad_span:
554     	printk("symlink spans iso9660 blocks\n");
555           fail:
556     	brelse(bh);
557     	unlock_kernel();
558     	SetPageError(page);
559     	kunmap(page);
560     	UnlockPage(page);
561     	return -EIO;
562     }
563     
564     struct address_space_operations isofs_symlink_aops = {
565     	readpage:	rock_ridge_symlink_readpage
566     };
567