Example #1
0
static bool recursive_rmdir(TALLOC_CTX *ctx,
			connection_struct *conn,
			struct smb_filename *smb_dname)
{
	const char *dname = NULL;
	char *talloced = NULL;
	bool ret = True;
	long offset = 0;
	SMB_STRUCT_STAT st;
	struct smb_Dir *dir_hnd;

	SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));

	dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0);
	if(dir_hnd == NULL)
		return False;

	while((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) {
		struct smb_filename *smb_dname_full = NULL;
		char *fullname = NULL;
		bool do_break = true;
		NTSTATUS status;

		if (ISDOT(dname) || ISDOTDOT(dname)) {
			TALLOC_FREE(talloced);
			continue;
		}

		if (!is_visible_file(conn, smb_dname->base_name, dname, &st,
				     false)) {
			TALLOC_FREE(talloced);
			continue;
		}

		/* Construct the full name. */
		fullname = talloc_asprintf(ctx,
				"%s/%s",
				smb_dname->base_name,
				dname);
		if (!fullname) {
			errno = ENOMEM;
			goto err_break;
		}

		status = create_synthetic_smb_fname(talloc_tos(), fullname,
						    NULL, NULL,
						    &smb_dname_full);
		if (!NT_STATUS_IS_OK(status)) {
			goto err_break;
		}

		if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
			goto err_break;
		}

		if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
			if(!recursive_rmdir(ctx, conn, smb_dname_full)) {
				goto err_break;
			}
			if(SMB_VFS_RMDIR(conn,
					 smb_dname_full->base_name) != 0) {
				goto err_break;
			}
		} else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
			goto err_break;
		}

		/* Successful iteration. */
		do_break = false;

	 err_break:
		TALLOC_FREE(smb_dname_full);
		TALLOC_FREE(fullname);
		TALLOC_FREE(talloced);
		if (do_break) {
			ret = false;
			break;
		}
	}
	TALLOC_FREE(dir_hnd);
	return ret;
}
Example #2
0
static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
{
	connection_struct *conn = fsp->conn;
	struct smb_filename *smb_dname = fsp->fsp_name;
	int ret;

	SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));

	/* Might be a symlink. */
	if(SMB_VFS_LSTAT(conn, smb_dname) != 0) {
		return map_nt_error_from_unix(errno);
	}

	if (S_ISLNK(smb_dname->st.st_ex_mode)) {
		/* Is what it points to a directory ? */
		if(SMB_VFS_STAT(conn, smb_dname) != 0) {
			return map_nt_error_from_unix(errno);
		}
		if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
			return NT_STATUS_NOT_A_DIRECTORY;
		}
		ret = SMB_VFS_UNLINK(conn, smb_dname);
	} else {
		ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
	}
	if (ret == 0) {
		notify_fname(conn, NOTIFY_ACTION_REMOVED,
			     FILE_NOTIFY_CHANGE_DIR_NAME,
			     smb_dname->base_name);
		return NT_STATUS_OK;
	}

	if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
		/*
		 * Check to see if the only thing in this directory are
		 * vetoed files/directories. If so then delete them and
		 * retry. If we fail to delete any of them (and we *don't*
		 * do a recursive delete) then fail the rmdir.
		 */
		SMB_STRUCT_STAT st;
		const char *dname = NULL;
		char *talloced = NULL;
		long dirpos = 0;
		struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
						  smb_dname->base_name, NULL,
						  0);

		if(dir_hnd == NULL) {
			errno = ENOTEMPTY;
			goto err;
		}

		while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
					    &talloced)) != NULL) {
			if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) {
				TALLOC_FREE(talloced);
				continue;
			}
			if (!is_visible_file(conn, smb_dname->base_name, dname,
					     &st, false)) {
				TALLOC_FREE(talloced);
				continue;
			}
			if(!IS_VETO_PATH(conn, dname)) {
				TALLOC_FREE(dir_hnd);
				TALLOC_FREE(talloced);
				errno = ENOTEMPTY;
				goto err;
			}
			TALLOC_FREE(talloced);
		}

		/* We only have veto files/directories.
		 * Are we allowed to delete them ? */

		if(!lp_recursive_veto_delete(SNUM(conn))) {
			TALLOC_FREE(dir_hnd);
			errno = ENOTEMPTY;
			goto err;
		}

		/* Do a recursive delete. */
		RewindDir(dir_hnd,&dirpos);
		while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
					    &talloced)) != NULL) {
			struct smb_filename *smb_dname_full = NULL;
			char *fullname = NULL;
			bool do_break = true;
			NTSTATUS status;

			if (ISDOT(dname) || ISDOTDOT(dname)) {
				TALLOC_FREE(talloced);
				continue;
			}
			if (!is_visible_file(conn, smb_dname->base_name, dname,
					     &st, false)) {
				TALLOC_FREE(talloced);
				continue;
			}

			fullname = talloc_asprintf(ctx,
					"%s/%s",
					smb_dname->base_name,
					dname);

			if(!fullname) {
				errno = ENOMEM;
				goto err_break;
			}

			status = create_synthetic_smb_fname(talloc_tos(),
							    fullname, NULL,
							    NULL,
							    &smb_dname_full);
			if (!NT_STATUS_IS_OK(status)) {
				errno = map_errno_from_nt_status(status);
				goto err_break;
			}

			if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
				goto err_break;
			}
			if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
				if(!recursive_rmdir(ctx, conn,
						    smb_dname_full)) {
					goto err_break;
				}
				if(SMB_VFS_RMDIR(conn,
					smb_dname_full->base_name) != 0) {
					goto err_break;
				}
			} else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
				goto err_break;
			}

			/* Successful iteration. */
			do_break = false;

		 err_break:
			TALLOC_FREE(fullname);
			TALLOC_FREE(smb_dname_full);
			TALLOC_FREE(talloced);
			if (do_break)
				break;
		}
		TALLOC_FREE(dir_hnd);
		/* Retry the rmdir */
		ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
	}

  err:

	if (ret != 0) {
		DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
			 "%s\n", smb_fname_str_dbg(smb_dname),
			 strerror(errno)));
		return map_nt_error_from_unix(errno);
	}

	notify_fname(conn, NOTIFY_ACTION_REMOVED,
		     FILE_NOTIFY_CHANGE_DIR_NAME,
		     smb_dname->base_name);

	return NT_STATUS_OK;
}
Example #3
0
/* dnormalize():
 *	If the name starts with . or .. then we might need to normalize
 *	it depending on the symbolic link flags
 */
Char   *
dnormalize(Char *cp)
{

#define UC (unsigned char)
#define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/')))
#define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1])))

    if ((unsigned char) cp[0] == '/')
	return (Strsave(cp));

    if (adrof(STRignore_symlinks)) {
	int     dotdot = 0;
	Char   *dp, *cwd;
	size_t	len;

	len = (size_t) (Strlen(dcwd->di_name) + 3);
	cwd = xreallocarray(NULL, len, sizeof(Char));
	(void) Strlcpy(cwd, dcwd->di_name, len);

	/*
	 * Ignore . and count ..'s
	 */
	while (*cp) {
	    if (ISDOT(cp)) {
		if (*++cp)
		    cp++;
	    }
	    else if (ISDOTDOT(cp)) {
		dotdot++;
		cp += 2;
		if (*cp)
		    cp++;
	    }
	    else
		break;
	}
	while (dotdot > 0)
	    if ((dp = Strrchr(cwd, '/'))) {
		*dp = '\0';
		dotdot--;
	    }
	    else
		break;

	if (*cp) {
	    cwd[dotdot = Strlen(cwd)] = '/';
	    cwd[dotdot + 1] = '\0';
	    dp = Strspl(cwd, cp);
	    free(cwd);
	    return dp;
	}
	else {
	    if (!*cwd) {
		cwd[0] = '/';
		cwd[1] = '\0';
	    }
	    return cwd;
	}
    }
    return Strsave(cp);
}
Example #4
0
char *
getwd(char *pathname)
{
    DIR    *dp;
    struct dirent *d;
    extern int errno;

    struct stat st_root, st_cur, st_next, st_dotdot;
    char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
    char   *pathptr, *nextpathptr, *cur_name_add;

    /* find the inode of root */
    if (stat("/", &st_root) == -1) {
	(void)sprintf(pathname,
			"getwd: Cannot stat \"/\" (%s)", strerror(errno));
	return (NULL);
    }
    pathbuf[MAXPATHLEN - 1] = '\0';
    pathptr = &pathbuf[MAXPATHLEN - 1];
    nextpathbuf[MAXPATHLEN - 1] = '\0';
    cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];

    /* find the inode of the current directory */
    if (lstat(".", &st_cur) == -1) {
	(void)sprintf(pathname,
			"getwd: Cannot stat \".\" (%s)", strerror(errno));
	return (NULL);
    }
    nextpathptr = strrcpy(nextpathptr, "../");

    /* Descend to root */
    for (;;) {

	/* look if we found root yet */
	if (st_cur.st_ino == st_root.st_ino &&
	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
	    (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr);
	    return (pathname);
	}

	/* open the parent directory */
	if (stat(nextpathptr, &st_dotdot) == -1) {
	    (void)sprintf(pathname,
			    "getwd: Cannot stat directory \"%s\" (%s)",
			    nextpathptr, strerror(errno));
	    return (NULL);
	}
	if ((dp = opendir(nextpathptr)) == NULL) {
	    (void)sprintf(pathname,
			    "getwd: Cannot open directory \"%s\" (%s)",
			    nextpathptr, strerror(errno));
	    return (NULL);
	}

	/* look in the parent for the entry with the same inode */
	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
	    /* Parent has same device. No need to stat every member */
	    for (d = readdir(dp); d != NULL; d = readdir(dp))
		if (d->d_fileno == st_cur.st_ino)
		    break;
	}
	else {
	    /*
	     * Parent has a different device. This is a mount point so we
	     * need to stat every member
	     */
	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
		    continue;
		(void)strcpy(cur_name_add, d->d_name);
		if (lstat(nextpathptr, &st_next) == -1) {
		    (void)sprintf(pathname,
			"getwd: Cannot stat \"%s\" (%s)",
			d->d_name, strerror(errno));
		    (void)closedir(dp);
		    return (NULL);
		}
		/* check if we found it yet */
		if (st_next.st_ino == st_cur.st_ino &&
		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
		    break;
	    }
	}
	if (d == NULL) {
	    (void)sprintf(pathname,
		"getwd: Cannot find \".\" in \"..\"");
	    (void)closedir(dp);
	    return (NULL);
	}
	st_cur = st_dotdot;
	pathptr = strrcpy(pathptr, d->d_name);
	pathptr = strrcpy(pathptr, "/");
	nextpathptr = strrcpy(nextpathptr, "../");
	(void)closedir(dp);
	*cur_name_add = '\0';
    }
} /* end getwd */
Example #5
0
static int get_real_filename_full_scan(connection_struct *conn,
				       const char *path, const char *name,
				       bool mangled,
				       TALLOC_CTX *mem_ctx, char **found_name)
{
	struct smb_Dir *cur_dir;
	const char *dname = NULL;
	char *talloced = NULL;
	char *unmangled_name = NULL;
	long curpos;

	/* handle null paths */
	if ((path == NULL) || (*path == 0)) {
		path = ".";
	}

	/* If we have a case-sensitive filesystem, it doesn't do us any
	 * good to search for a name. If a case variation of the name was
	 * there, then the original stat(2) would have found it.
	 */
	if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
		errno = ENOENT;
		return -1;
	}

	/*
	 * The incoming name can be mangled, and if we de-mangle it
	 * here it will not compare correctly against the filename (name2)
	 * read from the directory and then mangled by the name_to_8_3()
	 * call. We need to mangle both names or neither.
	 * (JRA).
	 *
	 * Fix for bug found by Dina Fine. If in case sensitive mode then
	 * the mangle cache is no good (3 letter extension could be wrong
	 * case - so don't demangle in this case - leave as mangled and
	 * allow the mangling of the directory entry read (which is done
	 * case insensitively) to match instead. This will lead to more
	 * false positive matches but we fail completely without it. JRA.
	 */

	if (mangled && !conn->case_sensitive) {
		mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
						       &unmangled_name,
						       conn->params);
		if (!mangled) {
			/* Name is now unmangled. */
			name = unmangled_name;
		}
	}

	/* open the directory */
	if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) {
		DEBUG(3,("scan dir didn't open dir [%s]\n",path));
		TALLOC_FREE(unmangled_name);
		return -1;
	}

	/* now scan for matching names */
	curpos = 0;
	while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {

		/* Is it dot or dot dot. */
		if (ISDOT(dname) || ISDOTDOT(dname)) {
			TALLOC_FREE(talloced);
			continue;
		}

		/*
		 * At this point dname is the unmangled name.
		 * name is either mangled or not, depending on the state
		 * of the "mangled" variable. JRA.
		 */

		/*
		 * Check mangled name against mangled name, or unmangled name
		 * against unmangled name.
		 */

		if ((mangled && mangled_equal(name,dname,conn->params)) ||
			fname_equal(name, dname, conn->case_sensitive)) {
			/* we've found the file, change it's name and return */
			*found_name = talloc_strdup(mem_ctx, dname);
			TALLOC_FREE(unmangled_name);
			TALLOC_FREE(cur_dir);
			if (!*found_name) {
				errno = ENOMEM;
				TALLOC_FREE(talloced);
				return -1;
			}
			TALLOC_FREE(talloced);
			return 0;
		}
		TALLOC_FREE(talloced);
	}

	TALLOC_FREE(unmangled_name);
	TALLOC_FREE(cur_dir);
	errno = ENOENT;
	return -1;
}
Example #6
0
int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern,
	       bool is_case_sensitive)
{
	smb_ucs2_t *p = NULL;
	smb_ucs2_t *s = NULL;
	int ret, count, i;
	struct max_n *max_n = NULL;
	struct max_n *max_n_free = NULL;
	struct max_n one_max_n;
	size_t converted_size;

	if (ISDOTDOT(string)) {
		string = ".";
	}

	if (strpbrk(pattern, "<>*?\"") == NULL) {
		/* this is not just an optmisation - it is essential
		   for LANMAN1 correctness */
		if (is_case_sensitive) {
			return strcmp(pattern, string);
		} else {
			return StrCaseCmp(pattern, string);
		}
	}

	if (!push_ucs2_talloc(talloc_tos(), &p, pattern, &converted_size)) {
		return -1;
	}

	if (!push_ucs2_talloc(talloc_tos(), &s, string, &converted_size)) {
		TALLOC_FREE(p);
		return -1;
	}

	if (translate_pattern) {
		/*
		  for older negotiated protocols it is possible to
		  translate the pattern to produce a "new style"
		  pattern that exactly matches w2k behaviour
		*/
		for (i=0;p[i];i++) {
			if (p[i] == UCS2_CHAR('?')) {
				p[i] = UCS2_CHAR('>');
			} else if (p[i] == UCS2_CHAR('.') &&
				   (p[i+1] == UCS2_CHAR('?') ||
				    p[i+1] == UCS2_CHAR('*') ||
				    p[i+1] == 0)) {
				p[i] = UCS2_CHAR('"');
			} else if (p[i] == UCS2_CHAR('*') && p[i+1] == UCS2_CHAR('.')) {
				p[i] = UCS2_CHAR('<');
			}
		}
	}

	for (count=i=0;p[i];i++) {
		if (p[i] == UCS2_CHAR('*') || p[i] == UCS2_CHAR('<')) count++;
	}

	if (count != 0) {
		if (count == 1) {
			/*
			 * We're doing this a LOT, so save the effort to allocate
			 */
			ZERO_STRUCT(one_max_n);
			max_n = &one_max_n;
		}
		else {
			max_n = SMB_CALLOC_ARRAY(struct max_n, count);
			if (!max_n) {
				TALLOC_FREE(p);
				TALLOC_FREE(s);
				return -1;
			}
			max_n_free = max_n;
		}
	}

	ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive);

	SAFE_FREE(max_n_free);
	TALLOC_FREE(p);
	TALLOC_FREE(s);
	return ret;
}
Example #7
0
/* 
   return the next entry
*/
const char *pvfs_list_next(struct pvfs_dir *dir, off_t *ofs)
{
	struct dirent *de;
	enum protocol_types protocol = dir->pvfs->ntvfs->ctx->protocol;

	/* non-wildcard searches are easy */
	if (dir->no_wildcard) {
		dir->end_of_search = True;
		if (*ofs != 0) return NULL;
		(*ofs)++;
		return dir->single_name;
	}

	/* . and .. are handled separately as some unix systems will
	   not return them first in a directory, but windows client
	   may assume that these entries always appear first */
	if (*ofs == DIR_OFFSET_DOT) {
		(*ofs) = DIR_OFFSET_DOTDOT;
		dir->offset = *ofs;
		if (ms_fnmatch(dir->pattern, ".", protocol) == 0) {
			dcache_add(dir, ".");
			return ".";
		}
	}

	if (*ofs == DIR_OFFSET_DOTDOT) {
		(*ofs) = DIR_OFFSET_BASE;
		dir->offset = *ofs;
		if (ms_fnmatch(dir->pattern, "..", protocol) == 0) {
			dcache_add(dir, "..");
			return "..";
		}
	}

	if (*ofs == DIR_OFFSET_BASE) {
		rewinddir(dir->dir);
	} else if (*ofs != dir->offset) {
		seekdir(dir->dir, (*ofs) - DIR_OFFSET_BASE);
	}
	dir->offset = *ofs;
	
	while ((de = readdir(dir->dir))) {
		const char *dname = de->d_name;

		if (ISDOT(dname) || ISDOTDOT(dname)) {
			continue;
		}

		if (ms_fnmatch(dir->pattern, dname, protocol) != 0) {
			char *short_name = pvfs_short_name_component(dir->pvfs, dname);
			if (short_name == NULL ||
			    ms_fnmatch(dir->pattern, short_name, protocol) != 0) {
				talloc_free(short_name);
				continue;
			}
			talloc_free(short_name);
		}

		dir->offset = telldir(dir->dir) + DIR_OFFSET_BASE;
		(*ofs) = dir->offset;

		dcache_add(dir, dname);

		return dname;
	}

	dir->end_of_search = True;
	return NULL;
}
Example #8
0
void stat_cache_add( const char *full_orig_name,
		char *translated_path,
		bool case_sensitive)
{
	size_t translated_path_length;
	char *original_path;
	size_t original_path_length;
	char saved_char;
	TALLOC_CTX *ctx = talloc_tos();

	if (!lp_stat_cache()) {
		return;
	}

	/*
	 * Don't cache trivial valid directory entries such as . and ..
	 */

	if ((*full_orig_name == '\0')
	    || ISDOT(full_orig_name) || ISDOTDOT(full_orig_name)) {
		return;
	}

	/*
	 * If we are in case insentive mode, we don't need to
	 * store names that need no translation - else, it
	 * would be a waste.
	 */

	if (case_sensitive && (strcmp(full_orig_name, translated_path) == 0)) {
		return;
	}

	/*
	 * Remove any trailing '/' characters from the
	 * translated path.
	 */

	translated_path_length = strlen(translated_path);

	if(translated_path[translated_path_length-1] == '/') {
		translated_path_length--;
	}

	if(case_sensitive) {
		original_path = talloc_strdup(ctx,full_orig_name);
	} else {
		original_path = talloc_strdup_upper(ctx,full_orig_name);
	}

	if (!original_path) {
		return;
	}

	original_path_length = strlen(original_path);

	if(original_path[original_path_length-1] == '/') {
		original_path[original_path_length-1] = '\0';
		original_path_length--;
	}

	if (original_path_length != translated_path_length) {
		if (original_path_length < translated_path_length) {
			DEBUG(0, ("OOPS - tried to store stat cache entry "
			"for weird length paths [%s] %lu and [%s] %lu)!\n",
				  original_path,
				  (unsigned long)original_path_length,
				  translated_path,
				  (unsigned long)translated_path_length));
			TALLOC_FREE(original_path);
			return;
		}

		/* we only want to index by the first part of original_path,
			up to the length of translated_path */

		original_path[translated_path_length] = '\0';
		original_path_length = translated_path_length;
	}

	/* Ensure we're null terminated. */
	saved_char = translated_path[translated_path_length];
	translated_path[translated_path_length] = '\0';

	/*
	 * New entry or replace old entry.
	 */

	memcache_add(
		smbd_memcache(), STAT_CACHE,
		data_blob_const(original_path, original_path_length),
		data_blob_const(translated_path, translated_path_length + 1));

	DEBUG(5,("stat_cache_add: Added entry (%lx:size %x) %s -> %s\n",
		 (unsigned long)translated_path,
		 (unsigned int)translated_path_length,
		 original_path,
		 translated_path));

	translated_path[translated_path_length] = saved_char;
	TALLOC_FREE(original_path);
}
Example #9
0
bool stat_cache_lookup(connection_struct *conn,
			bool posix_paths,
			char **pp_name,
			char **pp_dirpath,
			char **pp_start,
			SMB_STRUCT_STAT *pst)
{
	char *chk_name;
	size_t namelen;
	bool sizechanged = False;
	unsigned int num_components = 0;
	char *translated_path;
	size_t translated_path_length;
	DATA_BLOB data_val;
	char *name;
	TALLOC_CTX *ctx = talloc_tos();
	struct smb_filename smb_fname;
	int ret;

	*pp_dirpath = NULL;
	*pp_start = *pp_name;

	if (!lp_stat_cache()) {
		return False;
	}

	name = *pp_name;
	namelen = strlen(name);

	DO_PROFILE_INC(statcache_lookups);

	/*
	 * Don't lookup trivial valid directory entries.
	 */
	if ((*name == '\0') || ISDOT(name) || ISDOTDOT(name)) {
		return False;
	}

	if (conn->case_sensitive) {
		chk_name = talloc_strdup(ctx,name);
		if (!chk_name) {
			DEBUG(0, ("stat_cache_lookup: strdup failed!\n"));
			return False;
		}

	} else {
		chk_name = talloc_strdup_upper(ctx,name);
		if (!chk_name) {
			DEBUG(0, ("stat_cache_lookup: talloc_strdup_upper failed!\n"));
			return False;
		}

		/*
		 * In some language encodings the length changes
		 * if we uppercase. We need to treat this differently
		 * below.
		 */
		if (strlen(chk_name) != namelen) {
			sizechanged = True;
		}
	}

	while (1) {
		char *sp;

		data_val = data_blob_null;

		if (memcache_lookup(
			    smbd_memcache(), STAT_CACHE,
			    data_blob_const(chk_name, strlen(chk_name)),
			    &data_val)) {
			break;
		}

		DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n",
				chk_name ));
		/*
		 * Didn't find it - remove last component for next try.
		 */
		if (!(sp = strrchr_m(chk_name, '/'))) {
			/*
			 * We reached the end of the name - no match.
			 */
			DO_PROFILE_INC(statcache_misses);
			TALLOC_FREE(chk_name);
			return False;
		}

		*sp = '\0';

		/*
		 * Count the number of times we have done this, we'll
		 * need it when reconstructing the string.
		 */

		if (sizechanged) {
			num_components++;
		}

		if ((*chk_name == '\0')
		    || ISDOT(chk_name) || ISDOTDOT(chk_name)) {
			DO_PROFILE_INC(statcache_misses);
			TALLOC_FREE(chk_name);
			return False;
		}
	}

	translated_path = talloc_strdup(ctx,(char *)data_val.data);
	if (!translated_path) {
		smb_panic("talloc failed");
	}
	translated_path_length = data_val.length - 1;

	DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] "
		  "-> [%s]\n", chk_name, translated_path ));
	DO_PROFILE_INC(statcache_hits);

	ZERO_STRUCT(smb_fname);
	smb_fname.base_name = translated_path;

	if (posix_paths) {
		ret = SMB_VFS_LSTAT(conn, &smb_fname);
	} else {
		ret = SMB_VFS_STAT(conn, &smb_fname);
	}

	if (ret != 0) {
		/* Discard this entry - it doesn't exist in the filesystem. */
		memcache_delete(smbd_memcache(), STAT_CACHE,
				data_blob_const(chk_name, strlen(chk_name)));
		TALLOC_FREE(chk_name);
		TALLOC_FREE(translated_path);
		return False;
	}
	*pst = smb_fname.st;

	if (!sizechanged) {
		memcpy(*pp_name, translated_path,
		       MIN(namelen, translated_path_length));
	} else {
		if (num_components == 0) {
			name = talloc_strndup(ctx, translated_path,
					   translated_path_length);
		} else {
			char *sp;

			sp = strnrchr_m(name, '/', num_components);
			if (sp) {
				name = talloc_asprintf(ctx,"%.*s%s",
					 (int)translated_path_length,
					 translated_path, sp);
			} else {
				name = talloc_strndup(ctx,
						translated_path,
						translated_path_length);
			}
		}
		if (name == NULL) {
			/*
			 * TODO: Get us out of here with a real error message
			 */
			smb_panic("talloc failed");
		}
		TALLOC_FREE(*pp_name);
		*pp_name = name;
	}


	/* set pointer for 'where to start' on fixing the rest of the name */
	*pp_start = &name[translated_path_length];
	if (**pp_start == '/') {
		++*pp_start;
	}

	*pp_dirpath = translated_path;
	TALLOC_FREE(chk_name);
	return (namelen == translated_path_length);
}
Example #10
0
char *
xgetcwd(char *pathname, size_t pathlen)
{
    DIR    *dp;
    struct dirent *d;

    struct stat st_root, st_cur, st_next, st_dotdot;
    char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
    char   *pathptr, *nextpathptr, *cur_name_add;
    int	   save_errno = 0;

    /* find the inode of root */
    if (stat("/", &st_root) == -1) {
	(void) xsnprintf(pathname, pathlen, CGETS(23, 23, 
			"getcwd: Cannot stat \"/\" (%s)"),
			strerror(errno));
	return NULL;
    }
    pathbuf[MAXPATHLEN - 1] = '\0';
    pathptr = &pathbuf[MAXPATHLEN - 1];
    nextpathbuf[MAXPATHLEN - 1] = '\0';
    cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];

    /* find the inode of the current directory */
    if (lstat(".", &st_cur) == -1) {
	(void) xsnprintf(pathname, pathlen, CGETS(23, 24,
			 "getcwd: Cannot stat \".\" (%s)"),
			 strerror(errno));
	return NULL;
    }
    nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);

    /* Descend to root */
    for (;;) {

	/* look if we found root yet */
	if (st_cur.st_ino == st_root.st_ino &&
	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
	    (void) strncpy(pathname, *pathptr != '/' ? "/" : pathptr, pathlen);
	    pathname[pathlen - 1] = '\0';
	    return pathname;
	}

	/* open the parent directory */
	if (stat(nextpathptr, &st_dotdot) == -1) {
	    (void) xsnprintf(pathname, pathlen, CGETS(23, 25,
			     "getcwd: Cannot stat directory \"%s\" (%s)"),
			     nextpathptr, strerror(errno));
	    return NULL;
	}
	if ((dp = opendir(nextpathptr)) == NULL) {
	    (void) xsnprintf(pathname, pathlen, CGETS(23, 26,
			     "getcwd: Cannot open directory \"%s\" (%s)"),
			     nextpathptr, strerror(errno));
	    return NULL;
	}

	/* look in the parent for the entry with the same inode */
	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
	    /* Parent has same device. No need to stat every member */
	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
#ifdef __clipper__
		if (((unsigned long)d->d_ino & 0xffff) == st_cur.st_ino)
		    break;
#else
		if (d->d_ino == st_cur.st_ino)
		    break;
#endif
	    }
	}
	else {
	    /* 
	     * Parent has a different device. This is a mount point so we 
	     * need to stat every member 
	     */
	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
		    continue;
		(void)strncpy(cur_name_add, d->d_name,
		    (size_t) (&nextpathbuf[sizeof(nextpathbuf) - 1] - cur_name_add));
		if (lstat(nextpathptr, &st_next) == -1) {
		    /*
		     * We might not be able to stat() some path components
		     * if we are using afs, but this is not an error as
		     * long as we find the one we need; we also save the
		     * first error to report it if we don't finally succeed.
		     */
		    if (save_errno == 0)
			save_errno = errno;
		    continue;
		}
		/* check if we found it yet */
		if (st_next.st_ino == st_cur.st_ino &&
		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev)) 
		    break;
	    }
	}
	if (d == NULL) {
	    (void) xsnprintf(pathname, pathlen, CGETS(23, 27,
			     "getcwd: Cannot find \".\" in \"..\" (%s)"),
			     strerror(save_errno ? save_errno : ENOENT));
	    closedir(dp);
	    return NULL;
	}
	else
	    save_errno = 0;
	st_cur = st_dotdot;
	pathptr = strnrcpy(pathptr, d->d_name, pathptr - pathbuf);
	pathptr = strnrcpy(pathptr, "/", pathptr - pathbuf);
	nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
	*cur_name_add = '\0';
	closedir(dp);
    }
} /* end getcwd */
Example #11
0
/*
  delete a file - the dirtype specifies the file types to include in the search. 
  The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
*/
NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
		     struct ntvfs_request *req,
		     union smb_unlink *unl)
{
	struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
				  struct pvfs_state);
	struct pvfs_dir *dir;
	NTSTATUS status;
	uint32_t total_deleted=0;
	struct pvfs_filename *name;
	const char *fname;
	off_t ofs;

	/* resolve the cifs name to a posix name */
	status = pvfs_resolve_name(pvfs, req, unl->unlink.in.pattern, 
				   PVFS_RESOLVE_WILDCARD |
				   PVFS_RESOLVE_STREAMS |
				   PVFS_RESOLVE_NO_OPENDB,
				   &name);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (!name->exists && !name->has_wildcard) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (name->exists && 
	    (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
		return NT_STATUS_FILE_IS_A_DIRECTORY;
	}

	if (!name->has_wildcard) {
		return pvfs_unlink_one(pvfs, req, unl, name);
	}

	/*
	 * disable async requests in the wildcard case
	 * untill we have proper tests for this
	 */
	req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;

	/* get list of matching files */
	status = pvfs_list_start(pvfs, name, req, &dir);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	status = NT_STATUS_NO_SUCH_FILE;
	talloc_free(name);

	ofs = 0;

	while ((fname = pvfs_list_next(dir, &ofs))) {
		/* this seems to be a special case */
		if ((unl->unlink.in.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
		    (ISDOT(fname) || ISDOTDOT(fname))) {
			return NT_STATUS_OBJECT_NAME_INVALID;
		}

		/* get a pvfs_filename object */
		status = pvfs_resolve_partial(pvfs, req,
					      pvfs_list_unix_path(dir),
					      fname,
					      PVFS_RESOLVE_NO_OPENDB,
					      &name);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		status = pvfs_unlink_one(pvfs, req, unl, name);
		if (NT_STATUS_IS_OK(status)) {
			total_deleted++;
		}

		talloc_free(name);
	}

	if (total_deleted > 0) {
		status = NT_STATUS_OK;
	}

	return status;
}