| 1 | |
| 2 | |
| 3 | * linux/fs/fat/dir.c
|
| 4 | *
|
| 5 | * directory handling functions for fat-based filesystems
|
| 6 | *
|
| 7 | * Written 1992,1993 by Werner Almesberger
|
| 8 | *
|
| 9 | * Hidden files 1995 by Albert Cahalan <[email protected]> <[email protected]>
|
| 10 | *
|
| 11 | * VFAT extensions by Gordon Chaffee <[email protected]>
|
| 12 | * Merged with msdos fs by Henrik Storner <[email protected]>
|
| 13 | * Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV
|
| 14 | * Short name translation 1999, 2001 by Wolfram Pienkoss <[email protected]>
|
| 15 |
|
| 16 |
|
| 17 | #include <linux/slab.h>
|
| 18 | #include <linux/compat.h>
|
| 19 | #include <linux/filelock.h>
|
| 20 | #include <linux/hex.h>
|
| 21 | #include <linux/uaccess.h>
|
| 22 | #include <linux/iversion.h>
|
| 23 | #include "fat.h"
|
| 24 |
|
| 25 | |
| 26 | * Maximum buffer size of short name.
|
| 27 | * [(MSDOS_NAME + '.') * max one char + nul]
|
| 28 | * For msdos style, ['.' (hidden) + MSDOS_NAME + '.' + nul]
|
| 29 |
|
| 30 | #define FAT_MAX_SHORT_SIZE ((MSDOS_NAME + 1) * NLS_MAX_CHARSET_SIZE + 1)
|
| 31 | |
| 32 | * Maximum buffer size of unicode chars from slots.
|
| 33 | * [(max longname slots * 13 (size in a slot) + nul) * sizeof(wchar_t)]
|
| 34 |
|
| 35 | #define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1)
|
| 36 | #define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
|
| 37 |
|
| 38 | static inline unsigned char fat_tolower(unsigned char c)
|
| 39 | {
|
| 40 | return ((c >= 'A') && (c <= 'Z')) ? c+32 : c;
|
| 41 | }
|
| 42 |
|
| 43 | static inline loff_t fat_make_i_pos(struct super_block *sb,
|
| 44 | struct buffer_head *bh,
|
| 45 | struct msdos_dir_entry *de)
|
| 46 | {
|
| 47 | return ((loff_t)bh->b_blocknr << MSDOS_SB(sb)->dir_per_block_bits)
|
| 48 | | (de - (struct msdos_dir_entry *)bh->b_data);
|
| 49 | }
|
| 50 |
|
| 51 | static inline void fat_dir_readahead(struct inode *dir, sector_t iblock,
|
| 52 | sector_t phys)
|
| 53 | {
|
| 54 | struct super_block *sb = dir->i_sb;
|
| 55 | struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
| 56 | struct buffer_head *bh;
|
| 57 | int sec;
|
| 58 |
|
| 59 |
|
| 60 | if ((iblock & (sbi->sec_per_clus - 1)) || sbi->sec_per_clus == 1)
|
| 61 | return;
|
| 62 |
|
| 63 | if (!is_fat32(sbi) && (dir->i_ino == MSDOS_ROOT_INO))
|
| 64 | return;
|
| 65 |
|
| 66 | bh = sb_find_get_block(sb, phys);
|
| 67 | if (bh == NULL || !buffer_uptodate(bh)) {
|
| 68 | for (sec = 0; sec < sbi->sec_per_clus; sec++)
|
| 69 | sb_breadahead(sb, phys + sec);
|
| 70 | }
|
| 71 | brelse(bh);
|
| 72 | }
|
| 73 |
|
| 74 | |
| 75 | non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
|
| 76 | returned in bh.
|
| 77 | AV. Most often we do it item-by-item. Makes sense to optimize.
|
| 78 | AV. OK, there we go: if both bh and de are non-NULL we assume that we just
|
| 79 | AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
|
| 80 | AV. It's done in fat_get_entry() (inlined), here the slow case lives.
|
| 81 | AV. Additionally, when we return -1 (i.e. reached the end of directory)
|
| 82 | AV. we make bh NULL.
|
| 83 |
|
| 84 | static int fat__get_entry(struct inode *dir, loff_t *pos,
|
| 85 | struct buffer_head **bh, struct msdos_dir_entry **de)
|
| 86 | {
|
| 87 | struct super_block *sb = dir->i_sb;
|
| 88 | sector_t phys, iblock;
|
| 89 | unsigned long mapped_blocks;
|
| 90 | int err, offset;
|
| 91 |
|
| 92 | next:
|
| 93 | brelse(*bh);
|
| 94 | *bh = NULL;
|
| 95 | iblock = *pos >> sb->s_blocksize_bits;
|
| 96 | err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0, false);
|
| 97 | if (err || !phys)
|
| 98 | return -1;
|
| 99 |
|
| 100 | fat_dir_readahead(dir, iblock, phys);
|
| 101 |
|
| 102 | *bh = sb_bread(sb, phys);
|
| 103 | if (*bh == NULL) {
|
| 104 | fat_msg_ratelimit(sb, KERN_ERR,
|
| 105 | "Directory bread(block %llu) failed", (llu)phys);
|
| 106 |
|
| 107 | *pos = (iblock + 1) << sb->s_blocksize_bits;
|
| 108 | goto next;
|
| 109 | }
|
| 110 |
|
| 111 | offset = *pos & (sb->s_blocksize - 1);
|
| 112 | *pos += sizeof(struct msdos_dir_entry);
|
| 113 | *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
|
| 114 |
|
| 115 | return 0;
|
| 116 | }
|
| 117 |
|
| 118 | static inline int fat_get_entry(struct inode *dir, loff_t *pos,
|
| 119 | struct buffer_head **bh,
|
| 120 | struct msdos_dir_entry **de)
|
| 121 | {
|
| 122 |
|
| 123 | if (*bh && *de &&
|
| 124 | (*de - (struct msdos_dir_entry *)(*bh)->b_data) <
|
| 125 | MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
|
| 126 | *pos += sizeof(struct msdos_dir_entry);
|
| 127 | (*de)++;
|
| 128 | return 0;
|
| 129 | }
|
| 130 | return fat__get_entry(dir, pos, bh, de);
|
| 131 | }
|
| 132 |
|
| 133 | |
| 134 | * Like fat_get_entry(), but honour the FAT end-of-directory marker:
|
| 135 | * a dirent whose first name byte is NUL terminates iteration per the
|
| 136 | * spec, which also guarantees that every following slot is zeroed.
|
| 137 | * Skip straight to the end of the directory so the next call returns
|
| 138 | * -1 from fat_bmap() without re-reading the trailing zero slots, and
|
| 139 | * so callers that persist *pos across invocations (e.g. readdir's
|
| 140 | * ctx->pos) keep reporting EOD. Release *bh and set it to NULL to
|
| 141 | * match fat_get_entry()'s contract that *bh is NULL on the -1 return.
|
| 142 |
|
| 143 | static int fat_get_entry_eod(struct inode *dir, loff_t *pos,
|
| 144 | struct buffer_head **bh,
|
| 145 | struct msdos_dir_entry **de)
|
| 146 | {
|
| 147 | int err = fat_get_entry(dir, pos, bh, de);
|
| 148 |
|
| 149 | if (err == 0 && (*de)->name[0] == 0) {
|
| 150 | brelse(*bh);
|
| 151 | *bh = NULL;
|
| 152 | *pos = dir->i_size;
|
| 153 | return -1;
|
| 154 | }
|
| 155 | return err;
|
| 156 | }
|
| 157 |
|
| 158 | |
| 159 | * Convert Unicode 16 to UTF-8, translated Unicode, or ASCII.
|
| 160 | * If uni_xlate is enabled and we can't get a 1:1 conversion, use a
|
| 161 | * colon as an escape character since it is normally invalid on the vfat
|
| 162 | * filesystem. The following four characters are the hexadecimal digits
|
| 163 | * of Unicode value. This lets us do a full dump and restore of Unicode
|
| 164 | * filenames. We could get into some trouble with long Unicode names,
|
| 165 | * but ignore that right now.
|
| 166 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
|
| 167 |
|
| 168 | static int uni16_to_x8(struct super_block *sb, unsigned char *ascii,
|
| 169 | const wchar_t *uni, int len, struct nls_table *nls)
|
| 170 | {
|
| 171 | int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
|
| 172 | const wchar_t *ip;
|
| 173 | wchar_t ec;
|
| 174 | unsigned char *op;
|
| 175 | int charlen;
|
| 176 |
|
| 177 | ip = uni;
|
| 178 | op = ascii;
|
| 179 |
|
| 180 | while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) {
|
| 181 | ec = *ip++;
|
| 182 | charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE);
|
| 183 | if (charlen > 0) {
|
| 184 | op += charlen;
|
| 185 | len -= charlen;
|
| 186 | } else {
|
| 187 | if (uni_xlate == 1) {
|
| 188 | *op++ = ':';
|
| 189 | op = hex_byte_pack(op, ec >> 8);
|
| 190 | op = hex_byte_pack(op, ec);
|
| 191 | len -= 5;
|
| 192 | } else {
|
| 193 | *op++ = '?';
|
| 194 | len--;
|
| 195 | }
|
| 196 | }
|
| 197 | }
|
| 198 |
|
| 199 | if (unlikely(*ip)) {
|
| 200 | fat_msg(sb, KERN_WARNING,
|
| 201 | "filename was truncated while converting.");
|
| 202 | }
|
| 203 |
|
| 204 | *op = 0;
|
| 205 | return op - ascii;
|
| 206 | }
|
| 207 |
|
| 208 | static inline int fat_uni_to_x8(struct super_block *sb, const wchar_t *uni,
|
| 209 | unsigned char *buf, int size)
|
| 210 | {
|
| 211 | struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
| 212 | if (sbi->options.utf8)
|
| 213 | return utf16s_to_utf8s(uni, FAT_MAX_UNI_CHARS,
|
| 214 | UTF16_HOST_ENDIAN, buf, size);
|
| 215 | else
|
| 216 | return uni16_to_x8(sb, buf, uni, size, sbi->nls_io);
|
| 217 | }
|
| 218 |
|
| 219 | static inline int
|
| 220 | fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni)
|
| 221 | {
|
| 222 | int charlen;
|
| 223 |
|
| 224 | charlen = t->char2uni(c, clen, uni);
|
| 225 | if (charlen < 0) {
|
| 226 | *uni = 0x003f;
|
| 227 | charlen = 1;
|
| 228 | }
|
| 229 | return charlen;
|
| 230 | }
|
| 231 |
|
| 232 | static inline int
|
| 233 | fat_short2lower_uni(struct nls_table *t, unsigned char *c,
|
| 234 | int clen, wchar_t *uni)
|
| 235 | {
|
| 236 | int charlen;
|
| 237 | wchar_t wc;
|
| 238 |
|
| 239 | charlen = t->char2uni(c, clen, &wc);
|
| 240 | if (charlen < 0) {
|
| 241 | *uni = 0x003f;
|
| 242 | charlen = 1;
|
| 243 | } else if (charlen <= 1) {
|
| 244 | unsigned char nc = t->charset2lower[*c];
|
| 245 |
|
| 246 | if (!nc)
|
| 247 | nc = *c;
|
| 248 |
|
| 249 | charlen = t->char2uni(&nc, 1, uni);
|
| 250 | if (charlen < 0) {
|
| 251 | *uni = 0x003f;
|
| 252 | charlen = 1;
|
| 253 | }
|
| 254 | } else
|
| 255 | *uni = wc;
|
| 256 |
|
| 257 | return charlen;
|
| 258 | }
|
| 259 |
|
| 260 | static inline int
|
| 261 | fat_shortname2uni(struct nls_table *nls, unsigned char *buf, int buf_size,
|
| 262 | wchar_t *uni_buf, unsigned short opt, int lower)
|
| 263 | {
|
| 264 | int len = 0;
|
| 265 |
|
| 266 | if (opt & VFAT_SFN_DISPLAY_LOWER)
|
| 267 | len = fat_short2lower_uni(nls, buf, buf_size, uni_buf);
|
| 268 | else if (opt & VFAT_SFN_DISPLAY_WIN95)
|
| 269 | len = fat_short2uni(nls, buf, buf_size, uni_buf);
|
| 270 | else if (opt & VFAT_SFN_DISPLAY_WINNT) {
|
| 271 | if (lower)
|
| 272 | len = fat_short2lower_uni(nls, buf, buf_size, uni_buf);
|
| 273 | else
|
| 274 | len = fat_short2uni(nls, buf, buf_size, uni_buf);
|
| 275 | } else
|
| 276 | len = fat_short2uni(nls, buf, buf_size, uni_buf);
|
| 277 |
|
| 278 | return len;
|
| 279 | }
|
| 280 |
|
| 281 | static inline int fat_name_match(struct msdos_sb_info *sbi,
|
| 282 | const unsigned char *a, int a_len,
|
| 283 | const unsigned char *b, int b_len)
|
| 284 | {
|
| 285 | if (a_len != b_len)
|
| 286 | return 0;
|
| 287 |
|
| 288 | if (sbi->options.name_check != 's')
|
| 289 | return !nls_strnicmp(sbi->nls_io, a, b, a_len);
|
| 290 | else
|
| 291 | return !memcmp(a, b, a_len);
|
| 292 | }
|
| 293 |
|
| 294 | enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, };
|
| 295 |
|
| 296 | |
| 297 | * fat_parse_long - Parse extended directory entry.
|
| 298 | *
|
| 299 | * @dir: Pointer to the inode that represents the directory.
|
| 300 | * @pos: On input, contains the starting position to read from.
|
| 301 | * On output, updated with the new position.
|
| 302 | * @bh: Pointer to the buffer head that may be used for reading directory
|
| 303 | * entries. May be updated.
|
| 304 | * @de: On input, points to the current directory entry.
|
| 305 | * On output, points to the next directory entry.
|
| 306 | * @unicode: Pointer to a buffer where the parsed Unicode long filename will be
|
| 307 | * stored.
|
| 308 | * @nr_slots: Pointer to a variable that will store the number of longname
|
| 309 | * slots found.
|
| 310 | *
|
| 311 | * This function returns zero on success, negative value on error, or one of
|
| 312 | * the following:
|
| 313 | *
|
| 314 | * %PARSE_INVALID - Directory entry is invalid.
|
| 315 | * %PARSE_NOT_LONGNAME - Directory entry does not contain longname.
|
| 316 | * %PARSE_EOF - Directory has no more entries.
|
| 317 |
|
| 318 | static int fat_parse_long(struct inode *dir, loff_t *pos,
|
| 319 | struct buffer_head **bh, struct msdos_dir_entry **de,
|
| 320 | wchar_t **unicode, unsigned char *nr_slots)
|
| 321 | {
|
| 322 | struct msdos_dir_slot *ds;
|
| 323 | unsigned char id, slot, slots, alias_checksum;
|
| 324 |
|
| 325 | if (!*unicode) {
|
| 326 | *unicode = __getname();
|
| 327 | if (!*unicode) {
|
| 328 | brelse(*bh);
|
| 329 | return -ENOMEM;
|
| 330 | }
|
| 331 | }
|
| 332 | parse_long:
|
| 333 | ds = (struct msdos_dir_slot *)*de;
|
| 334 | id = ds->id;
|
| 335 | if (!(id & 0x40))
|
| 336 | return PARSE_INVALID;
|
| 337 | slots = id & ~0x40;
|
| 338 | if (slots > 20 || !slots)
|
| 339 | return PARSE_INVALID;
|
| 340 | *nr_slots = slots;
|
| 341 | alias_checksum = ds->alias_checksum;
|
| 342 |
|
| 343 | slot = slots;
|
| 344 | while (1) {
|
| 345 | int offset;
|
| 346 |
|
| 347 | slot--;
|
| 348 | offset = slot * 13;
|
| 349 | fat16_towchar(*unicode + offset, ds->name0_4, 5);
|
| 350 | fat16_towchar(*unicode + offset + 5, ds->name5_10, 6);
|
| 351 | fat16_towchar(*unicode + offset + 11, ds->name11_12, 2);
|
| 352 |
|
| 353 | if (ds->id & 0x40)
|
| 354 | (*unicode)[offset + 13] = 0;
|
| 355 | if (fat_get_entry_eod(dir, pos, bh, de) < 0)
|
| 356 | return PARSE_EOF;
|
| 357 | if (slot == 0)
|
| 358 | break;
|
| 359 | ds = (struct msdos_dir_slot *)*de;
|
| 360 | if (ds->attr != ATTR_EXT)
|
| 361 | return PARSE_NOT_LONGNAME;
|
| 362 | if ((ds->id & ~0x40) != slot)
|
| 363 | goto parse_long;
|
| 364 | if (ds->alias_checksum != alias_checksum)
|
| 365 | goto parse_long;
|
| 366 | }
|
| 367 | if ((*de)->name[0] == DELETED_FLAG)
|
| 368 | return PARSE_INVALID;
|
| 369 | if ((*de)->attr == ATTR_EXT)
|
| 370 | goto parse_long;
|
| 371 | if (IS_FREE((*de)->name) || ((*de)->attr & ATTR_VOLUME))
|
| 372 | return PARSE_INVALID;
|
| 373 | if (fat_checksum((*de)->name) != alias_checksum)
|
| 374 | *nr_slots = 0;
|
| 375 |
|
| 376 | return 0;
|
| 377 | }
|
| 378 |
|
| 379 | |
| 380 | * fat_parse_short - Parse MS-DOS (short) directory entry.
|
| 381 | * @sb: superblock
|
| 382 | * @de: directory entry to parse
|
| 383 | * @name: FAT_MAX_SHORT_SIZE array in which to place extracted name
|
| 384 | * @dot_hidden: Nonzero == prepend '.' to names with ATTR_HIDDEN
|
| 385 | *
|
| 386 | * Returns the number of characters extracted into 'name'.
|
| 387 |
|
| 388 | static int fat_parse_short(struct super_block *sb,
|
| 389 | const struct msdos_dir_entry *de,
|
| 390 | unsigned char *name, int dot_hidden)
|
| 391 | {
|
| 392 | const struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
| 393 | int isvfat = sbi->options.isvfat;
|
| 394 | int nocase = sbi->options.nocase;
|
| 395 | unsigned short opt_shortname = sbi->options.shortname;
|
| 396 | struct nls_table *nls_disk = sbi->nls_disk;
|
| 397 | wchar_t uni_name[14];
|
| 398 | unsigned char c, work[MSDOS_NAME];
|
| 399 | unsigned char *ptname = name;
|
| 400 | int chi, chl, i, j, k;
|
| 401 | int dotoffset = 0;
|
| 402 | int name_len = 0, uni_len = 0;
|
| 403 |
|
| 404 | if (!isvfat && dot_hidden && (de->attr & ATTR_HIDDEN)) {
|
| 405 | *ptname++ = '.';
|
| 406 | dotoffset = 1;
|
| 407 | }
|
| 408 |
|
| 409 | memcpy(work, de->name, sizeof(work));
|
| 410 | |
| 411 | * filenames, see msdos_format_name in namei_msdos.c
|
| 412 |
|
| 413 | if (work[0] == 0x05)
|
| 414 | work[0] = 0xE5;
|
| 415 |
|
| 416 |
|
| 417 | for (i = 0, j = 0; i < 8;) {
|
| 418 | c = work[i];
|
| 419 | if (!c)
|
| 420 | break;
|
| 421 | chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
|
| 422 | &uni_name[j++], opt_shortname,
|
| 423 | de->lcase & CASE_LOWER_BASE);
|
| 424 | if (chl <= 1) {
|
| 425 | if (!isvfat)
|
| 426 | ptname[i] = nocase ? c : fat_tolower(c);
|
| 427 | i++;
|
| 428 | if (c != ' ') {
|
| 429 | name_len = i;
|
| 430 | uni_len = j;
|
| 431 | }
|
| 432 | } else {
|
| 433 | uni_len = j;
|
| 434 | if (isvfat)
|
| 435 | i += min(chl, 8-i);
|
| 436 | else {
|
| 437 | for (chi = 0; chi < chl && i < 8; chi++, i++)
|
| 438 | ptname[i] = work[i];
|
| 439 | }
|
| 440 | if (chl)
|
| 441 | name_len = i;
|
| 442 | }
|
| 443 | }
|
| 444 |
|
| 445 | i = name_len;
|
| 446 | j = uni_len;
|
| 447 | fat_short2uni(nls_disk, ".", 1, &uni_name[j++]);
|
| 448 | if (!isvfat)
|
| 449 | ptname[i] = '.';
|
| 450 | i++;
|
| 451 |
|
| 452 |
|
| 453 | for (k = 8; k < MSDOS_NAME;) {
|
| 454 | c = work[k];
|
| 455 | if (!c)
|
| 456 | break;
|
| 457 | chl = fat_shortname2uni(nls_disk, &work[k], MSDOS_NAME - k,
|
| 458 | &uni_name[j++], opt_shortname,
|
| 459 | de->lcase & CASE_LOWER_EXT);
|
| 460 | if (chl <= 1) {
|
| 461 | k++;
|
| 462 | if (!isvfat)
|
| 463 | ptname[i] = nocase ? c : fat_tolower(c);
|
| 464 | i++;
|
| 465 | if (c != ' ') {
|
| 466 | name_len = i;
|
| 467 | uni_len = j;
|
| 468 | }
|
| 469 | } else {
|
| 470 | uni_len = j;
|
| 471 | if (isvfat) {
|
| 472 | int offset = min(chl, MSDOS_NAME-k);
|
| 473 | k += offset;
|
| 474 | i += offset;
|
| 475 | } else {
|
| 476 | for (chi = 0; chi < chl && k < MSDOS_NAME;
|
| 477 | chi++, i++, k++) {
|
| 478 | ptname[i] = work[k];
|
| 479 | }
|
| 480 | }
|
| 481 | if (chl)
|
| 482 | name_len = i;
|
| 483 | }
|
| 484 | }
|
| 485 |
|
| 486 | if (name_len > 0) {
|
| 487 | name_len += dotoffset;
|
| 488 |
|
| 489 | if (sbi->options.isvfat) {
|
| 490 | uni_name[uni_len] = 0x0000;
|
| 491 | name_len = fat_uni_to_x8(sb, uni_name, name,
|
| 492 | FAT_MAX_SHORT_SIZE);
|
| 493 | }
|
| 494 | }
|
| 495 |
|
| 496 | return name_len;
|
| 497 | }
|
| 498 |
|
| 499 | |
| 500 | * Return values: negative -> error/not found, 0 -> found.
|
| 501 |
|
| 502 | int fat_search_long(struct inode *inode, const unsigned char *name,
|
| 503 | int name_len, struct fat_slot_info *sinfo)
|
| 504 | {
|
| 505 | struct super_block *sb = inode->i_sb;
|
| 506 | struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
| 507 | struct buffer_head *bh = NULL;
|
| 508 | struct msdos_dir_entry *de;
|
| 509 | unsigned char nr_slots;
|
| 510 | wchar_t *unicode = NULL;
|
| 511 | unsigned char bufname[FAT_MAX_SHORT_SIZE];
|
| 512 | loff_t cpos = 0;
|
| 513 | int err, len;
|
| 514 |
|
| 515 | err = -ENOENT;
|
| 516 | while (1) {
|
| 517 | if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1)
|
| 518 | goto end_of_dir;
|
| 519 | parse_record:
|
| 520 | nr_slots = 0;
|
| 521 | if (de->name[0] == DELETED_FLAG)
|
| 522 | continue;
|
| 523 | if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
|
| 524 | continue;
|
| 525 | if (de->attr != ATTR_EXT && IS_FREE(de->name))
|
| 526 | continue;
|
| 527 | if (de->attr == ATTR_EXT) {
|
| 528 | int status = fat_parse_long(inode, &cpos, &bh, &de,
|
| 529 | &unicode, &nr_slots);
|
| 530 | if (status < 0) {
|
| 531 | err = status;
|
| 532 | goto end_of_dir;
|
| 533 | } else if (status == PARSE_INVALID)
|
| 534 | continue;
|
| 535 | else if (status == PARSE_NOT_LONGNAME)
|
| 536 | goto parse_record;
|
| 537 | else if (status == PARSE_EOF)
|
| 538 | goto end_of_dir;
|
| 539 | }
|
| 540 |
|
| 541 | |
| 542 | * That is done only for msdos mounts (and only when
|
| 543 | * 'dotsOK=yes'); if we are executing here, it is in the
|
| 544 | * context of a vfat mount.
|
| 545 |
|
| 546 | len = fat_parse_short(sb, de, bufname, 0);
|
| 547 | if (len == 0)
|
| 548 | continue;
|
| 549 |
|
| 550 |
|
| 551 | if (fat_name_match(sbi, name, name_len, bufname, len))
|
| 552 | goto found;
|
| 553 |
|
| 554 | if (nr_slots) {
|
| 555 | void *longname = unicode + FAT_MAX_UNI_CHARS;
|
| 556 | int size = PATH_MAX - FAT_MAX_UNI_SIZE;
|
| 557 |
|
| 558 |
|
| 559 | len = fat_uni_to_x8(sb, unicode, longname, size);
|
| 560 | if (fat_name_match(sbi, name, name_len, longname, len))
|
| 561 | goto found;
|
| 562 | }
|
| 563 | }
|
| 564 |
|
| 565 | found:
|
| 566 | nr_slots++;
|
| 567 | sinfo->slot_off = cpos - nr_slots * sizeof(*de);
|
| 568 | sinfo->nr_slots = nr_slots;
|
| 569 | sinfo->de = de;
|
| 570 | sinfo->bh = bh;
|
| 571 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
|
| 572 | err = 0;
|
| 573 | end_of_dir:
|
| 574 | if (unicode)
|
| 575 | __putname(unicode);
|
| 576 |
|
| 577 | return err;
|
| 578 | }
|
| 579 | EXPORT_SYMBOL_GPL(fat_search_long);
|
| 580 |
|
| 581 | struct fat_ioctl_filldir_callback {
|
| 582 | struct dir_context ctx;
|
| 583 | void __user *dirent;
|
| 584 | int result;
|
| 585 |
|
| 586 | const char *longname;
|
| 587 | int long_len;
|
| 588 | const char *shortname;
|
| 589 | int short_len;
|
| 590 | };
|
| 591 |
|
| 592 | static int __fat_readdir(struct inode *inode, struct file *file,
|
| 593 | struct dir_context *ctx, int short_only,
|
| 594 | struct fat_ioctl_filldir_callback *both)
|
| 595 | {
|
| 596 | struct super_block *sb = inode->i_sb;
|
| 597 | struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
| 598 | struct buffer_head *bh;
|
| 599 | struct msdos_dir_entry *de;
|
| 600 | unsigned char nr_slots;
|
| 601 | wchar_t *unicode = NULL;
|
| 602 | unsigned char bufname[FAT_MAX_SHORT_SIZE];
|
| 603 | int isvfat = sbi->options.isvfat;
|
| 604 | const char *fill_name = NULL;
|
| 605 | int fake_offset = 0;
|
| 606 | loff_t cpos;
|
| 607 | int short_len = 0, fill_len = 0;
|
| 608 | int ret = 0;
|
| 609 |
|
| 610 | mutex_lock(&sbi->s_lock);
|
| 611 |
|
| 612 | cpos = ctx->pos;
|
| 613 |
|
| 614 | if (inode->i_ino == MSDOS_ROOT_INO) {
|
| 615 | if (!dir_emit_dots(file, ctx))
|
| 616 | goto out;
|
| 617 | if (ctx->pos == 2) {
|
| 618 | fake_offset = 1;
|
| 619 | cpos = 0;
|
| 620 | }
|
| 621 | }
|
| 622 | if (cpos & (sizeof(struct msdos_dir_entry) - 1)) {
|
| 623 | ret = -ENOENT;
|
| 624 | goto out;
|
| 625 | }
|
| 626 |
|
| 627 | bh = NULL;
|
| 628 | get_new:
|
| 629 | if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1)
|
| 630 | goto end_of_dir;
|
| 631 | parse_record:
|
| 632 | nr_slots = 0;
|
| 633 | |
| 634 | * Check for long filename entry, but if short_only, we don't
|
| 635 | * need to parse long filename.
|
| 636 |
|
| 637 | if (isvfat && !short_only) {
|
| 638 | if (de->name[0] == DELETED_FLAG)
|
| 639 | goto record_end;
|
| 640 | if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
|
| 641 | goto record_end;
|
| 642 | if (de->attr != ATTR_EXT && IS_FREE(de->name))
|
| 643 | goto record_end;
|
| 644 | } else {
|
| 645 | if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))
|
| 646 | goto record_end;
|
| 647 | }
|
| 648 |
|
| 649 | if (isvfat && de->attr == ATTR_EXT) {
|
| 650 | int status = fat_parse_long(inode, &cpos, &bh, &de,
|
| 651 | &unicode, &nr_slots);
|
| 652 | if (status < 0) {
|
| 653 | bh = NULL;
|
| 654 | ret = status;
|
| 655 | goto end_of_dir;
|
| 656 | } else if (status == PARSE_INVALID)
|
| 657 | goto record_end;
|
| 658 | else if (status == PARSE_NOT_LONGNAME)
|
| 659 | goto parse_record;
|
| 660 | else if (status == PARSE_EOF)
|
| 661 | goto end_of_dir;
|
| 662 |
|
| 663 | if (nr_slots) {
|
| 664 | void *longname = unicode + FAT_MAX_UNI_CHARS;
|
| 665 | int size = PATH_MAX - FAT_MAX_UNI_SIZE;
|
| 666 | int len = fat_uni_to_x8(sb, unicode, longname, size);
|
| 667 |
|
| 668 | fill_name = longname;
|
| 669 | fill_len = len;
|
| 670 |
|
| 671 | if (!both)
|
| 672 | goto start_filldir;
|
| 673 |
|
| 674 | short_len = fat_parse_short(sb, de, bufname,
|
| 675 | sbi->options.dotsOK);
|
| 676 | if (short_len == 0)
|
| 677 | goto record_end;
|
| 678 |
|
| 679 | both->longname = fill_name;
|
| 680 | both->long_len = fill_len;
|
| 681 | both->shortname = bufname;
|
| 682 | both->short_len = short_len;
|
| 683 | fill_name = NULL;
|
| 684 | fill_len = 0;
|
| 685 | goto start_filldir;
|
| 686 | }
|
| 687 | }
|
| 688 |
|
| 689 | short_len = fat_parse_short(sb, de, bufname, sbi->options.dotsOK);
|
| 690 | if (short_len == 0)
|
| 691 | goto record_end;
|
| 692 |
|
| 693 | fill_name = bufname;
|
| 694 | fill_len = short_len;
|
| 695 |
|
| 696 | start_filldir:
|
| 697 | ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
|
| 698 | if (fake_offset && ctx->pos < 2)
|
| 699 | ctx->pos = 2;
|
| 700 |
|
| 701 | if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
|
| 702 | if (!dir_emit_dot(file, ctx))
|
| 703 | goto fill_failed;
|
| 704 | } else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
|
| 705 | if (!dir_emit_dotdot(file, ctx))
|
| 706 | goto fill_failed;
|
| 707 | } else {
|
| 708 | unsigned long inum;
|
| 709 | loff_t i_pos = fat_make_i_pos(sb, bh, de);
|
| 710 | struct inode *tmp = fat_iget(sb, i_pos);
|
| 711 | if (tmp) {
|
| 712 | inum = tmp->i_ino;
|
| 713 | iput(tmp);
|
| 714 | } else
|
| 715 | inum = iunique(sb, MSDOS_ROOT_INO);
|
| 716 | if (!dir_emit(ctx, fill_name, fill_len, inum,
|
| 717 | (de->attr & ATTR_DIR) ? DT_DIR : DT_REG))
|
| 718 | goto fill_failed;
|
| 719 | }
|
| 720 |
|
| 721 | record_end:
|
| 722 | fake_offset = 0;
|
| 723 | ctx->pos = cpos;
|
| 724 | goto get_new;
|
| 725 |
|
| 726 | end_of_dir:
|
| 727 | if (fake_offset && cpos < 2)
|
| 728 | ctx->pos = 2;
|
| 729 | else
|
| 730 | ctx->pos = cpos;
|
| 731 | fill_failed:
|
| 732 | brelse(bh);
|
| 733 | if (unicode)
|
| 734 | __putname(unicode);
|
| 735 | out:
|
| 736 | mutex_unlock(&sbi->s_lock);
|
| 737 |
|
| 738 | return ret;
|
| 739 | }
|
| 740 |
|
| 741 | static int fat_readdir(struct file *file, struct dir_context *ctx)
|
| 742 | {
|
| 743 | return __fat_readdir(file_inode(file), file, ctx, 0, NULL);
|
| 744 | }
|
| 745 |
|
| 746 | #define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \
|
| 747 | static bool func(struct dir_context *ctx, const char *name, int name_len, \
|
| 748 | loff_t offset, u64 ino, unsigned int d_type) \
|
| 749 | { \
|
| 750 | struct fat_ioctl_filldir_callback *buf = \
|
| 751 | container_of(ctx, struct fat_ioctl_filldir_callback, ctx); \
|
| 752 | struct dirent_type __user *d1 = buf->dirent; \
|
| 753 | struct dirent_type __user *d2 = d1 + 1; \
|
| 754 | \
|
| 755 | if (buf->result) \
|
| 756 | return false; \
|
| 757 | buf->result++; \
|
| 758 | \
|
| 759 | if (name != NULL) { \
|
| 760 | \
|
| 761 | if (name_len >= sizeof(d1->d_name)) \
|
| 762 | name_len = sizeof(d1->d_name) - 1; \
|
| 763 | \
|
| 764 | if (put_user(0, &d2->d_name[0]) || \
|
| 765 | put_user(0, &d2->d_reclen) || \
|
| 766 | copy_to_user(d1->d_name, name, name_len) || \
|
| 767 | put_user(0, d1->d_name + name_len) || \
|
| 768 | put_user(name_len, &d1->d_reclen)) \
|
| 769 | goto efault; \
|
| 770 | } else { \
|
| 771 | \
|
| 772 | const char *longname = buf->longname; \
|
| 773 | int long_len = buf->long_len; \
|
| 774 | const char *shortname = buf->shortname; \
|
| 775 | int short_len = buf->short_len; \
|
| 776 | \
|
| 777 | if (long_len >= sizeof(d1->d_name)) \
|
| 778 | long_len = sizeof(d1->d_name) - 1; \
|
| 779 | if (short_len >= sizeof(d1->d_name)) \
|
| 780 | short_len = sizeof(d1->d_name) - 1; \
|
| 781 | \
|
| 782 | if (copy_to_user(d2->d_name, longname, long_len) || \
|
| 783 | put_user(0, d2->d_name + long_len) || \
|
| 784 | put_user(long_len, &d2->d_reclen) || \
|
| 785 | put_user(ino, &d2->d_ino) || \
|
| 786 | put_user(offset, &d2->d_off) || \
|
| 787 | copy_to_user(d1->d_name, shortname, short_len) || \
|
| 788 | put_user(0, d1->d_name + short_len) || \
|
| 789 | put_user(short_len, &d1->d_reclen)) \
|
| 790 | goto efault; \
|
| 791 | } \
|
| 792 | return true; \
|
| 793 | efault: \
|
| 794 | buf->result = -EFAULT; \
|
| 795 | return false; \
|
| 796 | }
|
| 797 |
|
| 798 | FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent)
|
| 799 |
|
| 800 | static int fat_ioctl_readdir(struct inode *inode, struct file *file,
|
| 801 | void __user *dirent, filldir_t filldir,
|
| 802 | int short_only, int both)
|
| 803 | {
|
| 804 | struct fat_ioctl_filldir_callback buf = {
|
| 805 | .ctx.actor = filldir,
|
| 806 | .dirent = dirent
|
| 807 | };
|
| 808 | int ret;
|
| 809 |
|
| 810 | buf.dirent = dirent;
|
| 811 | buf.result = 0;
|
| 812 | inode_lock_shared(inode);
|
| 813 | buf.ctx.pos = file->f_pos;
|
| 814 | ret = -ENOENT;
|
| 815 | if (!IS_DEADDIR(inode)) {
|
| 816 | ret = __fat_readdir(inode, file, &buf.ctx,
|
| 817 | short_only, both ? &buf : NULL);
|
| 818 | file->f_pos = buf.ctx.pos;
|
| 819 | }
|
| 820 | inode_unlock_shared(inode);
|
| 821 | if (ret >= 0)
|
| 822 | ret = buf.result;
|
| 823 | return ret;
|
| 824 | }
|
| 825 |
|
| 826 | static long fat_dir_ioctl(struct file *filp, unsigned int cmd,
|
| 827 | unsigned long arg)
|
| 828 | {
|
| 829 | struct inode *inode = file_inode(filp);
|
| 830 | struct __fat_dirent __user *d1 = (struct __fat_dirent __user *)arg;
|
| 831 | int short_only, both;
|
| 832 |
|
| 833 | switch (cmd) {
|
| 834 | case VFAT_IOCTL_READDIR_SHORT:
|
| 835 | short_only = 1;
|
| 836 | both = 0;
|
| 837 | break;
|
| 838 | case VFAT_IOCTL_READDIR_BOTH:
|
| 839 | short_only = 0;
|
| 840 | both = 1;
|
| 841 | break;
|
| 842 | default:
|
| 843 | return fat_generic_ioctl(filp, cmd, arg);
|
| 844 | }
|
| 845 |
|
| 846 | |
| 847 | * Yes, we don't need this put_user() absolutely. However old
|
| 848 | * code didn't return the right value. So, app use this value,
|
| 849 | * in order to check whether it is EOF.
|
| 850 |
|
| 851 | if (put_user(0, &d1->d_reclen))
|
| 852 | return -EFAULT;
|
| 853 |
|
| 854 | return fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir,
|
| 855 | short_only, both);
|
| 856 | }
|
| 857 |
|
| 858 | #ifdef CONFIG_COMPAT
|
| 859 | #define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
|
| 860 | #define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
|
| 861 |
|
| 862 | FAT_IOCTL_FILLDIR_FUNC(fat_compat_ioctl_filldir, compat_dirent)
|
| 863 |
|
| 864 | static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
|
| 865 | unsigned long arg)
|
| 866 | {
|
| 867 | struct inode *inode = file_inode(filp);
|
| 868 | struct compat_dirent __user *d1 = compat_ptr(arg);
|
| 869 | int short_only, both;
|
| 870 |
|
| 871 | switch (cmd) {
|
| 872 | case VFAT_IOCTL_READDIR_SHORT32:
|
| 873 | short_only = 1;
|
| 874 | both = 0;
|
| 875 | break;
|
| 876 | case VFAT_IOCTL_READDIR_BOTH32:
|
| 877 | short_only = 0;
|
| 878 | both = 1;
|
| 879 | break;
|
| 880 | default:
|
| 881 | return fat_generic_ioctl(filp, cmd, (unsigned long)arg);
|
| 882 | }
|
| 883 |
|
| 884 | |
| 885 | * Yes, we don't need this put_user() absolutely. However old
|
| 886 | * code didn't return the right value. So, app use this value,
|
| 887 | * in order to check whether it is EOF.
|
| 888 |
|
| 889 | if (put_user(0, &d1->d_reclen))
|
| 890 | return -EFAULT;
|
| 891 |
|
| 892 | return fat_ioctl_readdir(inode, filp, d1, fat_compat_ioctl_filldir,
|
| 893 | short_only, both);
|
| 894 | }
|
| 895 | #endif
|
| 896 |
|
| 897 | const struct file_operations fat_dir_operations = {
|
| 898 | .llseek = generic_file_llseek,
|
| 899 | .read = generic_read_dir,
|
| 900 | .iterate_shared = fat_readdir,
|
| 901 | .unlocked_ioctl = fat_dir_ioctl,
|
| 902 | #ifdef CONFIG_COMPAT
|
| 903 | .compat_ioctl = fat_compat_dir_ioctl,
|
| 904 | #endif
|
| 905 | .fsync = fat_file_fsync,
|
| 906 | .setlease = generic_setlease,
|
| 907 | };
|
| 908 |
|
| 909 | static int fat_get_short_entry(struct inode *dir, loff_t *pos,
|
| 910 | struct buffer_head **bh,
|
| 911 | struct msdos_dir_entry **de)
|
| 912 | {
|
| 913 | while (fat_get_entry_eod(dir, pos, bh, de) >= 0) {
|
| 914 |
|
| 915 | if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME))
|
| 916 | return 0;
|
| 917 | }
|
| 918 | return -ENOENT;
|
| 919 | }
|
| 920 |
|
| 921 | |
| 922 | * The ".." entry can not provide the "struct fat_slot_info" information
|
| 923 | * for inode, nor a usable i_pos. So, this function provides some information
|
| 924 | * only.
|
| 925 | *
|
| 926 | * Since this function walks through the on-disk inodes within a directory,
|
| 927 | * callers are responsible for taking any locks necessary to prevent the
|
| 928 | * directory from changing.
|
| 929 |
|
| 930 | int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
|
| 931 | struct msdos_dir_entry **de)
|
| 932 | {
|
| 933 | loff_t offset = 0;
|
| 934 |
|
| 935 | *de = NULL;
|
| 936 | while (fat_get_short_entry(dir, &offset, bh, de) >= 0) {
|
| 937 | if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME))
|
| 938 | return 0;
|
| 939 | }
|
| 940 | return -ENOENT;
|
| 941 | }
|
| 942 | EXPORT_SYMBOL_GPL(fat_get_dotdot_entry);
|
| 943 |
|
| 944 |
|
| 945 | int fat_dir_empty(struct inode *dir)
|
| 946 | {
|
| 947 | struct buffer_head *bh;
|
| 948 | struct msdos_dir_entry *de;
|
| 949 | loff_t cpos;
|
| 950 | int result = 0;
|
| 951 |
|
| 952 | bh = NULL;
|
| 953 | cpos = 0;
|
| 954 | while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {
|
| 955 | if (strncmp(de->name, MSDOS_DOT , MSDOS_NAME) &&
|
| 956 | strncmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
|
| 957 | result = -ENOTEMPTY;
|
| 958 | break;
|
| 959 | }
|
| 960 | }
|
| 961 | brelse(bh);
|
| 962 | return result;
|
| 963 | }
|
| 964 | EXPORT_SYMBOL_GPL(fat_dir_empty);
|
| 965 |
|
| 966 | |
| 967 | * fat_subdirs counts the number of sub-directories of dir. It can be run
|
| 968 | * on directories being created.
|
| 969 |
|
| 970 | int fat_subdirs(struct inode *dir)
|
| 971 | {
|
| 972 | struct buffer_head *bh;
|
| 973 | struct msdos_dir_entry *de;
|
| 974 | loff_t cpos;
|
| 975 | int count = 0;
|
| 976 |
|
| 977 | bh = NULL;
|
| 978 | cpos = 0;
|
| 979 | while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {
|
| 980 | if (de->attr & ATTR_DIR)
|
| 981 | count++;
|
| 982 | }
|
| 983 | brelse(bh);
|
| 984 | return count;
|
| 985 | }
|
| 986 |
|
| 987 | |
| 988 | * Scans a directory for a given file (name points to its formatted name).
|
| 989 | * Returns an error code or zero.
|
| 990 |
|
| 991 | int fat_scan(struct inode *dir, const unsigned char *name,
|
| 992 | struct fat_slot_info *sinfo)
|
| 993 | {
|
| 994 | struct super_block *sb = dir->i_sb;
|
| 995 |
|
| 996 | sinfo->slot_off = 0;
|
| 997 | sinfo->bh = NULL;
|
| 998 | while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh,
|
| 999 | &sinfo->de) >= 0) {
|
| 1000 | if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) {
|
| 1001 | sinfo->slot_off -= sizeof(*sinfo->de);
|
| 1002 | sinfo->nr_slots = 1;
|
| 1003 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
|
| 1004 | return 0;
|
| 1005 | }
|
| 1006 | }
|
| 1007 | return -ENOENT;
|
| 1008 | }
|
| 1009 | EXPORT_SYMBOL_GPL(fat_scan);
|
| 1010 |
|
| 1011 | |
| 1012 | * Scans a directory for a given logstart.
|
| 1013 | * Returns an error code or zero.
|
| 1014 |
|
| 1015 | int fat_scan_logstart(struct inode *dir, int i_logstart,
|
| 1016 | struct fat_slot_info *sinfo)
|
| 1017 | {
|
| 1018 | struct super_block *sb = dir->i_sb;
|
| 1019 |
|
| 1020 | sinfo->slot_off = 0;
|
| 1021 | sinfo->bh = NULL;
|
| 1022 | while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh,
|
| 1023 | &sinfo->de) >= 0) {
|
| 1024 | if (fat_get_start(MSDOS_SB(sb), sinfo->de) == i_logstart) {
|
| 1025 | sinfo->slot_off -= sizeof(*sinfo->de);
|
| 1026 | sinfo->nr_slots = 1;
|
| 1027 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
|
| 1028 | return 0;
|
| 1029 | }
|
| 1030 | }
|
| 1031 | return -ENOENT;
|
| 1032 | }
|
| 1033 |
|
| 1034 | static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots)
|
| 1035 | {
|
| 1036 | struct super_block *sb = dir->i_sb;
|
| 1037 | struct buffer_head *bh;
|
| 1038 | struct msdos_dir_entry *de, *endp;
|
| 1039 | int err = 0, orig_slots;
|
| 1040 |
|
| 1041 | while (nr_slots) {
|
| 1042 | bh = NULL;
|
| 1043 | if (fat_get_entry(dir, &pos, &bh, &de) < 0) {
|
| 1044 | err = -EIO;
|
| 1045 | break;
|
| 1046 | }
|
| 1047 |
|
| 1048 | orig_slots = nr_slots;
|
| 1049 | endp = (struct msdos_dir_entry *)(bh->b_data + sb->s_blocksize);
|
| 1050 | while (nr_slots && de < endp) {
|
| 1051 | de->name[0] = DELETED_FLAG;
|
| 1052 | de++;
|
| 1053 | nr_slots--;
|
| 1054 | }
|
| 1055 | mmb_mark_buffer_dirty(bh, &MSDOS_I(dir)->i_metadata_bhs);
|
| 1056 | if (IS_DIRSYNC(dir))
|
| 1057 | err = sync_dirty_buffer(bh);
|
| 1058 | brelse(bh);
|
| 1059 | if (err)
|
| 1060 | break;
|
| 1061 |
|
| 1062 |
|
| 1063 | pos += ((orig_slots - nr_slots) * sizeof(*de)) - sizeof(*de);
|
| 1064 | }
|
| 1065 |
|
| 1066 | return err;
|
| 1067 | }
|
| 1068 |
|
| 1069 | int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
|
| 1070 | {
|
| 1071 | struct super_block *sb = dir->i_sb;
|
| 1072 | struct msdos_dir_entry *de;
|
| 1073 | struct buffer_head *bh;
|
| 1074 | int err = 0, nr_slots;
|
| 1075 |
|
| 1076 | |
| 1077 | * First stage: Remove the shortname. By this, the directory
|
| 1078 | * entry is removed.
|
| 1079 |
|
| 1080 | nr_slots = sinfo->nr_slots;
|
| 1081 | de = sinfo->de;
|
| 1082 | sinfo->de = NULL;
|
| 1083 | bh = sinfo->bh;
|
| 1084 | sinfo->bh = NULL;
|
| 1085 | while (nr_slots && de >= (struct msdos_dir_entry *)bh->b_data) {
|
| 1086 | de->name[0] = DELETED_FLAG;
|
| 1087 | de--;
|
| 1088 | nr_slots--;
|
| 1089 | }
|
| 1090 | mmb_mark_buffer_dirty(bh, &MSDOS_I(dir)->i_metadata_bhs);
|
| 1091 | if (IS_DIRSYNC(dir))
|
| 1092 | err = sync_dirty_buffer(bh);
|
| 1093 | brelse(bh);
|
| 1094 | if (err)
|
| 1095 | return err;
|
| 1096 | inode_inc_iversion(dir);
|
| 1097 |
|
| 1098 | if (nr_slots) {
|
| 1099 | |
| 1100 | * Second stage: remove the remaining longname slots.
|
| 1101 | * (This directory entry is already removed, and so return
|
| 1102 | * the success)
|
| 1103 |
|
| 1104 | err = __fat_remove_entries(dir, sinfo->slot_off, nr_slots);
|
| 1105 | if (err) {
|
| 1106 | fat_msg(sb, KERN_WARNING,
|
| 1107 | "Couldn't remove the long name slots");
|
| 1108 | }
|
| 1109 | }
|
| 1110 |
|
| 1111 | fat_truncate_time(dir, NULL, FAT_UPDATE_ATIME | FAT_UPDATE_CMTIME);
|
| 1112 | err = 0;
|
| 1113 | mark_inode_dirty(dir);
|
| 1114 | if (IS_DIRSYNC(dir))
|
| 1115 | (void)sync_inode_metadata(dir, 1);
|
| 1116 |
|
| 1117 | return 0;
|
| 1118 | }
|
| 1119 | EXPORT_SYMBOL_GPL(fat_remove_entries);
|
| 1120 |
|
| 1121 | static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used,
|
| 1122 | struct buffer_head **bhs, int nr_bhs)
|
| 1123 | {
|
| 1124 | struct super_block *sb = dir->i_sb;
|
| 1125 | sector_t last_blknr = blknr + MSDOS_SB(sb)->sec_per_clus;
|
| 1126 | int err, i, n;
|
| 1127 |
|
| 1128 |
|
| 1129 | blknr += nr_used;
|
| 1130 | n = nr_used;
|
| 1131 | while (blknr < last_blknr) {
|
| 1132 | bhs[n] = sb_getblk(sb, blknr);
|
| 1133 | if (!bhs[n]) {
|
| 1134 | err = -ENOMEM;
|
| 1135 | goto error;
|
| 1136 | }
|
| 1137 |
|
| 1138 | lock_buffer(bhs[n]);
|
| 1139 | memset(bhs[n]->b_data, 0, sb->s_blocksize);
|
| 1140 | set_buffer_uptodate(bhs[n]);
|
| 1141 | unlock_buffer(bhs[n]);
|
| 1142 | mmb_mark_buffer_dirty(bhs[n], &MSDOS_I(dir)->i_metadata_bhs);
|
| 1143 |
|
| 1144 | n++;
|
| 1145 | blknr++;
|
| 1146 | if (n == nr_bhs) {
|
| 1147 | if (IS_DIRSYNC(dir)) {
|
| 1148 | err = fat_sync_bhs(bhs, n);
|
| 1149 | if (err)
|
| 1150 | goto error;
|
| 1151 | }
|
| 1152 | for (i = 0; i < n; i++)
|
| 1153 | brelse(bhs[i]);
|
| 1154 | n = 0;
|
| 1155 | }
|
| 1156 | }
|
| 1157 | if (IS_DIRSYNC(dir)) {
|
| 1158 | err = fat_sync_bhs(bhs, n);
|
| 1159 | if (err)
|
| 1160 | goto error;
|
| 1161 | }
|
| 1162 | for (i = 0; i < n; i++)
|
| 1163 | brelse(bhs[i]);
|
| 1164 |
|
| 1165 | return 0;
|
| 1166 |
|
| 1167 | error:
|
| 1168 | for (i = 0; i < n; i++)
|
| 1169 | bforget(bhs[i]);
|
| 1170 | return err;
|
| 1171 | }
|
| 1172 |
|
| 1173 | int fat_alloc_new_dir(struct inode *dir, struct timespec64 *ts)
|
| 1174 | {
|
| 1175 | struct super_block *sb = dir->i_sb;
|
| 1176 | struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
| 1177 | struct buffer_head *bhs[MAX_BUF_PER_PAGE];
|
| 1178 | struct msdos_dir_entry *de;
|
| 1179 | sector_t blknr;
|
| 1180 | __le16 date, time;
|
| 1181 | u8 time_cs;
|
| 1182 | int err, cluster;
|
| 1183 |
|
| 1184 | err = fat_alloc_clusters(dir, &cluster, 1);
|
| 1185 | if (err)
|
| 1186 | goto error;
|
| 1187 |
|
| 1188 | blknr = fat_clus_to_blknr(sbi, cluster);
|
| 1189 | bhs[0] = sb_getblk(sb, blknr);
|
| 1190 | if (!bhs[0]) {
|
| 1191 | err = -ENOMEM;
|
| 1192 | goto error_free;
|
| 1193 | }
|
| 1194 |
|
| 1195 | fat_time_unix2fat(sbi, ts, &time, &date, &time_cs);
|
| 1196 |
|
| 1197 | de = (struct msdos_dir_entry *)bhs[0]->b_data;
|
| 1198 |
|
| 1199 | lock_buffer(bhs[0]);
|
| 1200 |
|
| 1201 | memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
|
| 1202 | memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
|
| 1203 | de->attr = de[1].attr = ATTR_DIR;
|
| 1204 | de[0].lcase = de[1].lcase = 0;
|
| 1205 | de[0].time = de[1].time = time;
|
| 1206 | de[0].date = de[1].date = date;
|
| 1207 | if (sbi->options.isvfat) {
|
| 1208 |
|
| 1209 | de[0].ctime = de[1].ctime = time;
|
| 1210 | de[0].ctime_cs = de[1].ctime_cs = time_cs;
|
| 1211 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
|
| 1212 | } else {
|
| 1213 | de[0].ctime = de[1].ctime = 0;
|
| 1214 | de[0].ctime_cs = de[1].ctime_cs = 0;
|
| 1215 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0;
|
| 1216 | }
|
| 1217 | fat_set_start(&de[0], cluster);
|
| 1218 | fat_set_start(&de[1], MSDOS_I(dir)->i_logstart);
|
| 1219 | de[0].size = de[1].size = 0;
|
| 1220 | memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de));
|
| 1221 | set_buffer_uptodate(bhs[0]);
|
| 1222 | unlock_buffer(bhs[0]);
|
| 1223 | mmb_mark_buffer_dirty(bhs[0], &MSDOS_I(dir)->i_metadata_bhs);
|
| 1224 |
|
| 1225 | err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE);
|
| 1226 | if (err)
|
| 1227 | goto error_free;
|
| 1228 |
|
| 1229 | return cluster;
|
| 1230 |
|
| 1231 | error_free:
|
| 1232 | fat_free_clusters(dir, cluster);
|
| 1233 | error:
|
| 1234 | return err;
|
| 1235 | }
|
| 1236 | EXPORT_SYMBOL_GPL(fat_alloc_new_dir);
|
| 1237 |
|
| 1238 | static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots,
|
| 1239 | int *nr_cluster, struct msdos_dir_entry **de,
|
| 1240 | struct buffer_head **bh)
|
| 1241 | {
|
| 1242 | struct super_block *sb = dir->i_sb;
|
| 1243 | struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
| 1244 | struct buffer_head *bhs[MAX_BUF_PER_PAGE];
|
| 1245 | sector_t blknr, start_blknr, last_blknr;
|
| 1246 | unsigned long size, copy;
|
| 1247 | int err, i, n, offset, cluster[2];
|
| 1248 |
|
| 1249 | |
| 1250 | * The minimum cluster size is 512bytes, and maximum entry
|
| 1251 | * size is 32*slots (672bytes). So, iff the cluster size is
|
| 1252 | * 512bytes, we may need two clusters.
|
| 1253 |
|
| 1254 | size = nr_slots * sizeof(struct msdos_dir_entry);
|
| 1255 | *nr_cluster = (size + (sbi->cluster_size - 1)) >> sbi->cluster_bits;
|
| 1256 | BUG_ON(*nr_cluster > 2);
|
| 1257 |
|
| 1258 | err = fat_alloc_clusters(dir, cluster, *nr_cluster);
|
| 1259 | if (err)
|
| 1260 | goto error;
|
| 1261 |
|
| 1262 | |
| 1263 | * First stage: Fill the directory entry. NOTE: This cluster
|
| 1264 | * is not referenced from any inode yet, so updates order is
|
| 1265 | * not important.
|
| 1266 |
|
| 1267 | i = n = copy = 0;
|
| 1268 | do {
|
| 1269 | start_blknr = blknr = fat_clus_to_blknr(sbi, cluster[i]);
|
| 1270 | last_blknr = start_blknr + sbi->sec_per_clus;
|
| 1271 | while (blknr < last_blknr) {
|
| 1272 | bhs[n] = sb_getblk(sb, blknr);
|
| 1273 | if (!bhs[n]) {
|
| 1274 | err = -ENOMEM;
|
| 1275 | goto error_nomem;
|
| 1276 | }
|
| 1277 |
|
| 1278 |
|
| 1279 | copy = min(size, sb->s_blocksize);
|
| 1280 |
|
| 1281 | lock_buffer(bhs[n]);
|
| 1282 | memcpy(bhs[n]->b_data, slots, copy);
|
| 1283 | set_buffer_uptodate(bhs[n]);
|
| 1284 | unlock_buffer(bhs[n]);
|
| 1285 | mmb_mark_buffer_dirty(bhs[n],
|
| 1286 | &MSDOS_I(dir)->i_metadata_bhs);
|
| 1287 | slots += copy;
|
| 1288 | size -= copy;
|
| 1289 | if (!size)
|
| 1290 | break;
|
| 1291 | n++;
|
| 1292 | blknr++;
|
| 1293 | }
|
| 1294 | } while (++i < *nr_cluster);
|
| 1295 |
|
| 1296 | memset(bhs[n]->b_data + copy, 0, sb->s_blocksize - copy);
|
| 1297 | offset = copy - sizeof(struct msdos_dir_entry);
|
| 1298 | get_bh(bhs[n]);
|
| 1299 | *bh = bhs[n];
|
| 1300 | *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
|
| 1301 |
|
| 1302 |
|
| 1303 | err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE);
|
| 1304 | if (err)
|
| 1305 | goto error_free;
|
| 1306 |
|
| 1307 | return cluster[0];
|
| 1308 |
|
| 1309 | error_free:
|
| 1310 | brelse(*bh);
|
| 1311 | *bh = NULL;
|
| 1312 | n = 0;
|
| 1313 | error_nomem:
|
| 1314 | for (i = 0; i < n; i++)
|
| 1315 | bforget(bhs[i]);
|
| 1316 | fat_free_clusters(dir, cluster[0]);
|
| 1317 | error:
|
| 1318 | return err;
|
| 1319 | }
|
| 1320 |
|
| 1321 | int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
|
| 1322 | struct fat_slot_info *sinfo)
|
| 1323 | {
|
| 1324 | struct super_block *sb = dir->i_sb;
|
| 1325 | struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
| 1326 | struct buffer_head *bh, *prev, *bhs[3];
|
| 1327 | struct msdos_dir_entry *de;
|
| 1328 | int err, free_slots, i, nr_bhs;
|
| 1329 | loff_t pos;
|
| 1330 | bool saw_eod;
|
| 1331 |
|
| 1332 | sinfo->nr_slots = nr_slots;
|
| 1333 |
|
| 1334 |
|
| 1335 | free_slots = nr_bhs = 0;
|
| 1336 | bh = prev = NULL;
|
| 1337 | pos = 0;
|
| 1338 | err = -ENOSPC;
|
| 1339 | saw_eod = false;
|
| 1340 | while (fat_get_entry(dir, &pos, &bh, &de) > -1) {
|
| 1341 |
|
| 1342 | if (pos >= FAT_MAX_DIR_SIZE)
|
| 1343 | goto error;
|
| 1344 |
|
| 1345 | if (IS_FREE(de->name)) {
|
| 1346 | if (de->name[0] == 0)
|
| 1347 | saw_eod = true;
|
| 1348 | if (prev != bh) {
|
| 1349 | get_bh(bh);
|
| 1350 | bhs[nr_bhs] = prev = bh;
|
| 1351 | nr_bhs++;
|
| 1352 | }
|
| 1353 | free_slots++;
|
| 1354 | if (free_slots == nr_slots)
|
| 1355 | goto found;
|
| 1356 | } else {
|
| 1357 | if (saw_eod) {
|
| 1358 | fat_fs_error_ratelimit(sb,
|
| 1359 | "allocated dir entry found after end-of-directory marker (i_pos %lld)",
|
| 1360 | MSDOS_I(dir)->i_pos);
|
| 1361 | err = -EIO;
|
| 1362 | goto error;
|
| 1363 | }
|
| 1364 | for (i = 0; i < nr_bhs; i++)
|
| 1365 | brelse(bhs[i]);
|
| 1366 | prev = NULL;
|
| 1367 | free_slots = nr_bhs = 0;
|
| 1368 | }
|
| 1369 | }
|
| 1370 | if (dir->i_ino == MSDOS_ROOT_INO) {
|
| 1371 | if (!is_fat32(sbi))
|
| 1372 | goto error;
|
| 1373 | } else if (MSDOS_I(dir)->i_start == 0) {
|
| 1374 | fat_msg(sb, KERN_ERR, "Corrupted directory (i_pos %lld)",
|
| 1375 | MSDOS_I(dir)->i_pos);
|
| 1376 | err = -EIO;
|
| 1377 | goto error;
|
| 1378 | }
|
| 1379 |
|
| 1380 | found:
|
| 1381 | err = 0;
|
| 1382 | pos -= free_slots * sizeof(*de);
|
| 1383 | nr_slots -= free_slots;
|
| 1384 | if (free_slots) {
|
| 1385 | |
| 1386 | * Second stage: filling the free entries with new entries.
|
| 1387 | * NOTE: If this slots has shortname, first, we write
|
| 1388 | * the long name slots, then write the short name.
|
| 1389 |
|
| 1390 | int size = free_slots * sizeof(*de);
|
| 1391 | int offset = pos & (sb->s_blocksize - 1);
|
| 1392 | int long_bhs = nr_bhs - (nr_slots == 0);
|
| 1393 |
|
| 1394 |
|
| 1395 | for (i = 0; i < long_bhs; i++) {
|
| 1396 | int copy = umin(sb->s_blocksize - offset, size);
|
| 1397 | memcpy(bhs[i]->b_data + offset, slots, copy);
|
| 1398 | mmb_mark_buffer_dirty(bhs[i],
|
| 1399 | &MSDOS_I(dir)->i_metadata_bhs);
|
| 1400 | offset = 0;
|
| 1401 | slots += copy;
|
| 1402 | size -= copy;
|
| 1403 | }
|
| 1404 | if (long_bhs && IS_DIRSYNC(dir))
|
| 1405 | err = fat_sync_bhs(bhs, long_bhs);
|
| 1406 | if (!err && i < nr_bhs) {
|
| 1407 |
|
| 1408 | int copy = umin(sb->s_blocksize - offset, size);
|
| 1409 | memcpy(bhs[i]->b_data + offset, slots, copy);
|
| 1410 | mmb_mark_buffer_dirty(bhs[i],
|
| 1411 | &MSDOS_I(dir)->i_metadata_bhs);
|
| 1412 | if (IS_DIRSYNC(dir))
|
| 1413 | err = sync_dirty_buffer(bhs[i]);
|
| 1414 | }
|
| 1415 | for (i = 0; i < nr_bhs; i++)
|
| 1416 | brelse(bhs[i]);
|
| 1417 | if (err)
|
| 1418 | goto error_remove;
|
| 1419 | }
|
| 1420 |
|
| 1421 | if (nr_slots) {
|
| 1422 | int cluster, nr_cluster;
|
| 1423 |
|
| 1424 | |
| 1425 | * Third stage: allocate the cluster for new entries.
|
| 1426 | * And initialize the cluster with new entries, then
|
| 1427 | * add the cluster to dir.
|
| 1428 |
|
| 1429 | cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster,
|
| 1430 | &de, &bh);
|
| 1431 | if (cluster < 0) {
|
| 1432 | err = cluster;
|
| 1433 | goto error_remove;
|
| 1434 | }
|
| 1435 | err = fat_chain_add(dir, cluster, nr_cluster);
|
| 1436 | if (err) {
|
| 1437 | fat_free_clusters(dir, cluster);
|
| 1438 | goto error_remove;
|
| 1439 | }
|
| 1440 | if (dir->i_size & (sbi->cluster_size - 1)) {
|
| 1441 | fat_fs_error(sb, "Odd directory size");
|
| 1442 | dir->i_size = (dir->i_size + sbi->cluster_size - 1)
|
| 1443 | & ~((loff_t)sbi->cluster_size - 1);
|
| 1444 | }
|
| 1445 | dir->i_size += nr_cluster << sbi->cluster_bits;
|
| 1446 | MSDOS_I(dir)->mmu_private += nr_cluster << sbi->cluster_bits;
|
| 1447 | }
|
| 1448 | sinfo->slot_off = pos;
|
| 1449 | sinfo->de = de;
|
| 1450 | sinfo->bh = bh;
|
| 1451 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
|
| 1452 |
|
| 1453 | return 0;
|
| 1454 |
|
| 1455 | error:
|
| 1456 | brelse(bh);
|
| 1457 | for (i = 0; i < nr_bhs; i++)
|
| 1458 | brelse(bhs[i]);
|
| 1459 | return err;
|
| 1460 |
|
| 1461 | error_remove:
|
| 1462 | brelse(bh);
|
| 1463 | if (free_slots)
|
| 1464 | __fat_remove_entries(dir, pos, free_slots);
|
| 1465 | return err;
|
| 1466 | }
|
| 1467 | EXPORT_SYMBOL_GPL(fat_add_entries);
|