linux/fs/udf/directory.c
<<
>>
Prefs
   1/*
   2 * directory.c
   3 *
   4 * PURPOSE
   5 *      Directory related functions
   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
  14#include "udfdecl.h"
  15#include "udf_i.h"
  16
  17#include <linux/fs.h>
  18#include <linux/string.h>
  19
  20struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
  21                                         struct udf_fileident_bh *fibh,
  22                                         struct fileIdentDesc *cfi,
  23                                         struct extent_position *epos,
  24                                         struct kernel_lb_addr *eloc, uint32_t *elen,
  25                                         sector_t *offset)
  26{
  27        struct fileIdentDesc *fi;
  28        int i, num, block;
  29        struct buffer_head *tmp, *bha[16];
  30        struct udf_inode_info *iinfo = UDF_I(dir);
  31
  32        fibh->soffset = fibh->eoffset;
  33
  34        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
  35                fi = udf_get_fileident(iinfo->i_ext.i_data -
  36                                       (iinfo->i_efe ?
  37                                        sizeof(struct extendedFileEntry) :
  38                                        sizeof(struct fileEntry)),
  39                                       dir->i_sb->s_blocksize,
  40                                       &(fibh->eoffset));
  41                if (!fi)
  42                        return NULL;
  43
  44                *nf_pos += fibh->eoffset - fibh->soffset;
  45
  46                memcpy((uint8_t *)cfi, (uint8_t *)fi,
  47                       sizeof(struct fileIdentDesc));
  48
  49                return fi;
  50        }
  51
  52        if (fibh->eoffset == dir->i_sb->s_blocksize) {
  53                int lextoffset = epos->offset;
  54                unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits;
  55
  56                if (udf_next_aext(dir, epos, eloc, elen, 1) !=
  57                    (EXT_RECORDED_ALLOCATED >> 30))
  58                        return NULL;
  59
  60                block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
  61
  62                (*offset)++;
  63
  64                if ((*offset << blocksize_bits) >= *elen)
  65                        *offset = 0;
  66                else
  67                        epos->offset = lextoffset;
  68
  69                brelse(fibh->sbh);
  70                fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
  71                if (!fibh->sbh)
  72                        return NULL;
  73                fibh->soffset = fibh->eoffset = 0;
  74
  75                if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) {
  76                        i = 16 >> (blocksize_bits - 9);
  77                        if (i + *offset > (*elen >> blocksize_bits))
  78                                i = (*elen >> blocksize_bits)-*offset;
  79                        for (num = 0; i > 0; i--) {
  80                                block = udf_get_lb_pblock(dir->i_sb, eloc,
  81                                                          *offset + i);
  82                                tmp = udf_tgetblk(dir->i_sb, block);
  83                                if (tmp && !buffer_uptodate(tmp) &&
  84                                                !buffer_locked(tmp))
  85                                        bha[num++] = tmp;
  86                                else
  87                                        brelse(tmp);
  88                        }
  89                        if (num) {
  90                                ll_rw_block(REQ_OP_READ, REQ_RAHEAD, num, bha);
  91                                for (i = 0; i < num; i++)
  92                                        brelse(bha[i]);
  93                        }
  94                }
  95        } else if (fibh->sbh != fibh->ebh) {
  96                brelse(fibh->sbh);
  97                fibh->sbh = fibh->ebh;
  98        }
  99
 100        fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
 101                               &(fibh->eoffset));
 102
 103        if (!fi)
 104                return NULL;
 105
 106        *nf_pos += fibh->eoffset - fibh->soffset;
 107
 108        if (fibh->eoffset <= dir->i_sb->s_blocksize) {
 109                memcpy((uint8_t *)cfi, (uint8_t *)fi,
 110                       sizeof(struct fileIdentDesc));
 111        } else if (fibh->eoffset > dir->i_sb->s_blocksize) {
 112                int lextoffset = epos->offset;
 113
 114                if (udf_next_aext(dir, epos, eloc, elen, 1) !=
 115                    (EXT_RECORDED_ALLOCATED >> 30))
 116                        return NULL;
 117
 118                block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
 119
 120                (*offset)++;
 121
 122                if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
 123                        *offset = 0;
 124                else
 125                        epos->offset = lextoffset;
 126
 127                fibh->soffset -= dir->i_sb->s_blocksize;
 128                fibh->eoffset -= dir->i_sb->s_blocksize;
 129
 130                fibh->ebh = udf_tread(dir->i_sb, block);
 131                if (!fibh->ebh)
 132                        return NULL;
 133
 134                if (sizeof(struct fileIdentDesc) > -fibh->soffset) {
 135                        int fi_len;
 136
 137                        memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset);
 138                        memcpy((uint8_t *)cfi - fibh->soffset,
 139                               fibh->ebh->b_data,
 140                               sizeof(struct fileIdentDesc) + fibh->soffset);
 141
 142                        fi_len = (sizeof(struct fileIdentDesc) +
 143                                  cfi->lengthFileIdent +
 144                                  le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
 145
 146                        *nf_pos += fi_len - (fibh->eoffset - fibh->soffset);
 147                        fibh->eoffset = fibh->soffset + fi_len;
 148                } else {
 149                        memcpy((uint8_t *)cfi, (uint8_t *)fi,
 150                               sizeof(struct fileIdentDesc));
 151                }
 152        }
 153        return fi;
 154}
 155
 156struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
 157{
 158        struct fileIdentDesc *fi;
 159        int lengthThisIdent;
 160        uint8_t *ptr;
 161        int padlen;
 162
 163        if ((!buffer) || (!offset)) {
 164                udf_debug("invalidparms, buffer=%p, offset=%p\n",
 165                          buffer, offset);
 166                return NULL;
 167        }
 168
 169        ptr = buffer;
 170
 171        if ((*offset > 0) && (*offset < bufsize))
 172                ptr += *offset;
 173        fi = (struct fileIdentDesc *)ptr;
 174        if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) {
 175                udf_debug("0x%x != TAG_IDENT_FID\n",
 176                          le16_to_cpu(fi->descTag.tagIdent));
 177                udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
 178                          *offset, (unsigned long)sizeof(struct fileIdentDesc),
 179                          bufsize);
 180                return NULL;
 181        }
 182        if ((*offset + sizeof(struct fileIdentDesc)) > bufsize)
 183                lengthThisIdent = sizeof(struct fileIdentDesc);
 184        else
 185                lengthThisIdent = sizeof(struct fileIdentDesc) +
 186                        fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
 187
 188        /* we need to figure padding, too! */
 189        padlen = lengthThisIdent % UDF_NAME_PAD;
 190        if (padlen)
 191                lengthThisIdent += (UDF_NAME_PAD - padlen);
 192        *offset = *offset + lengthThisIdent;
 193
 194        return fi;
 195}
 196
 197struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
 198                              int inc)
 199{
 200        struct short_ad *sa;
 201
 202        if ((!ptr) || (!offset)) {
 203                pr_err("%s: invalidparms\n", __func__);
 204                return NULL;
 205        }
 206
 207        if ((*offset + sizeof(struct short_ad)) > maxoffset)
 208                return NULL;
 209        else {
 210                sa = (struct short_ad *)ptr;
 211                if (sa->extLength == 0)
 212                        return NULL;
 213        }
 214
 215        if (inc)
 216                *offset += sizeof(struct short_ad);
 217        return sa;
 218}
 219
 220struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc)
 221{
 222        struct long_ad *la;
 223
 224        if ((!ptr) || (!offset)) {
 225                pr_err("%s: invalidparms\n", __func__);
 226                return NULL;
 227        }
 228
 229        if ((*offset + sizeof(struct long_ad)) > maxoffset)
 230                return NULL;
 231        else {
 232                la = (struct long_ad *)ptr;
 233                if (la->extLength == 0)
 234                        return NULL;
 235        }
 236
 237        if (inc)
 238                *offset += sizeof(struct long_ad);
 239        return la;
 240}
 241