static NTSTATUS determine_path_error(const char *name, bool allow_wcard_last_component) { const char *p; if (!allow_wcard_last_component) { /* Error code within a pathname. */ return NT_STATUS_OBJECT_PATH_NOT_FOUND; } /* We're terminating here so we * can be a little slower and get * the error code right. Windows * treats the last part of the pathname * separately I think, so if the last * component is a wildcard then we treat * this ./ as "end of component" */ p = strchr(name, '/'); if (!p && (ms_has_wild(name) || ISDOT(name))) { /* Error code at the end of a pathname. */ return NT_STATUS_OBJECT_NAME_INVALID; } else { /* Error code within a pathname. */ return NT_STATUS_OBJECT_PATH_NOT_FOUND; } }
static void checkdot(char **argv) { char *p, **save, **t; int complained; complained = 0; for (t = argv; *t;) { /* strip trailing slashes */ p = strrchr(*t, '\0'); while (--p > *t && *p == '/') *p = '\0'; /* extract basename */ if ((p = strrchr(*t, '/')) != NULL) ++p; else p = *t; if (ISDOT(p)) { if (!complained++) warnx("\".\" and \"..\" may not be removed"); eval = 1; for (save = t; (t[0] = t[1]) != NULL; ++t) continue; t = save; } else ++t; } }
static void test_mask(int argc, char *argv[], TALLOC_CTX *mem_ctx, struct smbcli_state *cli) { char *mask, *file; int l1, l2, i, l; int mc_len = strlen(maskchars); int fc_len = strlen(filechars); smbcli_mkdir(cli->tree, "\\masktest"); smbcli_unlink(cli->tree, "\\masktest\\*"); if (argc >= 2) { while (argc >= 2) { mask = talloc_strdup(mem_ctx, "\\masktest\\"); file = talloc_strdup(mem_ctx, "\\masktest\\"); mask = talloc_strdup_append(mask, argv[0]); file = talloc_strdup_append(file, argv[1]); testpair(mem_ctx, cli, mask, file); argv += 2; argc -= 2; } goto finished; } while (1) { l1 = 1 + random() % max_length; l2 = 1 + random() % max_length; mask = talloc_strdup(mem_ctx, "\\masktest\\"); file = talloc_strdup(mem_ctx, "\\masktest\\"); mask = talloc_realloc_size(mem_ctx, mask, strlen(mask)+l1+1); file = talloc_realloc_size(mem_ctx, file, strlen(file)+l2+1); l = strlen(mask); for (i=0;i<l1;i++) { mask[i+l] = maskchars[random() % mc_len]; } mask[l+l1] = 0; for (i=0;i<l2;i++) { file[i+l] = filechars[random() % fc_len]; } file[l+l2] = 0; if (ISDOT(file+l) || ISDOTDOT(file+l) || ISDOTDOT(mask+l)) { continue; } if (strspn(file+l, ".") == strlen(file+l)) continue; testpair(mem_ctx, cli, mask, file); if (NumLoops && (--NumLoops == 0)) break; } finished: smbcli_rmdir(cli->tree, "\\masktest"); talloc_free(mem_ctx); }
void read_cgmem_stats(struct module *mod) { DIR *dir; char path[128]; char line[LEN_128]; FILE *memfd; struct dirent *ent; /* dirent handle */ n_group = 0; memset(cgmem_groups, 0, CGMEM_GROUP_SIZE * MAX_GROUP); if ((dir = opendir(CGMEM_PATH)) == NULL) { return; } while ((ent = readdir(dir))) { if (ent->d_type == DT_DIR && !ISDOT(ent->d_name)) { //for each group memcpy(&cgmem_groups[n_group].group_name, ent->d_name, strlen(ent->d_name)+1); snprintf(path, 128, "%s/%s/memory.stat", CGMEM_PATH, ent->d_name); if ((memfd = fopen(path, "r")) == NULL) { closedir(dir); return; } while (fgets(line, 128, memfd) != NULL) { if (!strncmp(line, "cache", 5)) { sscanf(line + 5, "%lu", &cgmem_groups[n_group].cache); } else if (!strncmp(line, "rss", 3)) { sscanf(line + 3, "%lu", &cgmem_groups[n_group].rss); } else if (!strncmp(line, "swap", 4)) { sscanf(line + 4, "%lu", &cgmem_groups[n_group].swap); } else if (!strncmp(line, "inactive_anon", 13)) { sscanf(line + 13, "%lu", &cgmem_groups[n_group].inanon); } else if (!strncmp(line, "active_anon", 11)) { sscanf(line + 11, "%lu", &cgmem_groups[n_group].acanon); } else if (!strncmp(line, "inactive_file", 13)) { sscanf(line + 13, "%lu", &cgmem_groups[n_group].infile); } else if (!strncmp(line, "active_file", 11)) { sscanf(line + 11, "%lu", &cgmem_groups[n_group].acfile); } } fclose(memfd); n_group ++; } } closedir(dir); print_cgmem_stats(mod); }
int get_real_filename(connection_struct *conn, const char *path, const char *name, TALLOC_CTX *mem_ctx, char **found_name) { struct smb_Dir *cur_dir; const char *dname; bool mangled; char *unmangled_name = NULL; long curpos; /* 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))) { /* Is it dot or dot dot. */ if (ISDOT(dname) || ISDOTDOT(dname)) { 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; return -1; } return 0; } } TALLOC_FREE(unmangled_name); TALLOC_FREE(cur_dir); errno = ENOENT; return -1; }
NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32 dosmode) { /* * Only allow delete on close for writable files. */ if ((dosmode & FILE_ATTRIBUTE_READONLY) && !lp_delete_readonly(SNUM(fsp->conn))) { DEBUG(10,("can_set_delete_on_close: file %s delete on close " "flag set but file attribute is readonly.\n", fsp_str_dbg(fsp))); return NT_STATUS_CANNOT_DELETE; } /* * Only allow delete on close for writable shares. */ if (!CAN_WRITE(fsp->conn)) { DEBUG(10,("can_set_delete_on_close: file %s delete on " "close flag set but write access denied on share.\n", fsp_str_dbg(fsp))); return NT_STATUS_ACCESS_DENIED; } /* * Only allow delete on close for files/directories opened with delete * intent. */ if (!(fsp->access_mask & DELETE_ACCESS)) { DEBUG(10,("can_set_delete_on_close: file %s delete on " "close flag set but delete access denied.\n", fsp_str_dbg(fsp))); return NT_STATUS_ACCESS_DENIED; } /* Don't allow delete on close for non-empty directories. */ if (fsp->is_directory) { SMB_ASSERT(!is_ntfs_stream_smb_fname(fsp->fsp_name)); /* Or the root of a share. */ if (ISDOT(fsp->fsp_name->base_name)) { DEBUG(10,("can_set_delete_on_close: can't set delete on " "close for the root of a share.\n")); return NT_STATUS_ACCESS_DENIED; } return can_delete_directory(fsp->conn, fsp->fsp_name->base_name); } return NT_STATUS_OK; }
static bool reg_match_one(struct smbcli_state *cli, const char *pattern, const char *file) { /* oh what a weird world this is */ if (old_list && strcmp(pattern, "*.*") == 0) return true; if (ISDOT(pattern)) return false; if (ISDOTDOT(file)) file = "."; return ms_fnmatch(pattern, file, cli->transport->negotiate.protocol)==0; }
static uint32 set_offline_flag(connection_struct *conn, const char *const path) { if (ISDOT(path) || ISDOTDOT(path)) { return 0; } if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) { return 0; } return dmapi_file_flags(path); }
NTSTATUS check_veto_path(connection_struct *conn, const char *name) { if (IS_VETO_PATH(conn, name)) { /* Is it not dot or dot dot. */ if (!(ISDOT(name) || ISDOTDOT(name))) { DEBUG(5,("check_veto_path: file path name %s vetoed\n", name)); return map_nt_error_from_unix(ENOENT); } } return NT_STATUS_OK; }
static unsigned short fts_stat(FTS *sp, FTSENT *p) { FTSENT *t; dev_t dev; ino_t ino; struct stat *sbp; /* If user needs stat info, stat buffer already allocated. */ sbp = p->fts_statp; if (lstat(p->fts_accpath, sbp)) { p->fts_errno = errno; memset(sbp, 0, sizeof(struct stat)); return (FTS_NS); } if (S_ISDIR(sbp->st_mode)) { /* * Set the device/inode. Used to find cycles and check for * crossing mount points. Also remember the link count, used * in fts_build to limit the number of stat calls. It is * understood that these fields are only referenced if fts_info * is set to FTS_D. */ dev = p->fts_dev = sbp->st_dev; ino = p->fts_ino = sbp->st_ino; p->fts_nlink = sbp->st_nlink; if (ISDOT(p->fts_name)) return (FTS_DOT); /* * Cycle detection is done by brute force when the directory * is first encountered. If the tree gets deep enough or the * number of symbolic links to directories is high enough, * something faster might be worthwhile. */ for (t = p->fts_parent; t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) if (ino == t->fts_ino && dev == t->fts_dev) { p->fts_cycle = t; return (FTS_DC); } return (FTS_D); } if (S_ISLNK(sbp->st_mode)) return (FTS_SL); if (S_ISREG(sbp->st_mode)) return (FTS_F); return (FTS_DEFAULT); }
/* seek to the given name */ NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, off_t *ofs) { struct dirent *de; int i; dir->end_of_search = False; if (ISDOT(name)) { dir->offset = DIR_OFFSET_DOTDOT; *ofs = dir->offset; return NT_STATUS_OK; } if (ISDOTDOT(name)) { dir->offset = DIR_OFFSET_BASE; *ofs = dir->offset; return NT_STATUS_OK; } for (i=dir->name_cache_index;i>=0;i--) { struct name_cache_entry *e = &dir->name_cache[i]; if (e->name && strcasecmp_m(name, e->name) == 0) { *ofs = e->offset; return NT_STATUS_OK; } } for (i=NAME_CACHE_SIZE-1;i>dir->name_cache_index;i--) { struct name_cache_entry *e = &dir->name_cache[i]; if (e->name && strcasecmp_m(name, e->name) == 0) { *ofs = e->offset; return NT_STATUS_OK; } } rewinddir(dir->dir); while ((de = readdir(dir->dir))) { if (strcasecmp_m(name, de->d_name) == 0) { dir->offset = telldir(dir->dir) + DIR_OFFSET_BASE; *ofs = dir->offset; return NT_STATUS_OK; } } dir->end_of_search = True; return NT_STATUS_OBJECT_NAME_NOT_FOUND; }
static void listfn(struct clilist_file_info *f, const char *s, void *state) { struct masktest_state *m = (struct masktest_state *)state; if (ISDOT(f->name)) { resultp[0] = '+'; } else if (ISDOTDOT(f->name)) { resultp[1] = '+'; } else { resultp[2] = '+'; } last_hit.long_name = talloc_strdup(m->mem_ctx, f->name); last_hit.short_name = talloc_strdup(m->mem_ctx, f->short_name); f_info_hit = true; }
/* see if a directory is empty */ BOOL pvfs_directory_empty(struct pvfs_state *pvfs, struct pvfs_filename *name) { struct dirent *de; DIR *dir = opendir(name->full_name); if (dir == NULL) { return True; } while ((de = readdir(dir))) { if (!ISDOT(de->d_name) && !ISDOTDOT(de->d_name)) { closedir(dir); return False; } } closedir(dir); return True; }
/* callback function for torture_deltree() */ static void delete_fn(struct clilist_file_info *finfo, const char *name, void *state) { struct delete_state *dstate = (struct delete_state *)state; char *s, *n; if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) { return; } n = strdup(name); n[strlen(n)-1] = 0; asprintf(&s, "%s%s", n, finfo->name); if (finfo->attrib & FILE_ATTRIBUTE_READONLY) { if (NT_STATUS_IS_ERR(smbcli_setatr(dstate->tree, s, 0, 0))) { DEBUG(2,("Failed to remove READONLY on %s - %s\n", s, smbcli_errstr(dstate->tree))); } } if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) { char *s2; asprintf(&s2, "%s\\*", s); smbcli_unlink(dstate->tree, s2); smbcli_list(dstate->tree, s2, FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, delete_fn, state); free(s2); if (NT_STATUS_IS_ERR(smbcli_rmdir(dstate->tree, s))) { DEBUG(2,("Failed to delete %s - %s\n", s, smbcli_errstr(dstate->tree))); dstate->failed = true; } dstate->total_deleted++; } else { if (NT_STATUS_IS_ERR(smbcli_unlink(dstate->tree, s))) { DEBUG(2,("Failed to delete %s - %s\n", s, smbcli_errstr(dstate->tree))); dstate->failed = true; } dstate->total_deleted++; } free(s); free(n); }
static void gen_name(char *name) { const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~..."; uint_t max_idx = strlen(chars); uint_t len; int i; char *p; fstrcpy(name, "\\mangle_test\\"); p = name + strlen(name); len = 1 + random() % NAME_LENGTH; for (i=0;i<len;i++) { p[i] = chars[random() % max_idx]; } p[i] = 0; if (ISDOT(p) || ISDOTDOT(p)) { p[0] = '_'; } /* have a high probability of a common lead char */ if (random() % 2 == 0) { p[0] = 'A'; } /* and a medium probability of a common lead string */ if (random() % 10 == 0) { strncpy(p, "ABCDE", 5); } /* and a high probability of a good extension length */ if (random() % 2 == 0) { char *s = strrchr(p, '.'); if (s) { s[4] = 0; } } }
checkdot(char **argv) #endif { char *p, **save, **t; int complained; complained = 0; for (t = argv; *t;) { if ((p = strrchr(*t, '/')) != NULL) ++p; else p = *t; if (ISDOT(p)) { if (!complained++) warnx("\".\" and \"..\" may not be removed"); eval = 1; for (save = t; (t[0] = t[1]) != NULL; ++t); t = save; } else ++t; } }
void checkdot(char **argv) { char *p, **save, **t; int complained; struct stat sb, root; stat("/", &root); complained = 0; for (t = argv; *t;) { if (lstat(*t, &sb) == 0 && root.st_ino == sb.st_ino && root.st_dev == sb.st_dev) { if (!complained++) warnx("\"/\" may not be removed"); goto skip; } /* strip trailing slashes */ p = strrchr(*t, '\0'); while (--p > *t && *p == '/') *p = '\0'; /* extract basename */ if ((p = strrchr(*t, '/')) != NULL) ++p; else p = *t; if (ISDOT(p)) { if (!complained++) warnx("\".\" and \"..\" may not be removed"); skip: eval = 1; for (save = t; (t[0] = t[1]) != NULL; ++t) continue; t = save; } else ++t; } }
static void checkdot(char **argv) { char *p, **save, **t; int complained; complained = 0; for (t = argv; *t;) { #ifdef HAVE_DOS_PATHS const char *tmp = p = *t; while (*tmp) { switch (*tmp) { case '/': case '\\': case ':': p = (char *)tmp + 1; break; } tmp++; } #else if ((p = strrchr(*t, '/')) != NULL) ++p; else p = *t; #endif if (ISDOT(p)) { if (!complained++) fprintf(stderr, "%s: \".\" and \"..\" may not be removed\n", argv0); eval = 1; for (save = t; (t[0] = t[1]) != NULL; ++t) continue; t = save; } else ++t; } }
/* recursively delete a directory tree */ static void recursive_delete(const char *path) { DIR *dir; struct dirent *de; dir = opendir(path); if (!dir) { return; } for (de=readdir(dir);de;de=readdir(dir)) { char *fname; struct stat st; if (ISDOT(de->d_name) || ISDOTDOT(de->d_name)) { continue; } fname = talloc_asprintf(path, "%s/%s", path, de->d_name); if (stat(fname, &st) != 0) { continue; } if (S_ISDIR(st.st_mode)) { recursive_delete(fname); talloc_free(fname); continue; } if (unlink(fname) != 0) { DEBUG(0,("Unabled to delete '%s' - %s\n", fname, strerror(errno))); smb_panic("unable to cleanup tmp files"); } talloc_free(fname); } closedir(dir); }
/** * Obtain list of init functions from the modules in the specified * directory */ static init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path) { DIR *dir; struct dirent *entry; char *filename; int success = 0; init_module_fn *ret = talloc_array(mem_ctx, init_module_fn, 2); ret[0] = NULL; dir = opendir(path); if (dir == NULL) { talloc_free(ret); return NULL; } while((entry = readdir(dir))) { if (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name)) continue; filename = talloc_asprintf(mem_ctx, "%s/%s", path, entry->d_name); ret[success] = load_module(filename, true, NULL); if (ret[success]) { ret = talloc_realloc(mem_ctx, ret, init_module_fn, success+2); success++; ret[success] = NULL; } talloc_free(filename); } closedir(dir); return ret; }
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; 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; } smb_dname_full = synthetic_smb_fname(talloc_tos(), fullname, NULL, NULL); if (smb_dname_full == NULL) { errno = ENOMEM; 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; }
/* * This is the tricky part -- do not casually change *anything* in here. The * idea is to build the linked list of entries that are used by fts_children * and fts_read. There are lots of special cases. * * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is * set and it's a physical walk (so that symbolic links can't be directories), * we can do things quickly. First, if it's a 4.4BSD file system, the type * of the file is in the directory entry. Otherwise, we assume that the number * of subdirectories in a node is equal to the number of links to the parent. * The former skips all stat calls. The latter skips stat calls in any leaf * directories and for any files after the subdirectories in the directory have * been found, cutting the stat calls by about 2/3. */ static FTSENT * fts_build(FTS *sp, int type) { struct dirent *dp; FTSENT *p, *head; FTSENT *cur, *tail; DIR *dirp; void *oldaddr; size_t len, maxlen; int nitems, cderrno, descend, level, nlinks, nostat, doadjust; int saved_errno; char *cp; /* Set current node pointer. */ cur = sp->fts_cur; /* * Open the directory for reading. If this fails, we're done. * If being called from fts_read, set the fts_info field. */ if ((dirp = opendir(cur->fts_accpath)) == NULL) { if (type == BREAD) { cur->fts_info = FTS_DNR; cur->fts_errno = errno; } return (NULL); } /* * Nlinks is the number of possible entries of type directory in the * directory if we're cheating on stat calls, 0 if we're not doing * any stat calls at all, -1 if we're doing stats on everything. */ if (type == BNAMES) nlinks = 0; else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); nostat = 1; } else { nlinks = -1; nostat = 0; } #ifdef notdef (void)printf("nlinks == %d (cur: %u)\n", nlinks, cur->fts_nlink); (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); #endif /* * If we're going to need to stat anything or we want to descend * and stay in the directory, chdir. If this fails we keep going, * but set a flag so we don't chdir after the post-order visit. * We won't be able to stat anything, but we can still return the * names themselves. Note, that since fts_read won't be able to * chdir into the directory, it will have to return different path * names than before, i.e. "a/b" instead of "b". Since the node * has already been visited in pre-order, have to wait until the * post-order visit to return the error. There is a special case * here, if there was nothing to stat then it's not an error to * not be able to stat. This is all fairly nasty. If a program * needed sorted entries or stat information, they had better be * checking FTS_NS on the returned nodes. */ cderrno = 0; if (nlinks || type == BREAD) { if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { if (nlinks && type == BREAD) cur->fts_errno = errno; cur->fts_flags |= FTS_DONTCHDIR; descend = 0; cderrno = errno; (void)closedir(dirp); dirp = NULL; } else descend = 1; } else descend = 0; /* * Figure out the max file name length that can be stored in the * current path -- the inner loop allocates more path as necessary. * We really wouldn't have to do the maxlen calculations here, we * could do them in fts_read before returning the path, but it's a * lot easier here since the length is part of the dirent structure. * * If not changing directories set a pointer so that can just append * each new name into the path. */ len = NAPPEND(cur); if (ISSET(FTS_NOCHDIR)) { cp = sp->fts_path + len; *cp++ = '/'; } len++; maxlen = sp->fts_pathlen - len; /* * fts_level is signed so we must prevent it from wrapping * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL. */ level = cur->fts_level; if (level < FTS_MAXLEVEL) level++; /* Read the directory, attaching each entry to the `link' pointer. */ doadjust = 0; for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; if (!(p = fts_alloc(sp, dp->d_name, (size_t)dp->d_namlen))) goto mem1; if (dp->d_namlen >= maxlen) { /* include space for NUL */ oldaddr = sp->fts_path; if (fts_palloc(sp, dp->d_namlen +len + 1)) { /* * No more memory for path or structures. Save * errno, free up the current structure and the * structures already allocated. */ mem1: saved_errno = errno; if (p) free(p); fts_lfree(head); (void)closedir(dirp); cur->fts_info = FTS_ERR; SET(FTS_STOP); errno = saved_errno; return (NULL); } /* Did realloc() change the pointer? */ if (oldaddr != sp->fts_path) { doadjust = 1; if (ISSET(FTS_NOCHDIR)) cp = sp->fts_path + len; } maxlen = sp->fts_pathlen - len; } p->fts_level = level; p->fts_parent = sp->fts_cur; p->fts_pathlen = len + dp->d_namlen; if (p->fts_pathlen < len) { /* * If we wrap, free up the current structure and * the structures already allocated, then error * out with ENAMETOOLONG. */ free(p); fts_lfree(head); (void)closedir(dirp); cur->fts_info = FTS_ERR; SET(FTS_STOP); errno = ENAMETOOLONG; return (NULL); } if (cderrno) { if (nlinks) { p->fts_info = FTS_NS; p->fts_errno = cderrno; } else p->fts_info = FTS_NSOK; p->fts_accpath = cur->fts_accpath; } else if (nlinks == 0 #ifdef DT_DIR || (nostat && dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) #endif ) { p->fts_accpath = ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; p->fts_info = FTS_NSOK; } else { /* Build a file name for fts_stat to stat. */ if (ISSET(FTS_NOCHDIR)) { p->fts_accpath = p->fts_path; memmove(cp, p->fts_name, p->fts_namelen + 1); } else p->fts_accpath = p->fts_name; /* Stat it. */ p->fts_info = fts_stat(sp, p, 0); /* Decrement link count if applicable. */ if (nlinks > 0 && (p->fts_info == FTS_D || p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) --nlinks; } /* We walk in directory order so "ls -f" doesn't get upset. */ p->fts_link = NULL; if (head == NULL) head = tail = p; else { tail->fts_link = p; tail = p; } ++nitems; } if (dirp) (void)closedir(dirp); /* * If realloc() changed the address of the path, adjust the * addresses for the rest of the tree and the dir list. */ if (doadjust) fts_padjust(sp, head); /* * If not changing directories, reset the path back to original * state. */ if (ISSET(FTS_NOCHDIR)) { if (len == sp->fts_pathlen || nitems == 0) --cp; *cp = '\0'; } /* * If descended after called from fts_children or after called from * fts_read and nothing found, get back. At the root level we use * the saved fd; if one of fts_open()'s arguments is a relative path * to an empty directory, we wind up here with no other way back. If * can't get back, we're done. */ if (descend && (type == BCHILD || !nitems) && (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) : fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { cur->fts_info = FTS_ERR; SET(FTS_STOP); return (NULL); } /* If didn't find anything, return NULL. */ if (!nitems) { if (type == BREAD) cur->fts_info = FTS_DP; return (NULL); } /* Sort the entries. */ if (sp->fts_compar && nitems > 1) head = fts_sort(sp, head, nitems); return (head); }
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(talloc_tos(), 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_delete_veto_files(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; 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; } smb_dname_full = synthetic_smb_fname( talloc_tos(), fullname, NULL, NULL); if (smb_dname_full == NULL) { errno = ENOMEM; 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; }
internal_function fts_build (FTSOBJ *sp, int type) { struct dirent *dp; FTSENTRY *p, *head; int nitems; FTSENTRY *cur, *tail; DIR *dirp; void *oldaddr; int cderrno, descend, len, level, nlinks, saved_errno, nostat, doadjust; size_t maxlen; char *cp; /* Set current node pointer. */ cur = sp->fts_cur; /* * Open the directory for reading. If this fails, we're done. * If being called from fts_read, set the fts_info field. */ #if defined FTS_WHITEOUT && 0 if (ISSET(FTS_WHITEOUT)) oflag = DTF_NODUP|DTF_REWIND; else oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; #else # define __opendir2(path, flag) __opendir(path) #endif if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { if (type == BREAD) { cur->fts_info = FTS_DNR; cur->fts_errno = errno; } return (NULL); } /* * Nlinks is the number of possible entries of type directory in the * directory if we're cheating on stat calls, 0 if we're not doing * any stat calls at all, -1 if we're doing stats on everything. */ if (type == BNAMES) { nlinks = 0; /* Be quiet about nostat, GCC. */ nostat = 0; } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); nostat = 1; } else { nlinks = -1; nostat = 0; } #ifdef notdef (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); #endif /* * If we're going to need to stat anything or we want to descend * and stay in the directory, chdir. If this fails we keep going, * but set a flag so we don't chdir after the post-order visit. * We won't be able to stat anything, but we can still return the * names themselves. Note, that since fts_read won't be able to * chdir into the directory, it will have to return different path * names than before, i.e. "a/b" instead of "b". Since the node * has already been visited in pre-order, have to wait until the * post-order visit to return the error. There is a special case * here, if there was nothing to stat then it's not an error to * not be able to stat. This is all fairly nasty. If a program * needed sorted entries or stat information, they had better be * checking FTS_NS on the returned nodes. */ cderrno = 0; if (nlinks || type == BREAD) { if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { if (nlinks && type == BREAD) cur->fts_errno = errno; cur->fts_flags |= FTS_DONTCHDIR; descend = 0; cderrno = errno; (void)__closedir(dirp); dirp = NULL; } else descend = 1; } else descend = 0; /* * Figure out the max file name length that can be stored in the * current path -- the inner loop allocates more path as necessary. * We really wouldn't have to do the maxlen calculations here, we * could do them in fts_read before returning the path, but it's a * lot easier here since the length is part of the dirent structure. * * If not changing directories set a pointer so that can just append * each new name into the path. */ len = NAPPEND(cur); if (ISSET(FTS_NOCHDIR)) { cp = sp->fts_path + len; *cp++ = '/'; } else { /* GCC, you're too verbose. */ cp = NULL; } len++; maxlen = sp->fts_pathlen - len; level = cur->fts_level + 1; /* Read the directory, attaching each entry to the `link' pointer. */ doadjust = 0; for (head = tail = NULL, nitems = 0; dirp && (dp = __readdir(dirp));) { if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL) goto mem1; if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */ oldaddr = sp->fts_path; if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) { /* * No more memory for path or structures. Save * errno, free up the current structure and the * structures already allocated. */ mem1: saved_errno = errno; free(p); fts_lfree(head); (void)__closedir(dirp); cur->fts_info = FTS_ERR; SET(FTS_STOP); __set_errno (saved_errno); return (NULL); } /* Did realloc() change the pointer? */ if (oldaddr != sp->fts_path) { doadjust = 1; if (ISSET(FTS_NOCHDIR)) cp = sp->fts_path + len; } maxlen = sp->fts_pathlen - len; } if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) { /* * In an FTSENT, fts_pathlen is a u_short so it is * possible to wraparound here. If we do, free up * the current structure and the structures already * allocated, then error out with ENAMETOOLONG. */ free(p); fts_lfree(head); (void)__closedir(dirp); cur->fts_info = FTS_ERR; SET(FTS_STOP); __set_errno (ENAMETOOLONG); return (NULL); } p->fts_level = level; p->fts_parent = sp->fts_cur; p->fts_pathlen = len + _D_EXACT_NAMLEN (dp); #if defined FTS_WHITEOUT && 0 if (dp->d_type == DT_WHT) p->fts_flags |= FTS_ISW; #endif /* Unreachable code. cderrno is only ever set to a nonnull value if dirp is closed at the same time. But then we cannot enter this loop. */ if (0 && cderrno) { if (nlinks) { p->fts_info = FTS_NS; p->fts_errno = cderrno; } else p->fts_info = FTS_NSOK; p->fts_accpath = cur->fts_accpath; } else if (nlinks == 0 || (nostat && dirent_not_directory(dp))) { p->fts_accpath = ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; p->fts_info = FTS_NSOK; } else { /* Build a file name for fts_stat to stat. */ if (ISSET(FTS_NOCHDIR)) { p->fts_accpath = p->fts_path; memmove(cp, p->fts_name, p->fts_namelen + 1); } else p->fts_accpath = p->fts_name; /* Stat it. */ p->fts_info = fts_stat(sp, p, 0); /* Decrement link count if applicable. */ if (nlinks > 0 && (p->fts_info == FTS_D || p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) --nlinks; } /* We walk in directory order so "ls -f" doesn't get upset. */ p->fts_link = NULL; if (head == NULL) head = tail = p; else { tail->fts_link = p; tail = p; } ++nitems; } if (dirp) (void)__closedir(dirp); /* * If realloc() changed the address of the path, adjust the * addresses for the rest of the tree and the dir list. */ if (doadjust) fts_padjust(sp, head); /* * If not changing directories, reset the path back to original * state. */ if (ISSET(FTS_NOCHDIR)) { if (len == sp->fts_pathlen || nitems == 0) --cp; *cp = '\0'; } /* * If descended after called from fts_children or after called from * fts_read and nothing found, get back. At the root level we use * the saved fd; if one of fts_open()'s arguments is a relative path * to an empty directory, we wind up here with no other way back. If * can't get back, we're done. */ if (descend && (type == BCHILD || !nitems) && (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) : fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { cur->fts_info = FTS_ERR; SET(FTS_STOP); fts_lfree(head); return (NULL); } /* If didn't find anything, return NULL. */ if (!nitems) { if (type == BREAD) cur->fts_info = FTS_DP; fts_lfree(head); return (NULL); } /* Sort the entries. */ if (sp->fts_compar && nitems > 1) head = fts_sort(sp, head, nitems); return (head); }
void read_cgblkio_stats(struct module *mod) { DIR *dir; char path[128], buffer[128]; FILE *iofd; struct dirent *ent; /* dirent handle */ struct blkio_info curr; n_group = 0; memset(blkio_groups, 0, CGBLKIO_GROUP_SIZE * MAX_GROUP); if ((dir = opendir(CGBLKIO_PATH)) == NULL) { return; } while ((ent = readdir(dir))) { if (ent->d_type == DT_DIR && !ISDOT(ent->d_name)) { memcpy(&blkio_groups[n_group].group_name, ent->d_name, strlen(ent->d_name) + 1); snprintf(path, 128, "%s/%s/blkio.io_merged", CGBLKIO_PATH, ent->d_name); if ((iofd = fopen(path, "r")) == NULL) { closedir(dir); return; } while (fgets(buffer, 128, iofd) != NULL) { if (sscanf(buffer, "%s %s %llu", curr.disk, curr.type, &curr.num) == 3) { if (!strncmp(curr.type, "Read", 4)) blkio_groups[n_group].rd_merges += curr.num; if (!strncmp(curr.type, "Write", 5)) blkio_groups[n_group].wr_merges += curr.num; } } if (fclose(iofd) < 0) { return; } snprintf(path, 128, "%s/%s/blkio.io_serviced", CGBLKIO_PATH, ent->d_name); if ((iofd = fopen(path, "r")) == NULL) { closedir(dir); return; } while (fgets(buffer, 128, iofd) != NULL) { if (sscanf(buffer, "%s %s %llu", curr.disk, curr.type, &curr.num) == 3) { if (!strncmp(curr.type, "Read", 4)) blkio_groups[n_group].rd_ios += curr.num; if (!strncmp(curr.type, "Write", 5)) blkio_groups[n_group].wr_ios += curr.num; } } if (fclose(iofd) < 0) { return; } snprintf(path, 128, "%s/%s/blkio.io_service_bytes", CGBLKIO_PATH, ent->d_name); if ((iofd = fopen(path, "r")) == NULL) { closedir(dir); return; } while (fgets(buffer, 128, iofd) != NULL) { if (sscanf(buffer, "%s %s %llu", curr.disk, curr.type, &curr.num) == 3) { if (!strncmp(curr.type, "Read", 4)) blkio_groups[n_group].rd_secs += curr.num / SECTOR_SIZE; if (!strncmp(curr.type, "Write", 5)) blkio_groups[n_group].wr_secs += curr.num / SECTOR_SIZE; } } if (fclose(iofd) < 0) { return; } snprintf(path, 128, "%s/%s/blkio.io_queued", CGBLKIO_PATH, ent->d_name); if ((iofd = fopen(path, "r")) == NULL) { closedir(dir); return; } while (fgets(buffer, 128, iofd) != NULL) { if (sscanf(buffer, "%s %s %llu", curr.disk, curr.type, &curr.num) == 3) { if (!strncmp(curr.type, "Read", 4)) blkio_groups[n_group].qusize += curr.num; if (!strncmp(curr.type, "Write", 5)) blkio_groups[n_group].qusize += curr.num; } } if (fclose(iofd) < 0) { return; } snprintf(path, 128, "%s/%s/blkio.io_service_time", CGBLKIO_PATH, ent->d_name); if ((iofd = fopen(path, "r")) == NULL) { closedir(dir); return; } while (fgets(buffer, 128, iofd) != NULL) { if (sscanf(buffer, "%s %s %llu", curr.disk, curr.type, &curr.num) == 3) { if (!strncmp(curr.type, "Read", 4)) blkio_groups[n_group].svctm += (unsigned long long)(curr.num / 1000000); //in ms if (!strncmp(curr.type, "Write", 5)) blkio_groups[n_group].svctm += (unsigned long long )(curr.num / 1000000); } } if (fclose(iofd) < 0) { return; } snprintf(path, 128, "%s/%s/blkio.io_wait_time", CGBLKIO_PATH, ent->d_name); if ((iofd = fopen(path, "r")) == NULL) { closedir(dir); return; } while (fgets(buffer, 128, iofd) != NULL) { if (sscanf(buffer, "%s %s %llu", curr.disk, curr.type, &curr.num) == 3) { if (!strncmp(curr.type, "Read", 4)) blkio_groups[n_group].wait += (unsigned long long)(curr.num / 1000000); if (!strncmp(curr.type, "Write", 5)) blkio_groups[n_group].wait += (unsigned long long)(curr.num / 1000000); } } if (fclose(iofd) < 0) { return; } n_group ++; } } closedir(dir); print_cgblkio_stats(mod); }
char * getcwd(char *pt, size_t size) { struct dirent *dp; DIR *dir = NULL; dev_t dev; ino_t ino; int first; char *bpt, *bup; struct stat s; dev_t root_dev; ino_t root_ino; size_t ptsize, upsize; int save_errno; char *ept, *eup, *up; /* * If no buffer specified by the user, allocate one as necessary. * If a buffer is specified, the size has to be non-zero. The path * is built from the end of the buffer backwards. */ if (pt) { ptsize = 0; if (!size) { errno = EINVAL; return (NULL); } ept = pt + size; } else { if ((pt = malloc(ptsize = MAXPATHLEN)) == NULL) return (NULL); ept = pt + ptsize; } bpt = ept - 1; *bpt = '\0'; /* * Allocate bytes for the string of "../"'s. * Should always be enough (it's 340 levels). If it's not, allocate * as necessary. Special * case the first stat, it's ".", not "..". */ if ((up = malloc(upsize = MAXPATHLEN)) == NULL) goto err; eup = up + upsize; bup = up; up[0] = '.'; up[1] = '\0'; /* Save root values, so know when to stop. */ if (stat("/", &s)) goto err; root_dev = s.st_dev; root_ino = s.st_ino; errno = 0; /* XXX readdir has no error return. */ for (first = 1;; first = 0) { /* Stat the current level. */ if (lstat(up, &s)) goto err; /* Save current node values. */ ino = s.st_ino; dev = s.st_dev; /* Check for reaching root. */ if (root_dev == dev && root_ino == ino) { *--bpt = '/'; /* * It's unclear that it's a requirement to copy the * path to the beginning of the buffer, but it's always * been that way and stuff would probably break. */ memmove(pt, bpt, ept - bpt); free(up); return (pt); } /* * Build pointer to the parent directory, allocating memory * as necessary. Max length is 3 for "../", the largest * possible component name, plus a trailing NUL. */ if (bup + 3 + MAXNAMLEN + 1 >= eup) { char *nup; if ((nup = realloc(up, upsize *= 2)) == NULL) goto err; bup = nup + (bup - up); up = nup; eup = up + upsize; } *bup++ = '.'; *bup++ = '.'; *bup = '\0'; /* Open and stat parent directory. */ if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) goto err; /* Add trailing slash for next directory. */ *bup++ = '/'; /* * If it's a mount point, have to stat each element because * the inode number in the directory is for the entry in the * parent directory, not the inode number of the mounted file. */ save_errno = 0; if (s.st_dev == dev) { for (;;) { if (!(dp = readdir(dir))) goto notfound; if (dp->d_fileno == ino) break; } } else for (;;) { if (!(dp = readdir(dir))) goto notfound; if (ISDOT(dp)) continue; memcpy(bup, dp->d_name, dp->d_namlen + 1); /* Save the first error for later. */ if (lstat(up, &s)) { if (!save_errno) save_errno = errno; errno = 0; continue; } if (s.st_dev == dev && s.st_ino == ino) break; } /* * Check for length of the current name, preceding slash, * leading slash. */ if (bpt - pt < dp->d_namlen + (first ? 1 : 2)) { size_t len; char *npt; if (!ptsize) { errno = ERANGE; goto err; } len = ept - bpt; if ((npt = realloc(pt, ptsize *= 2)) == NULL) goto err; bpt = npt + (bpt - pt); pt = npt; ept = pt + ptsize; memmove(ept - len, bpt, len); bpt = ept - len; } if (!first) *--bpt = '/'; bpt -= dp->d_namlen; memcpy(bpt, dp->d_name, dp->d_namlen); (void)closedir(dir); /* Truncate any file name. */ *bup = '\0'; } notfound: /* * If readdir set errno, use it, not any saved error; otherwise, * didn't find the current directory in its parent directory, set * errno to ENOENT. */ if (!errno) errno = save_errno ? save_errno : ENOENT; /* FALLTHROUGH */ err: save_errno = errno; if (ptsize) free(pt); free(up); if (dir) (void)closedir(dir); errno = save_errno; return (NULL); }
/* 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; }
/* * This is the tricky part -- do not casually change *anything* in here. The * idea is to build the linked list of entries that are used by yfts_children * and yfts_read. There are lots of special cases. * * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is * set and it's a physical walk (so that symbolic links can't be directories), * we can do things quickly. First, if it's a 4.4BSD file system, the type * of the file is in the directory entry. Otherwise, we assume that the number * of subdirectories in a node is equal to the number of links to the parent. * The former skips all stat calls. The latter skips stat calls in any leaf * directories and for any files after the subdirectories in the directory have * been found, cutting the stat calls by about 2/3. */ static FTSENT * fts_build(FTS * sp, int type) { struct dirent *dp; FTSENT *p, *head; int nitems; FTSENT *cur, *tail; #ifdef _win_ dird dirpd; struct DIR *dirp; #else DIR *dirp; #endif void *oldaddr; int cderrno, descend, len, level, maxlen, nlinks, saved_errno, nostat, doadjust; char *cp; /* Set current node pointer. */ cur = sp->fts_cur; /* * Open the directory for reading. If this fails, we're done. * If being called from yfts_read, set the fts_info field. */ #ifdef FTS_WHITEOUT if (ISSET(FTS_WHITEOUT)) oflag = DTF_NODUP|DTF_REWIND; else oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; #else #define __opendir2(path, flag) opendir(path) #endif if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { if (type == BREAD) { cur->fts_info = FTS_DNR; cur->fts_errno = errno; } return (NULL); } #ifdef _win_ dirpd = get_dird(cur->fts_accpath); #endif /* * Nlinks is the number of possible entries of type directory in the * directory if we're cheating on stat calls, 0 if we're not doing * any stat calls at all, -1 if we're doing stats on everything. */ if (type == BNAMES) { nlinks = 0; /* Be quiet about nostat, GCC. */ nostat = 0; } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); nostat = 1; } else { nlinks = -1; nostat = 0; } #ifdef notdef (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); #endif /* * If we're going to need to stat anything or we want to descend * and stay in the directory, chdir. If this fails we keep going, * but set a flag so we don't chdir after the post-order visit. * We won't be able to stat anything, but we can still return the * names themselves. Note, that since yfts_read won't be able to * chdir into the directory, it will have to return different path * names than before, i.e. "a/b" instead of "b". Since the node * has already been visited in pre-order, have to wait until the * post-order visit to return the error. There is a special case * here, if there was nothing to stat then it's not an error to * not be able to stat. This is all fairly nasty. If a program * needed sorted entries or stat information, they had better be * checking FTS_NS on the returned nodes. */ cderrno = 0; if (nlinks || type == BREAD) { #ifndef _win_ if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { #else if (fts_safe_changedir(sp, cur, -1, dirpd)) { #endif if (nlinks && type == BREAD) cur->fts_errno = errno; cur->fts_flags |= FTS_DONTCHDIR; descend = 0; cderrno = errno; (void)closedir(dirp); dirp = NULL; #ifdef _win_ close_dird(dirpd); dirpd = invalidDirD; #else UNUSED(invalidDirD); #endif } else descend = 1; } else descend = 0; /* * Figure out the max file name length that can be stored in the * current path -- the inner loop allocates more path as necessary. * We really wouldn't have to do the maxlen calculations here, we * could do them in yfts_read before returning the path, but it's a * lot easier here since the length is part of the dirent structure. * * If not changing directories set a pointer so that can just append * each new name into the path. */ len = NAPPEND(cur); if (ISSET(FTS_NOCHDIR)) { cp = sp->fts_path + len; *cp++ = LOCSLASH_C; } else { /* GCC, you're too verbose. */ cp = NULL; } len++; maxlen = sp->fts_pathlen - len; level = cur->fts_level + 1; /* Read the directory, attaching each entry to the `link' pointer. */ doadjust = 0; //to ensure enough buffer TTempBuf dpe; for (head = tail = NULL, nitems = 0; dirp && (dp = yreaddir(dirp, (struct dirent*)dpe.Data())) != 0;) { if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; if ((p = fts_alloc(sp, dp->d_name, (int)strlen(dp->d_name))) == NULL) goto mem1; if (strlen(dp->d_name) >= (size_t)maxlen) { /* include space for NUL */ oldaddr = sp->fts_path; if (fts_palloc(sp, strlen(dp->d_name) +len + 1)) { /* * No more memory for path or structures. Save * errno, free up the current structure and the * structures already allocated. */ mem1: saved_errno = errno; if (p) free(p); fts_lfree(head); (void)closedir(dirp); #ifdef _win_ close_dird(dirpd); #endif cur->fts_info = FTS_ERR; SET(FTS_STOP); errno = saved_errno; return (NULL); } /* Did realloc() change the pointer? */ if (oldaddr != sp->fts_path) { doadjust = 1; if (ISSET(FTS_NOCHDIR)) cp = sp->fts_path + len; } maxlen = sp->fts_pathlen - len; } if (len + strlen(dp->d_name) >= USHRT_MAX) { /* * In an FTSENT, fts_pathlen is a u_short so it is * possible to wraparound here. If we do, free up * the current structure and the structures already * allocated, then error out with ENAMETOOLONG. */ free(p); fts_lfree(head); (void)closedir(dirp); #ifdef _win_ close_dird(dirpd); #endif cur->fts_info = FTS_ERR; SET(FTS_STOP); errno = ENAMETOOLONG; return (NULL); } p->fts_level = (short)level; p->fts_parent = sp->fts_cur; p->fts_pathlen = u_short(len + strlen(dp->d_name)); #ifdef FTS_WHITEOUT if (dp->d_type == DT_WHT) p->fts_flags |= FTS_ISW; #endif if (cderrno) { if (nlinks) { p->fts_info = FTS_NS; p->fts_errno = cderrno; } else p->fts_info = FTS_NSOK; p->fts_accpath = cur->fts_accpath; } else if (nlinks == 0 #ifdef DT_DIR || (nostat && dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) #endif ) { p->fts_accpath = ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; p->fts_info = FTS_NSOK; } else { /* Build a file name for fts_stat to stat. */ if (ISSET(FTS_NOCHDIR)) { p->fts_accpath = p->fts_path; memmove((void*)cp, (void*)p->fts_name, (size_t)p->fts_namelen + 1); } else p->fts_accpath = p->fts_name; /* Stat it. */ p->fts_info = fts_stat(sp, p, 0); /* Decrement link count if applicable. */ if (nlinks > 0 && (p->fts_info == FTS_D || p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) --nlinks; } /* We walk in directory order so "ls -f" doesn't get upset. */ p->fts_link = NULL; if (head == NULL) head = tail = p; else { tail->fts_link = p; tail = p; } ++nitems; } if (dirp) { (void)closedir(dirp); #ifdef _win_ close_dird(dirpd); #endif } /* * If realloc() changed the address of the path, adjust the * addresses for the rest of the tree and the dir list. */ if (doadjust) fts_padjust(sp); /* * If not changing directories, reset the path back to original * state. */ if (ISSET(FTS_NOCHDIR)) { if (len == sp->fts_pathlen || nitems == 0) --cp; *cp = '\0'; } /* * If descended after called from yfts_children or after called from * yfts_read and nothing found, get back. At the root level we use * the saved fd; if one of yfts_open()'s arguments is a relative path * to an empty directory, we wind up here with no other way back. If * can't get back, we're done. */ if (descend && (type == BCHILD || !nitems) && (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) : fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { cur->fts_info = FTS_ERR; SET(FTS_STOP); return (NULL); } /* If didn't find anything, return NULL. */ if (!nitems) { if (type == BREAD) cur->fts_info = FTS_DP; return (NULL); } /* Sort the entries. */ if (sp->fts_compar && nitems > 1) head = fts_sort(sp, head, nitems); return (head); } static u_short fts_stat(FTS * sp, FTSENT * p, int follow) { dev_t dev; ino_t ino; struct stat *sbp, sb; int saved_errno; /* If user needs stat info, stat buffer already allocated. */ sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; #ifdef FTS_WHITEOUT /* check for whiteout */ if (p->fts_flags & FTS_ISW) { if (sbp != &sb) { memset(sbp, '\0', sizeof (*sbp)); sbp->st_mode = S_IFWHT; } return (FTS_W); } #endif /* * If doing a logical walk, or application requested FTS_FOLLOW, do * a stat(2). If that fails, check for a non-existent symlink. If * fail, set the errno from the stat call. */ if (ISSET(FTS_LOGICAL) || follow) { if (stat(p->fts_accpath, sbp)) { saved_errno = errno; if (!lstat(p->fts_accpath, sbp)) { errno = 0; return (FTS_SLNONE); } p->fts_errno = saved_errno; memset(sbp, 0, sizeof(struct stat)); return (FTS_NS); } } else if (lstat(p->fts_accpath, sbp)) { p->fts_errno = errno; memset(sbp, 0, sizeof(struct stat)); return (FTS_NS); } if (S_ISDIR(sbp->st_mode)) { /* * Set the device/inode. Used to find cycles and check for * crossing mount points. Also remember the link count, used * in fts_build to limit the number of stat calls. It is * understood that these fields are only referenced if fts_info * is set to FTS_D. */ dev = p->fts_dev = sbp->st_dev; ino = p->fts_ino = sbp->st_ino; p->fts_nlink = sbp->st_nlink; const char* fts_name_x = p->fts_name; if (ISDOT(fts_name_x)) return (FTS_DOT); /* * Cycle detection is done by brute force when the directory * is first encountered. If the tree gets deep enough or the * number of symbolic links to directories is high enough, * something faster might be worthwhile. */ //There is no way to detect symlink or mount cycles on win32 #ifndef _win_ FTSENT *t; for (t = p->fts_parent; t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) if (ino == t->fts_ino && dev == t->fts_dev) { p->fts_cycle = t; return (FTS_DC); } #endif /*_win_*/ return (FTS_D); } if (S_ISLNK(sbp->st_mode)) return (FTS_SL); if (S_ISREG(sbp->st_mode)) return (FTS_F); return (FTS_DEFAULT); }
static u_short internal_function fts_stat (FTSOBJ *sp, FTSENTRY *p, int follow) { FTSENTRY *t; dev_t dev; INO_T ino; struct STAT *sbp, sb; int saved_errno; /* If user needs stat info, stat buffer already allocated. */ sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; #if defined FTS_WHITEOUT && 0 /* check for whiteout */ if (p->fts_flags & FTS_ISW) { if (sbp != &sb) { memset(sbp, '\0', sizeof (*sbp)); sbp->st_mode = S_IFWHT; } return (FTS_W); } #endif /* * If doing a logical walk, or application requested FTS_FOLLOW, do * a stat(2). If that fails, check for a non-existent symlink. If * fail, set the errno from the stat call. */ if (ISSET(FTS_LOGICAL) || follow) { if (STAT(p->fts_accpath, sbp)) { saved_errno = errno; if (!LSTAT(p->fts_accpath, sbp)) { __set_errno (0); return (FTS_SLNONE); } p->fts_errno = saved_errno; goto err; } } else if (LSTAT(p->fts_accpath, sbp)) { p->fts_errno = errno; err: memset(sbp, 0, sizeof(struct STAT)); return (FTS_NS); } if (S_ISDIR(sbp->st_mode)) { /* * Set the device/inode. Used to find cycles and check for * crossing mount points. Also remember the link count, used * in fts_build to limit the number of stat calls. It is * understood that these fields are only referenced if fts_info * is set to FTS_D. */ dev = p->fts_dev = sbp->st_dev; ino = p->fts_ino = sbp->st_ino; p->fts_nlink = sbp->st_nlink; if (ISDOT(p->fts_name)) return (FTS_DOT); /* * Cycle detection is done by brute force when the directory * is first encountered. If the tree gets deep enough or the * number of symbolic links to directories is high enough, * something faster might be worthwhile. */ for (t = p->fts_parent; t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) if (ino == t->fts_ino && dev == t->fts_dev) { p->fts_cycle = t; return (FTS_DC); } return (FTS_D); } if (S_ISLNK(sbp->st_mode)) return (FTS_SL); if (S_ISREG(sbp->st_mode)) return (FTS_F); return (FTS_DEFAULT); }
/* * call back action function for dent_walk */ static uint8_t print_dent_act(FS_INFO * fs, FS_DENT * fs_dent, int flags, void *ptr) { /* only print dirs if FLS_DIR is set and only print everything ** else if FLS_FILE is set (or we aren't sure what it is) */ if (((localflags & FLS_DIR) && ((fs_dent->fsi) && ((fs_dent->fsi->mode & FS_INODE_FMT) == FS_INODE_DIR))) || ((localflags & FLS_FILE) && (((fs_dent->fsi) && ((fs_dent->fsi->mode & FS_INODE_FMT) != FS_INODE_DIR)) || (!fs_dent->fsi)))) { /* Make a special case for NTFS so we can identify all of the * alternate data streams! */ if (((fs->ftype & FSMASK) == NTFS_TYPE) && (fs_dent->fsi)) { FS_DATA *fs_data = fs_dent->fsi->attr; uint8_t printed = 0; while ((fs_data) && (fs_data->flags & FS_DATA_INUSE)) { if (fs_data->type == NTFS_ATYPE_DATA) { mode_t mode = fs_dent->fsi->mode; uint8_t ent_type = fs_dent->ent_type; printed = 1; /* * A directory can have a Data stream, in which * case it would be printed with modes of a * directory, although it is really a file * So, to avoid confusion we will set the modes * to a file so it is printed that way. The * entry for the directory itself will still be * printed as a directory */ if ((fs_dent->fsi->mode & FS_INODE_FMT) == FS_INODE_DIR) { /* we don't want to print the ..:blah stream if * the -a flag was not given */ if ((fs_dent->name[0] == '.') && (fs_dent->name[1]) && (fs_dent->name[2] == '\0') && ((localflags & FLS_DOT) == 0)) { fs_data = fs_data->next; continue; } fs_dent->fsi->mode &= ~FS_INODE_FMT; fs_dent->fsi->mode |= FS_INODE_REG; fs_dent->ent_type = FS_DENT_REG; } printit(fs, fs_dent, flags, fs_data); fs_dent->fsi->mode = mode; fs_dent->ent_type = ent_type; } else if (fs_data->type == NTFS_ATYPE_IDXROOT) { printed = 1; /* If it is . or .. only print it if the flags say so, * we continue with other streams though in case the * directory has a data stream */ if (!((ISDOT(fs_dent->name)) && ((localflags & FLS_DOT) == 0))) printit(fs, fs_dent, flags, fs_data); } fs_data = fs_data->next; } /* A user reported that an allocated file had the standard * attributes, but no $Data. We should print something */ if (printed == 0) { printit(fs, fs_dent, flags, NULL); } } else { /* skip it if it is . or .. and we don't want them */ if (!((ISDOT(fs_dent->name)) && ((localflags & FLS_DOT) == 0))) printit(fs, fs_dent, flags, NULL); } } return WALK_CONT; }