diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/isofs/rock.c | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/isofs/rock.c')
-rw-r--r-- | fs/isofs/rock.c | 277 |
1 files changed, 146 insertions, 131 deletions
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 8b5c8befd..814d90b3c 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -12,6 +12,7 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/malloc.h> +#include <linux/pagemap.h> #include "rock.h" @@ -358,9 +359,10 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, #ifdef DEBUG printk("RR CL (%x)\n",inode->i_ino); #endif - inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) << - inode -> i_sb -> u.isofs_sb.s_log_zone_size; - reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent); + inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location); + reloc = iget(inode->i_sb, + (inode->u.isofs_i.i_first_extent << + inode -> i_sb -> u.isofs_sb.s_log_zone_size)); if (!reloc) goto out; inode->i_mode = reloc->i_mode; @@ -386,142 +388,155 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, return 0; } +static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr) +{ + int slen; + int rootflag; + struct SL_component *oldslp; + struct SL_component *slp; + slen = rr->len - 5; + slp = &rr->u.SL.link; + while (slen > 1) { + rootflag = 0; + switch (slp->flags & ~1) { + case 0: + memcpy(rpnt, slp->text, slp->len); + rpnt+=slp->len; + break; + case 4: + *rpnt++='.'; + /* fallthru */ + case 2: + *rpnt++='.'; + break; + case 8: + rootflag = 1; + *rpnt++='/'; + break; + default: + printk("Symlink component flag not implemented (%d)\n", + slp->flags); + } + slen -= slp->len + 2; + oldslp = slp; + slp = (struct SL_component *) ((char *) slp + slp->len + 2); + + if (slen < 2) { + /* + * If there is another SL record, and this component + * record isn't continued, then add a slash. + */ + if ((rr->u.SL.flags & 1) && !(oldslp->flags & 1)) + *rpnt++='/'; + break; + } + + /* + * If this component record isn't continued, then append a '/'. + */ + if (!rootflag && !(oldslp->flags & 1)) + *rpnt++='/'; -/* Returns the name of the file that this inode is symlinked to. This is - in malloc'd memory, so it needs to be freed, once we are through with it */ + } + return rpnt; +} -char * get_rock_ridge_symlink(struct inode * inode) -{ - unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); - unsigned char bufbits = ISOFS_BUFFER_BITS(inode); - struct buffer_head * bh; - char * rpnt = NULL; - unsigned char * pnt; - struct iso_directory_record * raw_inode; - CONTINUE_DECLS; - int block; - int sig; - int rootflag; - int len; - unsigned char * chr; - struct rock_ridge * rr; - - if (!inode->i_sb->u.isofs_sb.s_rock) - panic("Cannot have symlink with high sierra variant of iso filesystem\n"); - block = inode->i_ino >> bufbits; - bh = bread(inode->i_dev, block, bufsize); - if (!bh) - goto out_noread; - - pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (bufsize - 1)); - - raw_inode = ((struct iso_directory_record *) pnt); - - /* - * If we go past the end of the buffer, there is some sort of error. - */ - if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize) - goto out_bad_span; - - /* Now test for possible Rock Ridge extensions which will override some of - these numbers in the inode structure. */ - - SETUP_ROCK_RIDGE(raw_inode, chr, len); - - repeat: - while (len > 1){ /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *) chr; - if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; - chr += rr->len; - len -= rr->len; - - switch(sig){ - case SIG('R','R'): - if((rr->u.RR.flags[0] & RR_SL) == 0) goto out; - break; - case SIG('S','P'): - CHECK_SP(goto out); - break; - case SIG('S','L'): - {int slen; - struct SL_component * oldslp; - struct SL_component * slp; - slen = rr->len - 5; - slp = &rr->u.SL.link; - while (slen > 1){ - if (!rpnt){ - rpnt = (char *) kmalloc (inode->i_size +1, GFP_KERNEL); - if (!rpnt) goto out; - *rpnt = 0; - }; - rootflag = 0; - switch(slp->flags &~1){ - case 0: - strncat(rpnt,slp->text, slp->len); - break; - case 2: - strcat(rpnt,"."); - break; - case 4: - strcat(rpnt,".."); - break; - case 8: - rootflag = 1; - strcat(rpnt,"/"); - break; - default: - printk("Symlink component flag not implemented (%d)\n",slen); - }; - slen -= slp->len + 2; - oldslp = slp; - slp = (struct SL_component *) (((char *) slp) + slp->len + 2); - - if(slen < 2) { - /* - * If there is another SL record, and this component record - * isn't continued, then add a slash. - */ - if( ((rr->u.SL.flags & 1) != 0) - && ((oldslp->flags & 1) == 0) ) strcat(rpnt,"/"); - break; - } +/* readpage() for symlinks: reads symlink contents into the page and either + makes it uptodate and returns 0 or returns error (-EIO) */ - /* - * If this component record isn't continued, then append a '/'. - */ - if( (!rootflag) - && ((oldslp->flags & 1) == 0) ) strcat(rpnt,"/"); - - }; - break; - case SIG('C','E'): - CHECK_CE; /* This tells is if there is a continuation record */ - break; - default: - break; - } - }; - }; - MAYBE_CONTINUE(repeat,inode); - -out_freebh: +int rock_ridge_symlink_readpage(struct dentry *dentry, struct page *page) +{ + struct inode *inode = dentry->d_inode; + char *link = (char*)kmap(page); + unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); + unsigned char bufbits = ISOFS_BUFFER_BITS(inode); + struct buffer_head *bh; + char *rpnt = link; + unsigned char *pnt; + struct iso_directory_record *raw_inode; + CONTINUE_DECLS; + int block; + int sig; + int len; + unsigned char *chr; + struct rock_ridge *rr; + + if (!inode->i_sb->u.isofs_sb.s_rock) + panic ("Cannot have symlink with high sierra variant of iso filesystem\n"); + + block = inode->i_ino >> bufbits; + bh = bread(inode->i_dev, block, bufsize); + if (!bh) + goto out_noread; + + pnt = (unsigned char *) bh->b_data + (inode->i_ino & (bufsize - 1)); + + raw_inode = (struct iso_directory_record *) pnt; + + /* + * If we go past the end of the buffer, there is some sort of error. + */ + if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize) + goto out_bad_span; + + /* Now test for possible Rock Ridge extensions which will override + some of these numbers in the inode structure. */ + + SETUP_ROCK_RIDGE(raw_inode, chr, len); + + repeat: + while (len > 1) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *) chr; + if (rr->len == 0) + goto out; /* Something got screwed up here */ + sig = (chr[0] << 8) + chr[1]; + chr += rr->len; + len -= rr->len; + + switch (sig) { + case SIG('R', 'R'): + if ((rr->u.RR.flags[0] & RR_SL) == 0) + goto out; + break; + case SIG('S', 'P'): + CHECK_SP(goto out); + break; + case SIG('S', 'L'): + rpnt = get_symlink_chunk(rpnt, rr); + break; + case SIG('C', 'E'): + /* This tells is if there is a continuation record */ + CHECK_CE; + default: + break; + } + } + MAYBE_CONTINUE(repeat, inode); + + if (rpnt == link) + goto fail; brelse(bh); - return rpnt; + *rpnt = '\0'; + SetPageUptodate(page); + kunmap(page); + UnlockPage(page); + return 0; /* error exit from macro */ -out: - if(buffer) + out: + if (buffer) kfree(buffer); - if(rpnt) - kfree(rpnt); - rpnt = NULL; - goto out_freebh; -out_noread: + goto fail; + out_noread: printk("unable to read i-node block"); - goto out_freebh; -out_bad_span: + goto fail; + out_bad_span: printk("symlink spans iso9660 blocks\n"); - goto out_freebh; + fail: + brelse(bh); + SetPageError(page); + kunmap(page); + UnlockPage(page); + return -EIO; } |