// SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/msdos/namei.c * * Written 1992,1993 by Werner Almesberger * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu> * Rewritten for constant inumbers 1999 by Al Viro
*/
/* Characters that are undesirable in an MS-DOS file name */ staticunsignedchar bad_chars[] = "*?<>|\""; staticunsignedchar bad_if_strict[] = "+=,; ";
/***** Formats an MS-DOS file name. Rejects invalid names. */ staticint msdos_format_name(constunsignedchar *name, int len, unsignedchar *res, struct fat_mount_options *opts) /* * name is the proposed name, len is its length, res is * the resulting name, opts->name_check is either (r)elaxed, * (n)ormal or (s)trict, opts->dotsOK allows dots at the * beginning of name (for hidden files)
*/
{ unsignedchar *walk; unsignedchar c; int space;
if (name[0] == '.') { /* dotfile because . and .. already done */ if (opts->dotsOK) { /* Get rid of dot - test for it elsewhere */
name++;
len--;
} else return -EINVAL;
} /* * disallow names that _really_ start with a dot
*/
space = 1;
c = 0; for (walk = res; len && walk - res < 8; walk++) {
c = *name++;
len--; if (opts->name_check != 'r' && strchr(bad_chars, c)) return -EINVAL; if (opts->name_check == 's' && strchr(bad_if_strict, c)) return -EINVAL; if (c >= 'A' && c <= 'Z' && opts->name_check == 's') return -EINVAL; if (c < ' ' || c == ':' || c == '\\') return -EINVAL; /* * 0xE5 is legal as a first character, but we must substitute * 0x05 because 0xE5 marks deleted files. Yes, DOS really * does this. * It seems that Microsoft hacked DOS to support non-US * characters after the 0xE5 character was already in use to * mark deleted files.
*/ if ((res == walk) && (c == 0xE5))
c = 0x05; if (c == '.') break;
space = (c == ' ');
*walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c;
} if (space) return -EINVAL; if (opts->name_check == 's' && len && c != '.') {
c = *name++;
len--; if (c != '.') return -EINVAL;
} while (c != '.' && len--)
c = *name++; if (c == '.') { while (walk - res < 8)
*walk++ = ' '; while (len > 0 && walk - res < MSDOS_NAME) {
c = *name++;
len--; if (opts->name_check != 'r' && strchr(bad_chars, c)) return -EINVAL; if (opts->name_check == 's' &&
strchr(bad_if_strict, c)) return -EINVAL; if (c < ' ' || c == ':' || c == '\\') return -EINVAL; if (c == '.') { if (opts->name_check == 's') return -EINVAL; break;
} if (c >= 'A' && c <= 'Z' && opts->name_check == 's') return -EINVAL;
space = c == ' '; if (!opts->nocase && c >= 'a' && c <= 'z')
*walk++ = c - 32; else
*walk++ = c;
} if (space) return -EINVAL; if (opts->name_check == 's' && len) return -EINVAL;
} while (walk - res < MSDOS_NAME)
*walk++ = ' ';
return 0;
}
/***** Locates a directory entry. Uses unformatted name. */ staticint msdos_find(struct inode *dir, constunsignedchar *name, int len, struct fat_slot_info *sinfo)
{ struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); unsignedchar msdos_name[MSDOS_NAME]; int err;
err = msdos_format_name(name, len, msdos_name, &sbi->options); if (err) return -ENOENT;
err = fat_scan(dir, msdos_name, sinfo); if (!err && sbi->options.dotsOK) { if (name[0] == '.') { if (!(sinfo->de->attr & ATTR_HIDDEN))
err = -ENOENT;
} else { if (sinfo->de->attr & ATTR_HIDDEN)
err = -ENOENT;
} if (err)
brelse(sinfo->bh);
} return err;
}
/* * Compute the hash for the msdos name corresponding to the dentry. * Note: if the name is invalid, we leave the hash code unchanged so * that the existing dentry can be used. The msdos fs routines will * return ENOENT or EINVAL as appropriate.
*/ staticint msdos_hash(conststruct dentry *dentry, struct qstr *qstr)
{ struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; unsignedchar msdos_name[MSDOS_NAME]; int error;
/* * Compare two msdos names. If either of the names are invalid, * we fall back to doing the standard name comparison.
*/ staticint msdos_cmp(conststruct dentry *dentry, unsignedint len, constchar *str, conststruct qstr *name)
{ struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; unsignedchar a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; int error;
err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
msdos_name, &MSDOS_SB(sb)->options); if (err) goto out;
is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.'); /* Have to do it due to foo vs. .foo conflicts */ if (!fat_scan(dir, msdos_name, &sinfo)) {
brelse(sinfo.bh);
err = -EINVAL; goto out;
}
ts = current_time(dir);
err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo); if (err) goto out;
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh); if (IS_ERR(inode)) {
err = PTR_ERR(inode); goto out;
}
fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME); /* timestamp is already written, so mark_inode_dirty() is unneeded. */
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh); if (IS_ERR(inode)) {
err = PTR_ERR(inode); /* the directory was completed, just return a error */ goto out;
}
set_nlink(inode, 2);
fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME); /* timestamp is already written, so mark_inode_dirty() is unneeded. */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.