162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/hpfs/name.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * operations with filenames 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "hpfs_fn.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic inline int not_allowed_char(unsigned char c) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci return c<' ' || c=='"' || c=='*' || c=='/' || c==':' || c=='<' || 1562306a36Sopenharmony_ci c=='>' || c=='?' || c=='\\' || c=='|'; 1662306a36Sopenharmony_ci} 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic inline int no_dos_char(unsigned char c) 1962306a36Sopenharmony_ci{ /* Characters that are allowed in HPFS but not in DOS */ 2062306a36Sopenharmony_ci return c=='+' || c==',' || c==';' || c=='=' || c=='[' || c==']'; 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic inline unsigned char upcase(unsigned char *dir, unsigned char a) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci if (a<128 || a==255) return a>='a' && a<='z' ? a - 0x20 : a; 2662306a36Sopenharmony_ci if (!dir) return a; 2762306a36Sopenharmony_ci return dir[a-128]; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciunsigned char hpfs_upcase(unsigned char *dir, unsigned char a) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci return upcase(dir, a); 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic inline unsigned char locase(unsigned char *dir, unsigned char a) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci if (a<128 || a==255) return a>='A' && a<='Z' ? a + 0x20 : a; 3862306a36Sopenharmony_ci if (!dir) return a; 3962306a36Sopenharmony_ci return dir[a]; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciint hpfs_chk_name(const unsigned char *name, unsigned *len) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci int i; 4562306a36Sopenharmony_ci if (*len > 254) return -ENAMETOOLONG; 4662306a36Sopenharmony_ci hpfs_adjust_length(name, len); 4762306a36Sopenharmony_ci if (!*len) return -EINVAL; 4862306a36Sopenharmony_ci for (i = 0; i < *len; i++) if (not_allowed_char(name[i])) return -EINVAL; 4962306a36Sopenharmony_ci if (*len == 1) if (name[0] == '.') return -EINVAL; 5062306a36Sopenharmony_ci if (*len == 2) if (name[0] == '.' && name[1] == '.') return -EINVAL; 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciunsigned char *hpfs_translate_name(struct super_block *s, unsigned char *from, 5562306a36Sopenharmony_ci unsigned len, int lc, int lng) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci unsigned char *to; 5862306a36Sopenharmony_ci int i; 5962306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk >= 2) if (hpfs_is_name_long(from, len) != lng) { 6062306a36Sopenharmony_ci pr_err("Long name flag mismatch - name "); 6162306a36Sopenharmony_ci for (i = 0; i < len; i++) 6262306a36Sopenharmony_ci pr_cont("%c", from[i]); 6362306a36Sopenharmony_ci pr_cont(" misidentified as %s.\n", lng ? "short" : "long"); 6462306a36Sopenharmony_ci pr_err("It's nothing serious. It could happen because of bug in OS/2.\nSet checks=normal to disable this message.\n"); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci if (!lc) return from; 6762306a36Sopenharmony_ci if (!(to = kmalloc(len, GFP_KERNEL))) { 6862306a36Sopenharmony_ci pr_err("can't allocate memory for name conversion buffer\n"); 6962306a36Sopenharmony_ci return from; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci for (i = 0; i < len; i++) to[i] = locase(hpfs_sb(s)->sb_cp_table,from[i]); 7262306a36Sopenharmony_ci return to; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciint hpfs_compare_names(struct super_block *s, 7662306a36Sopenharmony_ci const unsigned char *n1, unsigned l1, 7762306a36Sopenharmony_ci const unsigned char *n2, unsigned l2, int last) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci unsigned l = l1 < l2 ? l1 : l2; 8062306a36Sopenharmony_ci unsigned i; 8162306a36Sopenharmony_ci if (last) return -1; 8262306a36Sopenharmony_ci for (i = 0; i < l; i++) { 8362306a36Sopenharmony_ci unsigned char c1 = upcase(hpfs_sb(s)->sb_cp_table,n1[i]); 8462306a36Sopenharmony_ci unsigned char c2 = upcase(hpfs_sb(s)->sb_cp_table,n2[i]); 8562306a36Sopenharmony_ci if (c1 < c2) return -1; 8662306a36Sopenharmony_ci if (c1 > c2) return 1; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci if (l1 < l2) return -1; 8962306a36Sopenharmony_ci if (l1 > l2) return 1; 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ciint hpfs_is_name_long(const unsigned char *name, unsigned len) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci int i,j; 9662306a36Sopenharmony_ci for (i = 0; i < len && name[i] != '.'; i++) 9762306a36Sopenharmony_ci if (no_dos_char(name[i])) return 1; 9862306a36Sopenharmony_ci if (!i || i > 8) return 1; 9962306a36Sopenharmony_ci if (i == len) return 0; 10062306a36Sopenharmony_ci for (j = i + 1; j < len; j++) 10162306a36Sopenharmony_ci if (name[j] == '.' || no_dos_char(name[i])) return 1; 10262306a36Sopenharmony_ci return j - i > 4; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* OS/2 clears dots and spaces at the end of file name, so we have to */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_civoid hpfs_adjust_length(const unsigned char *name, unsigned *len) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci if (!*len) return; 11062306a36Sopenharmony_ci if (*len == 1 && name[0] == '.') return; 11162306a36Sopenharmony_ci if (*len == 2 && name[0] == '.' && name[1] == '.') return; 11262306a36Sopenharmony_ci while (*len && (name[*len - 1] == '.' || name[*len - 1] == ' ')) 11362306a36Sopenharmony_ci (*len)--; 11462306a36Sopenharmony_ci} 115