18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/hpfs/name.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * operations with filenames 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "hpfs_fn.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic inline int not_allowed_char(unsigned char c) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci return c<' ' || c=='"' || c=='*' || c=='/' || c==':' || c=='<' || 158c2ecf20Sopenharmony_ci c=='>' || c=='?' || c=='\\' || c=='|'; 168c2ecf20Sopenharmony_ci} 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic inline int no_dos_char(unsigned char c) 198c2ecf20Sopenharmony_ci{ /* Characters that are allowed in HPFS but not in DOS */ 208c2ecf20Sopenharmony_ci return c=='+' || c==',' || c==';' || c=='=' || c=='[' || c==']'; 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic inline unsigned char upcase(unsigned char *dir, unsigned char a) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (a<128 || a==255) return a>='a' && a<='z' ? a - 0x20 : a; 268c2ecf20Sopenharmony_ci if (!dir) return a; 278c2ecf20Sopenharmony_ci return dir[a-128]; 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciunsigned char hpfs_upcase(unsigned char *dir, unsigned char a) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci return upcase(dir, a); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic inline unsigned char locase(unsigned char *dir, unsigned char a) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci if (a<128 || a==255) return a>='A' && a<='Z' ? a + 0x20 : a; 388c2ecf20Sopenharmony_ci if (!dir) return a; 398c2ecf20Sopenharmony_ci return dir[a]; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ciint hpfs_chk_name(const unsigned char *name, unsigned *len) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int i; 458c2ecf20Sopenharmony_ci if (*len > 254) return -ENAMETOOLONG; 468c2ecf20Sopenharmony_ci hpfs_adjust_length(name, len); 478c2ecf20Sopenharmony_ci if (!*len) return -EINVAL; 488c2ecf20Sopenharmony_ci for (i = 0; i < *len; i++) if (not_allowed_char(name[i])) return -EINVAL; 498c2ecf20Sopenharmony_ci if (*len == 1) if (name[0] == '.') return -EINVAL; 508c2ecf20Sopenharmony_ci if (*len == 2) if (name[0] == '.' && name[1] == '.') return -EINVAL; 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciunsigned char *hpfs_translate_name(struct super_block *s, unsigned char *from, 558c2ecf20Sopenharmony_ci unsigned len, int lc, int lng) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci unsigned char *to; 588c2ecf20Sopenharmony_ci int i; 598c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk >= 2) if (hpfs_is_name_long(from, len) != lng) { 608c2ecf20Sopenharmony_ci pr_err("Long name flag mismatch - name "); 618c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 628c2ecf20Sopenharmony_ci pr_cont("%c", from[i]); 638c2ecf20Sopenharmony_ci pr_cont(" misidentified as %s.\n", lng ? "short" : "long"); 648c2ecf20Sopenharmony_ci pr_err("It's nothing serious. It could happen because of bug in OS/2.\nSet checks=normal to disable this message.\n"); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci if (!lc) return from; 678c2ecf20Sopenharmony_ci if (!(to = kmalloc(len, GFP_KERNEL))) { 688c2ecf20Sopenharmony_ci pr_err("can't allocate memory for name conversion buffer\n"); 698c2ecf20Sopenharmony_ci return from; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) to[i] = locase(hpfs_sb(s)->sb_cp_table,from[i]); 728c2ecf20Sopenharmony_ci return to; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciint hpfs_compare_names(struct super_block *s, 768c2ecf20Sopenharmony_ci const unsigned char *n1, unsigned l1, 778c2ecf20Sopenharmony_ci const unsigned char *n2, unsigned l2, int last) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci unsigned l = l1 < l2 ? l1 : l2; 808c2ecf20Sopenharmony_ci unsigned i; 818c2ecf20Sopenharmony_ci if (last) return -1; 828c2ecf20Sopenharmony_ci for (i = 0; i < l; i++) { 838c2ecf20Sopenharmony_ci unsigned char c1 = upcase(hpfs_sb(s)->sb_cp_table,n1[i]); 848c2ecf20Sopenharmony_ci unsigned char c2 = upcase(hpfs_sb(s)->sb_cp_table,n2[i]); 858c2ecf20Sopenharmony_ci if (c1 < c2) return -1; 868c2ecf20Sopenharmony_ci if (c1 > c2) return 1; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci if (l1 < l2) return -1; 898c2ecf20Sopenharmony_ci if (l1 > l2) return 1; 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciint hpfs_is_name_long(const unsigned char *name, unsigned len) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci int i,j; 968c2ecf20Sopenharmony_ci for (i = 0; i < len && name[i] != '.'; i++) 978c2ecf20Sopenharmony_ci if (no_dos_char(name[i])) return 1; 988c2ecf20Sopenharmony_ci if (!i || i > 8) return 1; 998c2ecf20Sopenharmony_ci if (i == len) return 0; 1008c2ecf20Sopenharmony_ci for (j = i + 1; j < len; j++) 1018c2ecf20Sopenharmony_ci if (name[j] == '.' || no_dos_char(name[i])) return 1; 1028c2ecf20Sopenharmony_ci return j - i > 4; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* OS/2 clears dots and spaces at the end of file name, so we have to */ 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_civoid hpfs_adjust_length(const unsigned char *name, unsigned *len) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci if (!*len) return; 1108c2ecf20Sopenharmony_ci if (*len == 1 && name[0] == '.') return; 1118c2ecf20Sopenharmony_ci if (*len == 2 && name[0] == '.' && name[1] == '.') return; 1128c2ecf20Sopenharmony_ci while (*len && (name[*len - 1] == '.' || name[*len - 1] == ' ')) 1138c2ecf20Sopenharmony_ci (*len)--; 1148c2ecf20Sopenharmony_ci} 115