summaryrefslogtreecommitdiffstats
path: root/fs/isofs/rock.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
commit33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch)
tree2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/isofs/rock.c
parent216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff)
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/isofs/rock.c')
-rw-r--r--fs/isofs/rock.c277
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;
}