00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #include "includes.h"
00055
00056 #if 1
00057 #define M_DEBUG(level, x) DEBUG(level, x)
00058 #else
00059 #define M_DEBUG(level, x)
00060 #endif
00061
00062
00063
00064 #define FLAG_BASECHAR 1
00065 #define FLAG_ASCII 2
00066 #define FLAG_ILLEGAL 4
00067 #define FLAG_WILDCARD 8
00068
00069
00070
00071 #define FLAG_POSSIBLE1 16
00072 #define FLAG_POSSIBLE2 32
00073 #define FLAG_POSSIBLE3 64
00074 #define FLAG_POSSIBLE4 128
00075
00076
00077 #ifndef MANGLE_CACHE_SIZE
00078 #define MANGLE_CACHE_SIZE 4096
00079 #endif
00080
00081 #define FNV1_PRIME 0x01000193
00082
00083 #define FNV1_INIT 0xa6b93095
00084
00085
00086 static unsigned char char_flags[256];
00087
00088 #define FLAG_CHECK(c, flag) (char_flags[(unsigned char)(c)] & (flag))
00089
00090
00091
00092
00093
00094
00095 static unsigned mangle_prefix;
00096
00097
00098
00099
00100
00101
00102
00103 static char **prefix_cache;
00104 static unsigned int *prefix_cache_hashes;
00105
00106
00107 static const char *basechars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
00108 static unsigned char base_reverse[256];
00109 #define base_forward(v) basechars[v]
00110
00111
00112 static const char *reserved_names[] =
00113 { "AUX", "LOCK$", "CON", "COM1", "COM2", "COM3", "COM4",
00114 "LPT1", "LPT2", "LPT3", "NUL", "PRN", NULL };
00115
00116
00117
00118
00119
00120
00121
00122 static unsigned int mangle_hash(const char *key, unsigned int length)
00123 {
00124 unsigned int value;
00125 unsigned int i;
00126 fstring str;
00127
00128
00129
00130
00131
00132 length = MIN(length,sizeof(fstring)-1);
00133 strncpy(str, key, length);
00134 str[length] = 0;
00135 strupper_m(str);
00136
00137
00138 length = strlen(str);
00139
00140
00141 for (value = FNV1_INIT, i=0; i < length; i++) {
00142 value *= (unsigned int)FNV1_PRIME;
00143 value ^= (unsigned int)(str[i]);
00144 }
00145
00146
00147
00148 return value & ~0x80000000;
00149 }
00150
00151
00152
00153
00154 static BOOL cache_init(void)
00155 {
00156 if (prefix_cache) {
00157 return True;
00158 }
00159
00160 prefix_cache = SMB_CALLOC_ARRAY(char *,MANGLE_CACHE_SIZE);
00161 if (!prefix_cache) {
00162 return False;
00163 }
00164
00165 prefix_cache_hashes = SMB_CALLOC_ARRAY(unsigned int, MANGLE_CACHE_SIZE);
00166 if (!prefix_cache_hashes) {
00167 return False;
00168 }
00169
00170 return True;
00171 }
00172
00173
00174
00175
00176 static void cache_insert(const char *prefix, int length, unsigned int hash)
00177 {
00178 int i = hash % MANGLE_CACHE_SIZE;
00179
00180 if (prefix_cache[i]) {
00181 free(prefix_cache[i]);
00182 }
00183
00184 prefix_cache[i] = SMB_STRNDUP(prefix, length);
00185 prefix_cache_hashes[i] = hash;
00186 }
00187
00188
00189
00190
00191 static const char *cache_lookup(unsigned int hash)
00192 {
00193 int i = hash % MANGLE_CACHE_SIZE;
00194
00195 if (!prefix_cache[i] || hash != prefix_cache_hashes[i]) {
00196 return NULL;
00197 }
00198
00199
00200 return prefix_cache[i];
00201 }
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 static BOOL is_mangled_component(const char *name, size_t len)
00212 {
00213 unsigned int i;
00214
00215 M_DEBUG(10,("is_mangled_component %s (len %lu) ?\n", name, (unsigned long)len));
00216
00217
00218 if (len > 12 || len < 8)
00219 return False;
00220
00221
00222 if (name[6] != '~')
00223 return False;
00224
00225
00226 if (len > 8) {
00227 if (name[8] != '.')
00228 return False;
00229 for (i=9; name[i] && i < len; i++) {
00230 if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
00231 return False;
00232 }
00233 }
00234 }
00235
00236
00237 for (i=0;i<mangle_prefix;i++) {
00238 if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
00239 return False;
00240 }
00241 }
00242
00243
00244 if (! FLAG_CHECK(name[7], FLAG_BASECHAR)) {
00245 return False;
00246 }
00247 for (i=mangle_prefix;i<6;i++) {
00248 if (! FLAG_CHECK(name[i], FLAG_BASECHAR)) {
00249 return False;
00250 }
00251 }
00252
00253 M_DEBUG(10,("is_mangled_component %s (len %lu) -> yes\n", name, (unsigned long)len));
00254
00255 return True;
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 static BOOL is_mangled(const char *name, const struct share_params *parm)
00272 {
00273 const char *p;
00274 const char *s;
00275
00276 M_DEBUG(10,("is_mangled %s ?\n", name));
00277
00278 for (s=name; (p=strchr(s, '/')); s=p+1) {
00279 if (is_mangled_component(s, PTR_DIFF(p, s))) {
00280 return True;
00281 }
00282 }
00283
00284
00285 return is_mangled_component(s,strlen(s));
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 static BOOL is_8_3(const char *name, BOOL check_case, BOOL allow_wildcards, const struct share_params *p)
00297 {
00298 int len, i;
00299 char *dot_p;
00300
00301
00302 if (name[0] == '.') {
00303 if (!name[1] || (name[1] == '.' && !name[2])) {
00304 return True;
00305 }
00306 }
00307
00308
00309
00310
00311
00312
00313 len = strlen(name);
00314 if (len > 12)
00315 return False;
00316
00317
00318
00319 dot_p = strchr(name, '.');
00320
00321 if (!dot_p) {
00322
00323
00324 if (len > 8) {
00325 return False;
00326 }
00327 } else {
00328 int prefix_len, suffix_len;
00329
00330
00331
00332 prefix_len = PTR_DIFF(dot_p, name);
00333 suffix_len = len - (prefix_len+1);
00334
00335 if (prefix_len > 8 || suffix_len > 3 || suffix_len == 0) {
00336 return False;
00337 }
00338
00339
00340 if (strchr(dot_p+1, '.')) {
00341 return False;
00342 }
00343 }
00344
00345
00346 for (i=0; name[i]; i++) {
00347
00348 if (!FLAG_CHECK(name[i], FLAG_ASCII|(allow_wildcards ? FLAG_WILDCARD : 0)) && name[i] != '.') {
00349 return False;
00350 }
00351 }
00352
00353
00354 return True;
00355 }
00356
00357
00358
00359
00360
00361
00362
00363 static void mangle_reset(void)
00364 {
00365
00366 }
00367
00368
00369
00370
00371
00372
00373 static BOOL check_cache(char *name, size_t maxlen, const struct share_params *p)
00374 {
00375 unsigned int hash, multiplier;
00376 unsigned int i;
00377 const char *prefix;
00378 char extension[4];
00379
00380
00381 if (!is_mangled(name, p)) {
00382 M_DEBUG(10,("check_cache: %s -> not mangled\n", name));
00383 return False;
00384 }
00385
00386
00387 hash = base_reverse[(unsigned char)name[7]];
00388 for (multiplier=36, i=5;i>=mangle_prefix;i--) {
00389 unsigned int v = base_reverse[(unsigned char)name[i]];
00390 hash += multiplier * v;
00391 multiplier *= 36;
00392 }
00393
00394
00395 prefix = cache_lookup(hash);
00396 if (!prefix) {
00397 M_DEBUG(10,("check_cache: %s -> %08X -> not found\n", name, hash));
00398 return False;
00399 }
00400
00401
00402 if (name[8] == '.') {
00403 strncpy(extension, name+9, 3);
00404 extension[3] = 0;
00405 } else {
00406 extension[0] = 0;
00407 }
00408
00409 if (extension[0]) {
00410 M_DEBUG(10,("check_cache: %s -> %s.%s\n", name, prefix, extension));
00411 slprintf(name, maxlen, "%s.%s", prefix, extension);
00412 } else {
00413 M_DEBUG(10,("check_cache: %s -> %s\n", name, prefix));
00414 safe_strcpy(name, prefix, maxlen);
00415 }
00416
00417 return True;
00418 }
00419
00420
00421
00422
00423
00424 static BOOL is_reserved_name(const char *name)
00425 {
00426 if (FLAG_CHECK(name[0], FLAG_POSSIBLE1) &&
00427 FLAG_CHECK(name[1], FLAG_POSSIBLE2) &&
00428 FLAG_CHECK(name[2], FLAG_POSSIBLE3) &&
00429 FLAG_CHECK(name[3], FLAG_POSSIBLE4)) {
00430
00431 int i;
00432 for (i=0; reserved_names[i]; i++) {
00433 int len = strlen(reserved_names[i]);
00434
00435 if (strnequal(name, reserved_names[i], len) &&
00436 (name[len] == '.' || name[len] == 0)) {
00437 return True;
00438 }
00439 }
00440 }
00441
00442 return False;
00443 }
00444
00445
00446
00447
00448
00449
00450
00451 static BOOL is_legal_name(const char *name)
00452 {
00453 const char *dot_pos = NULL;
00454 BOOL alldots = True;
00455 size_t numdots = 0;
00456
00457 while (*name) {
00458 if (((unsigned int)name[0]) > 128 && (name[1] != 0)) {
00459
00460 char mbc[2];
00461
00462
00463
00464
00465
00466
00467
00468 if (convert_string(CH_UNIX, CH_UTF16LE, name, 2, mbc, 2, False) == 2) {
00469
00470 name += 2;
00471 continue;
00472 }
00473 }
00474
00475 if (FLAG_CHECK(name[0], FLAG_ILLEGAL)) {
00476 return False;
00477 }
00478 if (name[0] == '.') {
00479 dot_pos = name;
00480 numdots++;
00481 } else {
00482 alldots = False;
00483 }
00484 if ((name[0] == ' ') && (name[1] == '\0')) {
00485
00486 return False;
00487 }
00488 name++;
00489 }
00490
00491 if (dot_pos) {
00492 if (alldots && (numdots == 1 || numdots == 2))
00493 return True;
00494
00495
00496 if (dot_pos[1] == '\0')
00497 return False;
00498 }
00499 return True;
00500 }
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case, const struct share_params *p)
00514 {
00515 char *dot_p;
00516 char lead_chars[7];
00517 char extension[4];
00518 unsigned int extension_length, i;
00519 unsigned int prefix_len;
00520 unsigned int hash, v;
00521 char new_name[13];
00522
00523
00524 if (!is_reserved_name(name)) {
00525
00526
00527 if (is_8_3(name, False, False, p)) {
00528 return;
00529 }
00530
00531
00532
00533 if (!need83 && is_legal_name(name)) {
00534 return;
00535 }
00536 }
00537
00538
00539 dot_p = strrchr(name, '.');
00540
00541 if (dot_p) {
00542
00543
00544
00545 for (i=0; i<4 && dot_p[i+1]; i++) {
00546 if (! FLAG_CHECK(dot_p[i+1], FLAG_ASCII)) {
00547 dot_p = NULL;
00548 break;
00549 }
00550 }
00551 if (i == 0 || i == 4) dot_p = NULL;
00552 }
00553
00554
00555
00556
00557
00558 for (i=0;i<mangle_prefix && name[i];i++) {
00559 lead_chars[i] = name[i];
00560 if (! FLAG_CHECK(lead_chars[i], FLAG_ASCII)) {
00561 lead_chars[i] = '_';
00562 }
00563 lead_chars[i] = toupper_ascii(lead_chars[i]);
00564 }
00565 for (;i<mangle_prefix;i++) {
00566 lead_chars[i] = '_';
00567 }
00568
00569
00570 if (dot_p) {
00571 prefix_len = PTR_DIFF(dot_p, name);
00572 } else {
00573 prefix_len = strlen(name);
00574 }
00575
00576
00577
00578 extension_length = 0;
00579 if (dot_p) {
00580 for (i=1; extension_length < 3 && dot_p[i]; i++) {
00581 char c = dot_p[i];
00582 if (FLAG_CHECK(c, FLAG_ASCII)) {
00583 extension[extension_length++] = toupper_ascii(c);
00584 }
00585 }
00586 }
00587
00588
00589 v = hash = mangle_hash(name, prefix_len);
00590
00591
00592 for (i=0;i<mangle_prefix;i++) {
00593 new_name[i] = lead_chars[i];
00594 }
00595 new_name[7] = base_forward(v % 36);
00596 new_name[6] = '~';
00597 for (i=5; i>=mangle_prefix; i--) {
00598 v = v / 36;
00599 new_name[i] = base_forward(v % 36);
00600 }
00601
00602
00603 if (extension_length) {
00604 new_name[8] = '.';
00605 memcpy(&new_name[9], extension, extension_length);
00606 new_name[9+extension_length] = 0;
00607 } else {
00608 new_name[8] = 0;
00609 }
00610
00611 if (cache83) {
00612
00613 cache_insert(name, prefix_len, hash);
00614 }
00615
00616 M_DEBUG(10,("name_map: %s -> %08X -> %s (cache=%d)\n",
00617 name, hash, new_name, cache83));
00618
00619
00620 fstrcpy(name, new_name);
00621
00622
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 static void init_tables(void)
00634 {
00635 int i;
00636
00637 memset(char_flags, 0, sizeof(char_flags));
00638
00639 for (i=1;i<128;i++) {
00640 if (i <= 0x1f) {
00641
00642 char_flags[i] |= FLAG_ILLEGAL;
00643 }
00644
00645 if ((i >= '0' && i <= '9') ||
00646 (i >= 'a' && i <= 'z') ||
00647 (i >= 'A' && i <= 'Z')) {
00648 char_flags[i] |= (FLAG_ASCII | FLAG_BASECHAR);
00649 }
00650 if (strchr("_-$~", i)) {
00651 char_flags[i] |= FLAG_ASCII;
00652 }
00653
00654 if (strchr("*\\/?<>|\":", i)) {
00655 char_flags[i] |= FLAG_ILLEGAL;
00656 }
00657
00658 if (strchr("*?\"<>", i)) {
00659 char_flags[i] |= FLAG_WILDCARD;
00660 }
00661 }
00662
00663 memset(base_reverse, 0, sizeof(base_reverse));
00664 for (i=0;i<36;i++) {
00665 base_reverse[(unsigned char)base_forward(i)] = i;
00666 }
00667
00668
00669
00670 for (i=0; reserved_names[i]; i++) {
00671 unsigned char c1, c2, c3, c4;
00672
00673 c1 = (unsigned char)reserved_names[i][0];
00674 c2 = (unsigned char)reserved_names[i][1];
00675 c3 = (unsigned char)reserved_names[i][2];
00676 c4 = (unsigned char)reserved_names[i][3];
00677
00678 char_flags[c1] |= FLAG_POSSIBLE1;
00679 char_flags[c2] |= FLAG_POSSIBLE2;
00680 char_flags[c3] |= FLAG_POSSIBLE3;
00681 char_flags[c4] |= FLAG_POSSIBLE4;
00682 char_flags[tolower_ascii(c1)] |= FLAG_POSSIBLE1;
00683 char_flags[tolower_ascii(c2)] |= FLAG_POSSIBLE2;
00684 char_flags[tolower_ascii(c3)] |= FLAG_POSSIBLE3;
00685 char_flags[tolower_ascii(c4)] |= FLAG_POSSIBLE4;
00686
00687 char_flags[(unsigned char)'.'] |= FLAG_POSSIBLE4;
00688 }
00689 }
00690
00691
00692
00693
00694 static struct mangle_fns mangle_fns = {
00695 mangle_reset,
00696 is_mangled,
00697 is_8_3,
00698 check_cache,
00699 name_map
00700 };
00701
00702
00703 struct mangle_fns *mangle_hash2_init(void)
00704 {
00705
00706 mangle_prefix = lp_mangle_prefix();
00707 if (mangle_prefix > 6) {
00708 mangle_prefix = 6;
00709 }
00710 if (mangle_prefix < 1) {
00711 mangle_prefix = 1;
00712 }
00713
00714 init_tables();
00715 mangle_reset();
00716
00717 if (!cache_init()) {
00718 return NULL;
00719 }
00720
00721 return &mangle_fns;
00722 }
00723
00724 static void posix_mangle_reset(void)
00725 {;}
00726
00727 static BOOL posix_is_mangled(const char *s, const struct share_params *p)
00728 {
00729 return False;
00730 }
00731
00732 static BOOL posix_is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards, const struct share_params *p)
00733 {
00734 return False;
00735 }
00736
00737 static BOOL posix_check_cache( char *s, size_t maxlen, const struct share_params *p )
00738 {
00739 return False;
00740 }
00741
00742 static void posix_name_map(char *OutName, BOOL need83, BOOL cache83, int default_case, const struct share_params *p)
00743 {
00744 if (need83) {
00745 memset(OutName, '\0', 13);
00746 }
00747 }
00748
00749
00750 static struct mangle_fns posix_mangle_fns = {
00751 posix_mangle_reset,
00752 posix_is_mangled,
00753 posix_is_8_3,
00754 posix_check_cache,
00755 posix_name_map
00756 };
00757
00758 struct mangle_fns *posix_mangle_init(void)
00759 {
00760 return &posix_mangle_fns;
00761 }