symlink.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. * symlink.c
  3. *
  4. * PURPOSE
  5. * Symlink handling routines for the OSTA-UDF(tm) filesystem.
  6. *
  7. * COPYRIGHT
  8. * This file is distributed under the terms of the GNU General Public
  9. * License (GPL). Copies of the GPL can be obtained from:
  10. * ftp://prep.ai.mit.edu/pub/gnu/GPL
  11. * Each contributing author retains all rights to their own work.
  12. *
  13. * (C) 1998-2001 Ben Fennema
  14. * (C) 1999 Stelias Computing Inc
  15. *
  16. * HISTORY
  17. *
  18. * 04/16/99 blf Created.
  19. *
  20. */
  21. #include "udfdecl.h"
  22. #include <linux/uaccess.h>
  23. #include <linux/errno.h>
  24. #include <linux/fs.h>
  25. #include <linux/time.h>
  26. #include <linux/mm.h>
  27. #include <linux/stat.h>
  28. #include <linux/pagemap.h>
  29. #include "udf_i.h"
  30. static int udf_pc_to_char(struct super_block *sb, unsigned char *from,
  31. int fromlen, unsigned char *to, int tolen)
  32. {
  33. struct pathComponent *pc;
  34. int elen = 0;
  35. int comp_len;
  36. unsigned char *p = to;
  37. /* Reserve one byte for terminating \0 */
  38. tolen--;
  39. while (elen < fromlen) {
  40. pc = (struct pathComponent *)(from + elen);
  41. elen += sizeof(struct pathComponent);
  42. switch (pc->componentType) {
  43. case 1:
  44. /*
  45. * Symlink points to some place which should be agreed
  46. * upon between originator and receiver of the media. Ignore.
  47. */
  48. if (pc->lengthComponentIdent > 0) {
  49. elen += pc->lengthComponentIdent;
  50. break;
  51. }
  52. /* Fall through */
  53. case 2:
  54. if (tolen == 0)
  55. return -ENAMETOOLONG;
  56. p = to;
  57. *p++ = '/';
  58. tolen--;
  59. break;
  60. case 3:
  61. if (tolen < 3)
  62. return -ENAMETOOLONG;
  63. memcpy(p, "../", 3);
  64. p += 3;
  65. tolen -= 3;
  66. break;
  67. case 4:
  68. if (tolen < 2)
  69. return -ENAMETOOLONG;
  70. memcpy(p, "./", 2);
  71. p += 2;
  72. tolen -= 2;
  73. /* that would be . - just ignore */
  74. break;
  75. case 5:
  76. elen += pc->lengthComponentIdent;
  77. if (elen > fromlen)
  78. return -EIO;
  79. comp_len = udf_get_filename(sb, pc->componentIdent,
  80. pc->lengthComponentIdent,
  81. p, tolen);
  82. if (comp_len < 0)
  83. return comp_len;
  84. p += comp_len;
  85. tolen -= comp_len;
  86. if (tolen == 0)
  87. return -ENAMETOOLONG;
  88. *p++ = '/';
  89. tolen--;
  90. break;
  91. }
  92. }
  93. if (p > to + 1)
  94. p[-1] = '\0';
  95. else
  96. p[0] = '\0';
  97. return 0;
  98. }
  99. static int udf_symlink_filler(struct file *file, struct page *page)
  100. {
  101. struct inode *inode = page->mapping->host;
  102. struct buffer_head *bh = NULL;
  103. unsigned char *symlink;
  104. int err;
  105. unsigned char *p = page_address(page);
  106. struct udf_inode_info *iinfo;
  107. uint32_t pos;
  108. /* We don't support symlinks longer than one block */
  109. if (inode->i_size > inode->i_sb->s_blocksize) {
  110. err = -ENAMETOOLONG;
  111. goto out_unmap;
  112. }
  113. iinfo = UDF_I(inode);
  114. pos = udf_block_map(inode, 0);
  115. down_read(&iinfo->i_data_sem);
  116. if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
  117. symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
  118. } else {
  119. bh = sb_bread(inode->i_sb, pos);
  120. if (!bh) {
  121. err = -EIO;
  122. goto out_unlock_inode;
  123. }
  124. symlink = bh->b_data;
  125. }
  126. err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE);
  127. brelse(bh);
  128. if (err)
  129. goto out_unlock_inode;
  130. up_read(&iinfo->i_data_sem);
  131. SetPageUptodate(page);
  132. unlock_page(page);
  133. return 0;
  134. out_unlock_inode:
  135. up_read(&iinfo->i_data_sem);
  136. SetPageError(page);
  137. out_unmap:
  138. unlock_page(page);
  139. return err;
  140. }
  141. /*
  142. * symlinks can't do much...
  143. */
  144. const struct address_space_operations udf_symlink_aops = {
  145. .readpage = udf_symlink_filler,
  146. };