1/* 2 Unix SMB/CIFS implementation. 3 filename handling routines 4 Copyright (C) Andrew Tridgell 1992-1998 5 Copyright (C) Jeremy Allison 1999-2004 6 Copyright (C) Ying Chen 2000 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23/* 24 * New hash table stat cache code added by Ying Chen. 25 */ 26 27#include "includes.h" 28 29static BOOL scan_directory(connection_struct *conn, const char *path, char *name,size_t maxlength); 30 31/**************************************************************************** 32 Check if two filenames are equal. 33 This needs to be careful about whether we are case sensitive. 34****************************************************************************/ 35 36static BOOL fname_equal(const char *name1, const char *name2, BOOL case_sensitive) 37{ 38 /* Normal filename handling */ 39 if (case_sensitive) 40 return(strcmp(name1,name2) == 0); 41 42 return(strequal(name1,name2)); 43} 44 45/**************************************************************************** 46 Mangle the 2nd name and check if it is then equal to the first name. 47****************************************************************************/ 48 49static BOOL mangled_equal(const char *name1, const char *name2, int snum) 50{ 51 pstring tmpname; 52 53 pstrcpy(tmpname, name2); 54 mangle_map(tmpname, True, False, snum); 55 return strequal(name1, tmpname); 56} 57 58/**************************************************************************** 59This routine is called to convert names from the dos namespace to unix 60namespace. It needs to handle any case conversions, mangling, format 61changes etc. 62 63We assume that we have already done a chdir() to the right "root" directory 64for this service. 65 66The function will return False if some part of the name except for the last 67part cannot be resolved 68 69If the saved_last_component != 0, then the unmodified last component 70of the pathname is returned there. This is used in an exceptional 71case in reply_mv (so far). If saved_last_component == 0 then nothing 72is returned there. 73 74The bad_path arg is set to True if the filename walk failed. This is 75used to pick the correct error code to return between ENOENT and ENOTDIR 76as Windows applications depend on ERRbadpath being returned if a component 77of a pathname does not exist. 78 79On exit from unix_convert, if *pst was not null, then the file stat 80struct will be returned if the file exists and was found, if not this 81stat struct will be filled with zeros (and this can be detected by checking 82for nlinks = 0, which can never be true for any file). 83****************************************************************************/ 84 85BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_component, 86 BOOL *bad_path, SMB_STRUCT_STAT *pst) 87{ 88 SMB_STRUCT_STAT st; 89 char *start, *end; 90 pstring dirpath; 91 pstring orig_path; 92 BOOL component_was_mangled = False; 93 BOOL name_has_wildcard = False; 94 95 ZERO_STRUCTP(pst); 96 97 *dirpath = 0; 98 *bad_path = False; 99 if(saved_last_component) 100 *saved_last_component = 0; 101 102 if (conn->printer) { 103 /* we don't ever use the filenames on a printer share as a 104 filename - so don't convert them */ 105 return True; 106 } 107 108 DEBUG(5, ("unix_convert called on file \"%s\"\n", name)); 109 110 /* 111 * Conversion to basic unix format is already done in check_path_syntax(). 112 */ 113 114 /* 115 * Names must be relative to the root of the service - any leading /. 116 * and trailing /'s should have been trimmed by check_path_syntax(). 117 */ 118 119#ifdef DEVELOPER 120 SMB_ASSERT(*name != '/'); 121#endif 122 123 /* 124 * If we trimmed down to a single '\0' character 125 * then we should use the "." directory to avoid 126 * searching the cache, but not if we are in a 127 * printing share. 128 * As we know this is valid we can return true here. 129 */ 130 131 if (!*name) { 132 name[0] = '.'; 133 name[1] = '\0'; 134 if (SMB_VFS_STAT(conn,name,&st) == 0) { 135 *pst = st; 136 } 137 DEBUG(5,("conversion finished \"\" -> %s\n",name)); 138 return(True); 139 } 140 141 /* 142 * Ensure saved_last_component is valid even if file exists. 143 */ 144 145 if(saved_last_component) { 146 end = strrchr_m(name, '/'); 147 if(end) 148 pstrcpy(saved_last_component, end + 1); 149 else 150 pstrcpy(saved_last_component, name); 151 } 152 153 if (!conn->case_preserve || (mangle_is_8_3(name, False) && !conn->short_case_preserve)) 154 strnorm(name, lp_defaultcase(SNUM(conn))); 155 156 start = name; 157 pstrcpy(orig_path, name); 158 159 if(!conn->case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) { 160 *pst = st; 161 return True; 162 } 163 164 /* 165 * stat the name - if it exists then we are all done! 166 */ 167 168 if (SMB_VFS_STAT(conn,name,&st) == 0) { 169 stat_cache_add(orig_path, name, conn->case_sensitive); 170 DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); 171 *pst = st; 172 return(True); 173 } 174 175 DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start)); 176 177 /* 178 * A special case - if we don't have any mangling chars and are case 179 * sensitive then searching won't help. 180 */ 181 182 if (conn->case_sensitive && !mangle_is_mangled(name) && !*lp_mangled_map(SNUM(conn))) 183 return(False); 184 185 name_has_wildcard = ms_has_wild(start); 186 187 /* 188 * is_mangled() was changed to look at an entire pathname, not 189 * just a component. JRA. 190 */ 191 192 if (mangle_is_mangled(start)) 193 component_was_mangled = True; 194 195 /* 196 * Now we need to recursively match the name against the real 197 * directory structure. 198 */ 199 200 /* 201 * Match each part of the path name separately, trying the names 202 * as is first, then trying to scan the directory for matching names. 203 */ 204 205 for (; start ; start = (end?end+1:(char *)NULL)) { 206 /* 207 * Pinpoint the end of this section of the filename. 208 */ 209 end = strchr_m(start, '/'); 210 211 /* 212 * Chop the name at this point. 213 */ 214 if (end) 215 *end = 0; 216 217 if(saved_last_component != 0) 218 pstrcpy(saved_last_component, end ? end + 1 : start); 219 220 /* 221 * Check if the name exists up to this point. 222 */ 223 224 if (SMB_VFS_STAT(conn,name, &st) == 0) { 225 /* 226 * It exists. it must either be a directory or this must be 227 * the last part of the path for it to be OK. 228 */ 229 if (end && !(st.st_mode & S_IFDIR)) { 230 /* 231 * An intermediate part of the name isn't a directory. 232 */ 233 DEBUG(5,("Not a dir %s\n",start)); 234 *end = '/'; 235 /* 236 * We need to return the fact that the intermediate 237 * name resolution failed. This is used to return an 238 * error of ERRbadpath rather than ERRbadfile. Some 239 * Windows applications depend on the difference between 240 * these two errors. 241 */ 242 errno = ENOTDIR; 243 *bad_path = True; 244 return(False); 245 } 246 247 if (!end) { 248 /* 249 * We just scanned for, and found the end of the path. 250 * We must return the valid stat struct. 251 * JRA. 252 */ 253 254 *pst = st; 255 } 256 257 } else { 258 pstring rest; 259 260 /* Stat failed - ensure we don't use it. */ 261 ZERO_STRUCT(st); 262 *rest = 0; 263 264 /* 265 * Remember the rest of the pathname so it can be restored 266 * later. 267 */ 268 269 if (end) 270 pstrcpy(rest,end+1); 271 272 /* Reset errno so we can detect directory open errors. */ 273 errno = 0; 274 275 /* 276 * Try to find this part of the path in the directory. 277 */ 278 279 if (ms_has_wild(start) || 280 !scan_directory(conn, dirpath, start, sizeof(pstring) - 1 - (start - name))) { 281 if (end) { 282 /* 283 * An intermediate part of the name can't be found. 284 */ 285 DEBUG(5,("Intermediate not found %s\n",start)); 286 *end = '/'; 287 288 /* 289 * We need to return the fact that the intermediate 290 * name resolution failed. This is used to return an 291 * error of ERRbadpath rather than ERRbadfile. Some 292 * Windows applications depend on the difference between 293 * these two errors. 294 */ 295 *bad_path = True; 296 return(False); 297 } 298 299 if (errno == ENOTDIR) { 300 *bad_path = True; 301 return(False); 302 } 303 304 /* 305 * Just the last part of the name doesn't exist. 306 * We may need to strupper() or strlower() it in case 307 * this conversion is being used for file creation 308 * purposes. If the filename is of mixed case then 309 * don't normalise it. 310 */ 311 312 if (!conn->case_preserve && (!strhasupper(start) || !strhaslower(start))) 313 strnorm(start, lp_defaultcase(SNUM(conn))); 314 315 /* 316 * check on the mangled stack to see if we can recover the 317 * base of the filename. 318 */ 319 320 if (mangle_is_mangled(start)) { 321 mangle_check_cache( start, sizeof(pstring) - 1 - (start - name) ); 322 } 323 324 DEBUG(5,("New file %s\n",start)); 325 return(True); 326 } 327 328 /* 329 * Restore the rest of the string. If the string was mangled the size 330 * may have changed. 331 */ 332 if (end) { 333 end = start + strlen(start); 334 if (!safe_strcat(start, "/", sizeof(pstring) - 1 - (start - name)) || 335 !safe_strcat(start, rest, sizeof(pstring) - 1 - (start - name))) { 336 return False; 337 } 338 *end = '\0'; 339 } else { 340 /* 341 * We just scanned for, and found the end of the path. 342 * We must return a valid stat struct if it exists. 343 * JRA. 344 */ 345 346 if (SMB_VFS_STAT(conn,name, &st) == 0) { 347 *pst = st; 348 } else { 349 ZERO_STRUCT(st); 350 } 351 } 352 } /* end else */ 353 354 /* 355 * Add to the dirpath that we have resolved so far. 356 */ 357 if (*dirpath) 358 pstrcat(dirpath,"/"); 359 360 pstrcat(dirpath,start); 361 362 /* 363 * Don't cache a name with mangled or wildcard components 364 * as this can change the size. 365 */ 366 367 if(!component_was_mangled && !name_has_wildcard) 368 stat_cache_add(orig_path, dirpath, conn->case_sensitive); 369 370 /* 371 * Restore the / that we wiped out earlier. 372 */ 373 if (end) 374 *end = '/'; 375 } 376 377 /* 378 * Don't cache a name with mangled or wildcard components 379 * as this can change the size. 380 */ 381 382 if(!component_was_mangled && !name_has_wildcard) 383 stat_cache_add(orig_path, name, conn->case_sensitive); 384 385 /* 386 * The name has been resolved. 387 */ 388 389 DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); 390 return(True); 391} 392 393/**************************************************************************** 394 Check a filename - possibly caling reducename. 395 This is called by every routine before it allows an operation on a filename. 396 It does any final confirmation necessary to ensure that the filename is 397 a valid one for the user to access. 398****************************************************************************/ 399 400BOOL check_name(pstring name,connection_struct *conn) 401{ 402 BOOL ret = True; 403 404 if (IS_VETO_PATH(conn, name)) { 405 /* Is it not dot or dot dot. */ 406 if (!((name[0] == '.') && (!name[1] || (name[1] == '.' && !name[2])))) { 407 DEBUG(5,("file path name %s vetoed\n",name)); 408 errno = ENOENT; 409 return False; 410 } 411 } 412 413 if (!lp_widelinks(SNUM(conn)) || !lp_symlinks(SNUM(conn))) { 414 ret = reduce_name(conn,name); 415 } 416 417 if (!ret) { 418 DEBUG(5,("check_name on %s failed\n",name)); 419 } 420 421 return(ret); 422} 423 424/**************************************************************************** 425 Scan a directory to find a filename, matching without case sensitivity. 426 If the name looks like a mangled name then try via the mangling functions 427****************************************************************************/ 428 429static BOOL scan_directory(connection_struct *conn, const char *path, char *name, size_t maxlength) 430{ 431 struct smb_Dir *cur_dir; 432 const char *dname; 433 BOOL mangled; 434 long curpos; 435 436 mangled = mangle_is_mangled(name); 437 438 /* handle null paths */ 439 if (*path == 0) 440 path = "."; 441 442 /* 443 * The incoming name can be mangled, and if we de-mangle it 444 * here it will not compare correctly against the filename (name2) 445 * read from the directory and then mangled by the mangle_map() 446 * call. We need to mangle both names or neither. 447 * (JRA). 448 */ 449 if (mangled) 450 mangled = !mangle_check_cache( name, maxlength ); 451 452 /* open the directory */ 453 if (!(cur_dir = OpenDir(conn, path))) { 454 DEBUG(3,("scan dir didn't open dir [%s]\n",path)); 455 return(False); 456 } 457 458 /* now scan for matching names */ 459 curpos = 0; 460 while ((dname = ReadDirName(cur_dir, &curpos))) { 461 462 /* Is it dot or dot dot. */ 463 if ((dname[0] == '.') && (!dname[1] || (dname[1] == '.' && !dname[2]))) { 464 continue; 465 } 466 467 /* 468 * At this point dname is the unmangled name. 469 * name is either mangled or not, depending on the state of the "mangled" 470 * variable. JRA. 471 */ 472 473 /* 474 * Check mangled name against mangled name, or unmangled name 475 * against unmangled name. 476 */ 477 478 if ((mangled && mangled_equal(name,dname,SNUM(conn))) || fname_equal(name, dname, conn->case_sensitive)) { 479 /* we've found the file, change it's name and return */ 480 safe_strcpy(name, dname, maxlength); 481 CloseDir(cur_dir); 482 return(True); 483 } 484 } 485 486 CloseDir(cur_dir); 487 errno = ENOENT; 488 return(False); 489} 490