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; }
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; }
/* 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); }
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 */
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; }
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; }
/* 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; }
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); }
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); }
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 */
/* 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; }