int makeflow_archive_copy_preserved_files(struct archive_instance *a, struct batch_task *t, char *task_path ) { struct batch_file *f; struct stat buf; struct list_cursor *cur = list_cursor_create(t->output_files); // Iterate through output files for(list_seek(cur, 0); list_get(cur, (void**)&f); list_next(cur)) { char *file_name = xxstrdup(f->outer_name); debug(D_MAKEFLOW_HOOK,"Trying to copy file to %s",file_name); char *file_to_check = xxstrdup(file_name); //Check to see if the directory was copied as an empty file/incorrectly stat(dirname(file_to_check),&buf); if(S_ISREG(buf.st_mode)){ debug(D_MAKEFLOW,"Removing empty file in the place of directory name %s",file_to_check); char *dirEmpty = string_format("rm -rf %s",file_to_check); system(dirEmpty); free(dirEmpty); } free(file_to_check); // Gets path of output file char *output_file_path = string_format("%s/output_files/%s",task_path,basename(file_name)); char *directory_name = xxstrdup(file_name); debug(D_MAKEFLOW_HOOK,"Creating directory %s",dirname(directory_name)); if(strcmp(directory_name,file_name) != 0){ //Create the upper level directory to copy the output files into if necessary if (!create_dir(directory_name, 0777) && errno != EEXIST){ debug(D_ERROR|D_MAKEFLOW_HOOK,"Failed to create directory %s",directory_name); free(directory_name); free(output_file_path); free(file_name); return 1; } } free(directory_name); // Copy output file or directory over to specified location if(path_is_dir(output_file_path) != 1){ int success = copy_file_to_file(output_file_path, file_name); free(output_file_path); free(file_name); if (!success) { list_cursor_destroy(cur); debug(D_ERROR|D_MAKEFLOW_HOOK,"Failed to copy output file %s to %s\n", output_file_path, file_name); return 1; } } else{ if(copy_dir(output_file_path, file_name) != 0){ list_cursor_destroy(cur); debug(D_ERROR|D_MAKEFLOW_HOOK,"Failed to copy output file %s to %s\n", output_file_path, file_name); free(output_file_path); free(file_name); return 1; } free(output_file_path); free(file_name); } } list_cursor_destroy(cur); return 0; }
static int lookup_umount_fs(struct libmnt_context *cxt) { int rc, loopdev = 0; const char *tgt; struct libmnt_table *mtab = NULL; struct libmnt_fs *fs; assert(cxt); assert(cxt->fs); DBG(CXT, mnt_debug_h(cxt, "umount: lookup FS")); tgt = mnt_fs_get_target(cxt->fs); if (!tgt) { DBG(CXT, mnt_debug_h(cxt, "umount: undefined target")); return -EINVAL; } rc = mnt_context_get_mtab(cxt, &mtab); if (rc) { DBG(CXT, mnt_debug_h(cxt, "umount: failed to read mtab")); return rc; } try_loopdev: fs = mnt_table_find_target(mtab, tgt, MNT_ITER_BACKWARD); if (!fs && mnt_context_is_swapmatch(cxt)) { /* maybe the option is source rather than target (mountpoint) */ fs = mnt_table_find_source(mtab, tgt, MNT_ITER_BACKWARD); if (fs) { struct libmnt_fs *fs1 = mnt_table_find_target(mtab, mnt_fs_get_target(fs), MNT_ITER_BACKWARD); if (!fs1) { DBG(CXT, mnt_debug_h(cxt, "mtab is broken?!?!")); return -EINVAL; } if (fs != fs1) { /* Something was stacked over `file' on the * same mount point. */ DBG(CXT, mnt_debug_h(cxt, "umount: %s: %s is mounted " "over it on the same point", tgt, mnt_fs_get_source(fs1))); return -EINVAL; } } } if (!fs && !loopdev) { /* * Maybe target is /path/file.img, try to convert to /dev/loopN */ struct stat st; if (stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) { char *dev = NULL; int count = loopdev_count_by_backing_file(tgt, &dev); if (count == 1) { DBG(CXT, mnt_debug_h(cxt, "umount: %s --> %s (retry)", tgt, dev)); mnt_fs_set_source(cxt->fs, tgt); mnt_fs_set_target(cxt->fs, dev); free(dev); tgt = mnt_fs_get_target(cxt->fs); loopdev = 1; /* to avoid endless loop */ goto try_loopdev; } else if (count > 1) DBG(CXT, mnt_debug_h(cxt, "umount: warning: %s is associated " "with more than one loodev", tgt)); } } if (!fs) { DBG(CXT, mnt_debug_h(cxt, "umount: cannot find %s in mtab", tgt)); return 0; } if (fs != cxt->fs) { /* copy from mtab to our FS description */ mnt_fs_set_source(cxt->fs, NULL); mnt_fs_set_target(cxt->fs, NULL); if (!mnt_copy_fs(cxt->fs, fs)) { DBG(CXT, mnt_debug_h(cxt, "umount: failed to copy FS")); return -errno; } DBG(CXT, mnt_debug_h(cxt, "umount: mtab applied")); } cxt->flags |= MNT_FL_TAB_APPLIED; return rc; }
int is_regular_file(const char *path) { struct stat path_stat; stat(path, &path_stat); return S_ISREG(path_stat.st_mode); }
static void filegen_open( FILEGEN * gen, uint32_t stamp, const time_t * pivot ) { char *savename; /* temp store for name collision handling */ char *fullname; /* name with any designation extension */ char *filename; /* name without designation extension */ char *suffix; /* where to print suffix extension */ u_int len, suflen; FILE *fp; struct calendar cal; struct isodate iso; /* get basic filename in buffer, leave room for extensions */ len = strlen(gen->dir) + strlen(gen->fname) + 65; filename = emalloc(len); fullname = emalloc(len); savename = NULL; snprintf(filename, len, "%s%s", gen->dir, gen->fname); /* where to place suffix */ suflen = strlcpy(fullname, filename, len); suffix = fullname + suflen; suflen = len - suflen; /* last octet of fullname set to '\0' for truncation check */ fullname[len - 1] = '\0'; switch (gen->type) { default: msyslog(LOG_ERR, "unsupported file generations type %d for " "\"%s\" - reverting to FILEGEN_NONE", gen->type, filename); gen->type = FILEGEN_NONE; break; case FILEGEN_NONE: /* no suffix, all set */ break; case FILEGEN_PID: gen->id_lo = getpid(); gen->id_hi = 0; snprintf(suffix, suflen, "%c#%ld", SUFFIX_SEP, gen->id_lo); break; case FILEGEN_DAY: /* * You can argue here in favor of using MJD, but I * would assume it to be easier for humans to interpret * dates in a format they are used to in everyday life. */ ntpcal_ntp_to_date(&cal, stamp, pivot); snprintf(suffix, suflen, "%c%04d%02d%02d", SUFFIX_SEP, cal.year, cal.month, cal.monthday); cal.hour = cal.minute = cal.second = 0; gen->id_lo = ntpcal_date_to_ntp(&cal); gen->id_hi = (uint32_t)(gen->id_lo + SECSPERDAY); break; case FILEGEN_WEEK: isocal_ntp_to_date(&iso, stamp, pivot); snprintf(suffix, suflen, "%c%04dw%02d", SUFFIX_SEP, iso.year, iso.week); iso.hour = iso.minute = iso.second = 0; iso.weekday = 1; gen->id_lo = isocal_date_to_ntp(&iso); gen->id_hi = (uint32_t)(gen->id_lo + 7 * SECSPERDAY); break; case FILEGEN_MONTH: ntpcal_ntp_to_date(&cal, stamp, pivot); snprintf(suffix, suflen, "%c%04d%02d", SUFFIX_SEP, cal.year, cal.month); cal.hour = cal.minute = cal.second = 0; cal.monthday = 1; gen->id_lo = ntpcal_date_to_ntp(&cal); cal.month++; gen->id_hi = ntpcal_date_to_ntp(&cal); break; case FILEGEN_YEAR: ntpcal_ntp_to_date(&cal, stamp, pivot); snprintf(suffix, suflen, "%c%04d", SUFFIX_SEP, cal.year); cal.hour = cal.minute = cal.second = 0; cal.month = cal.monthday = 1; gen->id_lo = ntpcal_date_to_ntp(&cal); cal.year++; gen->id_hi = ntpcal_date_to_ntp(&cal); break; case FILEGEN_AGE: gen->id_lo = current_time - (current_time % SECSPERDAY); gen->id_hi = gen->id_lo + SECSPERDAY; snprintf(suffix, suflen, "%ca%08ld", SUFFIX_SEP, gen->id_lo); } /* check possible truncation */ if ('\0' != fullname[len - 1]) { fullname[len - 1] = '\0'; msyslog(LOG_ERR, "logfile name truncated: \"%s\"", fullname); } if (FILEGEN_NONE != gen->type) { /* * check for existence of a file with name 'basename' * as we disallow such a file * if FGEN_FLAG_LINK is set create a link */ struct stat stats; /* * try to resolve name collisions */ static u_long conflicts = 0; #ifndef S_ISREG #define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG) #endif if (stat(filename, &stats) == 0) { /* Hm, file exists... */ if (S_ISREG(stats.st_mode)) { if (stats.st_nlink <= 1) { /* * Oh, it is not linked - try to save it */ savename = emalloc(len); snprintf(savename, len, "%s%c%dC%lu", filename, SUFFIX_SEP, (int)getpid(), conflicts++); if (rename(filename, savename) != 0) msyslog(LOG_ERR, "couldn't save %s: %m", filename); free(savename); } else { /* * there is at least a second link to * this file. * just remove the conflicting one */ /* coverity[toctou] */ if (unlink(filename) != 0) msyslog(LOG_ERR, "couldn't unlink %s: %m", filename); } } else { /* * Ehh? Not a regular file ?? strange !!!! */ msyslog(LOG_ERR, "expected regular file for %s " "(found mode 0%lo)", filename, (unsigned long)stats.st_mode); } } else { /* * stat(..) failed, but it is absolutely correct for * 'basename' not to exist */ if (ENOENT != errno) msyslog(LOG_ERR, "stat(%s) failed: %m", filename); } } /* * now, try to open new file generation... */ DPRINTF(4, ("opening filegen (type=%d/stamp=%u) \"%s\"\n", gen->type, stamp, fullname)); fp = fopen(fullname, "a"); if (NULL == fp) { /* open failed -- keep previous state * * If the file was open before keep the previous generation. * This will cause output to end up in the 'wrong' file, * but I think this is still better than losing output * * ignore errors due to missing directories */ if (ENOENT != errno) msyslog(LOG_ERR, "can't open %s: %m", fullname); } else { if (NULL != gen->fp) { fclose(gen->fp); gen->fp = NULL; } gen->fp = fp; if (gen->flag & FGEN_FLAG_LINK) { /* * need to link file to basename * have to use hardlink for now as I want to allow * gen->basename spanning directory levels * this would make it more complex to get the correct * fullname for symlink * * Ok, it would just mean taking the part following * the last '/' in the name.... Should add it later.... */ /* Windows NT does not support file links -Greg Schueman 1/18/97 */ #if defined(SYS_WINNT) SetLastError(0); /* On WinNT, don't support FGEN_FLAG_LINK */ #else /* not WINNT ; DO THE LINK) */ if (link(fullname, filename) != 0) if (EEXIST != errno) msyslog(LOG_ERR, "can't link(%s, %s): %m", fullname, filename); #endif /* SYS_WINNT */ } /* flags & FGEN_FLAG_LINK */ } /* else fp == NULL */ free(filename); free(fullname); return; }
uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname) { uint32_t result = 0; bool offline; DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname))); if (!VALID_STAT(smb_fname->st)) { return 0; } /* First do any modifications that depend on the path name. */ /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { const char *p = strrchr_m(smb_fname->base_name,'/'); if (p) { p++; } else { p = smb_fname->base_name; } /* Only . and .. are not hidden. */ if (p[0] == '.' && !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0'))) { result |= FILE_ATTRIBUTE_HIDDEN; } } /* Get the DOS attributes from an EA by preference. */ if (!get_ea_dos_attribute(conn, smb_fname, &result)) { result |= dos_mode_from_sbuf(conn, smb_fname); } offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st); if (S_ISREG(smb_fname->st.st_ex_mode) && offline) { result |= FILE_ATTRIBUTE_OFFLINE; } if (conn->fs_capabilities & FILE_FILE_COMPRESSION) { bool compressed = false; NTSTATUS status = dos_mode_check_compressed(conn, smb_fname, &compressed); if (NT_STATUS_IS_OK(status) && compressed) { result |= FILE_ATTRIBUTE_COMPRESSED; } } /* Optimization : Only call is_hidden_path if it's not already hidden. */ if (!(result & FILE_ATTRIBUTE_HIDDEN) && IS_HIDDEN_PATH(conn, smb_fname->base_name)) { result |= FILE_ATTRIBUTE_HIDDEN; } if (result == 0) { result = FILE_ATTRIBUTE_NORMAL; } result = filter_mode_by_protocol(result); dos_mode_debug_print(__func__, result); return result; }
/* * rm_overwrite -- * Overwrite the file 3 times with varying bit patterns. * * XXX * This is a cheap way to *really* delete files. Note that only regular * files are deleted, directories (and therefore names) will remain. * Also, this assumes a fixed-block file system (like FFS, or a V7 or a * System V file system). In a logging or COW file system, you'll have to * have kernel support. */ static int rm_overwrite(const char *file, struct stat *sbp) { struct stat sb, sb2; struct statfs fsb; off_t len; int bsize, fd, wlen; char *buf = NULL; fd = -1; if (sbp == NULL) { if (lstat(file, &sb)) goto err; sbp = &sb; } if (!S_ISREG(sbp->st_mode)) return (1); if (sbp->st_nlink > 1 && !fflag) { warnx("%s (inode %ju): not overwritten due to multiple links", file, (uintmax_t)sbp->st_ino); return (0); } if ((fd = open(file, O_WRONLY|O_NONBLOCK|O_NOFOLLOW, 0)) == -1) goto err; if (fstat(fd, &sb2)) goto err; if (sb2.st_dev != sbp->st_dev || sb2.st_ino != sbp->st_ino || !S_ISREG(sb2.st_mode)) { errno = EPERM; goto err; } if (fstatfs(fd, &fsb) == -1) goto err; bsize = MAX(fsb.f_iosize, 1024); if ((buf = malloc(bsize)) == NULL) err(1, "%s: malloc", file); #define PASS(byte) { \ memset(buf, byte, bsize); \ for (len = sbp->st_size; len > 0; len -= wlen) { \ wlen = len < bsize ? len : bsize; \ if (write(fd, buf, wlen) != wlen) \ goto err; \ } \ } PASS(0xff); if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) goto err; PASS(0x00); if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) goto err; PASS(0xff); if (!fsync(fd) && !close(fd)) { free(buf); return (1); } err: eval = 1; if (buf) free(buf); if (fd != -1) close(fd); warn("%s", file); return (0); }
void zro_load (mstr *str) { unsigned toktyp, status; mstr tok; char *lp, *top; zro_ent array[ZRO_MAX_ENTS], *op; int oi, si, total_ents; struct stat outbuf; int stat_res; char tranbuf[MAX_FBUFF + 1]; parse_blk pblk; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; memset(array, 0, SIZEOF(array)); lp = str->addr; top = lp + str->len; while (lp < top && *lp == ZRO_DEL) /* Bypass leading blanks */ lp++; array[0].type = ZRO_TYPE_COUNT; array[0].count = 0; memset(&pblk, 0, SIZEOF(pblk)); pblk.buffer = tranbuf; GETTOK; if (toktyp == ZRO_EOL) { /* Null string - set default */ array[0].count = 1; array[1].type = ZRO_TYPE_OBJECT; array[1].str.len = 0; array[2].type = ZRO_TYPE_COUNT; array[2].count = 1; array[3].type = ZRO_TYPE_SOURCE; array[3].str.len = 0; si = 4; } else { /* String supplied - parse it */ for (oi = 1;;) { if (toktyp != ZRO_IDN) rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FSEXP); if (oi + 1 >= ZRO_MAX_ENTS) rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_MAXARGCNT, 1, ZRO_MAX_ENTS); if (tok.len >= SIZEOF(tranbuf)) rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr); pblk.buff_size = MAX_FBUFF; pblk.fnb = 0; status = parse_file(&tok, &pblk); if (!(status & 1)) rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr, status); tranbuf[pblk.b_esl] = 0; STAT_FILE(tranbuf, &outbuf, stat_res); if (-1 == stat_res) rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr, errno); if (S_ISREG(outbuf.st_mode)) { /* regular file - a shared library file */ array[oi].shrlib = zro_shlibs_find(tranbuf); array[oi].type = ZRO_TYPE_OBJLIB; si = oi + 1; } else { if (!S_ISDIR(outbuf.st_mode)) rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_INVZROENT, 2, tok.len, tok.addr); array[oi].type = ZRO_TYPE_OBJECT; array[oi + 1].type = ZRO_TYPE_COUNT; si = oi + 2; } array[0].count++; array[oi].str = tok; GETTOK; if (toktyp == ZRO_LBR) { if (array[oi].type == ZRO_TYPE_OBJLIB) rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_NOLBRSRC); GETTOK; if (toktyp == ZRO_DEL) GETTOK; if (toktyp != ZRO_IDN && toktyp != ZRO_RBR) rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_QUALEXP); array[oi + 1].count = 0; for (;;) { if (toktyp == ZRO_RBR) break; if (toktyp != ZRO_IDN) rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FSEXP); if (si >= ZRO_MAX_ENTS) rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_MAXARGCNT, 1, ZRO_MAX_ENTS); if (tok.len >= SIZEOF(tranbuf)) rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr); pblk.buff_size = MAX_FBUFF; pblk.fnb = 0; status = parse_file(&tok, &pblk); if (!(status & 1)) rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr, status); tranbuf[pblk.b_esl] = 0; STAT_FILE(tranbuf, &outbuf, stat_res); if (-1 == stat_res) rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr, errno); if (!S_ISDIR(outbuf.st_mode)) rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_DIRONLY, 2, tok.len, tok.addr); array[oi + 1].count++; array[si].type = ZRO_TYPE_SOURCE; array[si].str = tok; si++; GETTOK; if (toktyp == ZRO_DEL) GETTOK; } GETTOK; } else { if ((array[oi].type != ZRO_TYPE_OBJLIB) && (toktyp == ZRO_DEL || toktyp == ZRO_EOL)) { if (si >= ZRO_MAX_ENTS) rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_MAXARGCNT, 1, ZRO_MAX_ENTS); array[oi + 1].count = 1; array[si] = array[oi]; array[si].type = ZRO_TYPE_SOURCE; si++; } } if (toktyp == ZRO_EOL) break; if (toktyp == ZRO_DEL) GETTOK; else rts_error(VARLSTCNT(4) ERR_ZROSYNTAX, 2, str->len, str->addr); oi = si; } } total_ents = si; if (TREF(zro_root)) { assert((TREF(zro_root))->type == ZRO_TYPE_COUNT); oi = (TREF(zro_root))->count; assert(oi); for (op = TREF(zro_root) + 1; oi-- > 0; ) { /* release space held by translated entries */ assert(op->type == ZRO_TYPE_OBJECT || op->type == ZRO_TYPE_OBJLIB); if (op->str.len) free(op->str.addr); if ((op++)->type == ZRO_TYPE_OBJLIB) continue; /* i.e. no sources for shared library */ assert(op->type == ZRO_TYPE_COUNT); si = (op++)->count; for ( ; si-- > 0; op++) { assert(op->type == ZRO_TYPE_SOURCE); if (op->str.len) free(op->str.addr); } } free(TREF(zro_root)); } TREF(zro_root) = (zro_ent *)malloc(total_ents * SIZEOF(zro_ent)); memcpy((uchar_ptr_t)TREF(zro_root), (uchar_ptr_t)array, total_ents * SIZEOF(zro_ent)); assert((TREF(zro_root))->type == ZRO_TYPE_COUNT); oi = (TREF(zro_root))->count; assert(oi); for (op = TREF(zro_root) + 1; oi-- > 0; ) { assert(op->type == ZRO_TYPE_OBJECT || op->type == ZRO_TYPE_OBJLIB); if (op->str.len) { pblk.buff_size = MAX_FBUFF; pblk.fnb = 0; status = parse_file(&op->str, &pblk); if (!(status & 1)) rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, op->str.len, op->str.addr, status); op->str.addr = (char *)malloc(pblk.b_esl); op->str.len = pblk.b_esl; memcpy(op->str.addr, pblk.buffer, pblk.b_esl); } if ((op++)->type == ZRO_TYPE_OBJLIB) continue; assert(op->type == ZRO_TYPE_COUNT); si = (op++)->count; for ( ; si-- > 0; op++) { assert(op->type == ZRO_TYPE_SOURCE); if (op->str.len) { pblk.buff_size = MAX_FBUFF; pblk.fnb = 0; status = parse_file(&op->str, &pblk); if (!(status & 1)) rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, op->str.len, op->str.addr, status); op->str.addr = (char *)malloc(pblk.b_esl); op->str.len = pblk.b_esl; memcpy(op->str.addr, pblk.buffer, pblk.b_esl); } } } }
/* * Save one file into the tar file. * If the file is a directory, then this will recursively save all of * the files and directories within the directory. The seeLinks * flag indicates whether or not we want to see symbolic links as * they really are, instead of blindly following them. */ static void saveFile(const char * fileName, BOOL seeLinks) { int status; int mode; struct stat statbuf; if (verboseFlag) printf("a %s\n", fileName); /* * Check that the file name will fit in the header. */ if (strlen(fileName) >= TAR_NAME_SIZE) { fprintf(stderr, "%s: File name is too long\n", fileName); return; } /* * Find out about the file. */ #ifdef S_ISLNK if (seeLinks) status = lstat(fileName, &statbuf); else #endif status = stat(fileName, &statbuf); if (status < 0) { perror(fileName); return; } /* * Make sure we aren't trying to save our file into itself. */ if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) { fprintf(stderr, "Skipping saving of archive file itself\n"); return; } /* * Check the type of file. */ mode = statbuf.st_mode; if (S_ISDIR(mode)) { saveDirectory(fileName, &statbuf); return; } if (S_ISREG(mode)) { saveRegularFile(fileName, &statbuf); return; } /* * The file is a strange type of file, ignore it. */ fprintf(stderr, "%s: not a directory or regular file\n", fileName); }
int ELFNAME(nlist)(int fd, struct nlist *list) { struct nlist *p; caddr_t strtab; Elf_Off symoff = 0, symstroff = 0; Elf_Word symsize = 0; long symstrsize = 0; Elf_Sword nent, cc, i; Elf_Sym sbuf[1024]; Elf_Sym *s; Elf_Ehdr ehdr; Elf_Shdr *shdr = NULL; size_t shdr_size; struct stat st; int usemalloc = 0; size_t left, len; /* Make sure obj is OK */ if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) || !ELFNAME(__elf_is_okay__)(&ehdr) || fstat(fd, &st) < 0) return (-1); /* calculate section header table size */ shdr_size = ehdr.e_shentsize * ehdr.e_shnum; /* Make sure it's not too big to mmap */ if (SIZE_MAX - ehdr.e_shoff < shdr_size || S_ISREG(st.st_mode) && ehdr.e_shoff + shdr_size > st.st_size) { errno = EFBIG; return (-1); } /* mmap section header table */ shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ, MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff); if (shdr == MAP_FAILED) { usemalloc = 1; if ((shdr = malloc(shdr_size)) == NULL) return (-1); if (pread(fd, shdr, shdr_size, (off_t)ehdr.e_shoff) != shdr_size) { free(shdr); return (-1); } } /* * Find the symbol table entry and its corresponding * string table entry. Version 1.1 of the ABI states * that there is only one symbol table but that this * could change in the future. */ for (i = 0; i < ehdr.e_shnum; i++) { if (shdr[i].sh_type == SHT_SYMTAB) { if (shdr[i].sh_link >= ehdr.e_shnum) continue; symoff = shdr[i].sh_offset; symsize = shdr[i].sh_size; symstroff = shdr[shdr[i].sh_link].sh_offset; symstrsize = shdr[shdr[i].sh_link].sh_size; break; } } /* Flush the section header table */ if (usemalloc) free(shdr); else munmap((caddr_t)shdr, shdr_size); /* * clean out any left-over information for all valid entries. * Type and value defined to be 0 if not found; historical * versions cleared other and desc as well. Also figure out * the largest string length so don't read any more of the * string table than we have to. * * XXX clearing anything other than n_type and n_value violates * the semantics given in the man page. */ nent = 0; for (p = list; !ISLAST(p); ++p) { p->n_type = 0; p->n_other = 0; p->n_desc = 0; p->n_value = 0; ++nent; } /* Don't process any further if object is stripped. */ /* ELFism - dunno if stripped by looking at header */ if (symoff == 0) return nent; /* Check for files too large to mmap. */ if (SIZE_MAX - symstrsize < symstroff || S_ISREG(st.st_mode) && symstrsize + symstroff > st.st_size) { errno = EFBIG; return (-1); } /* * Map string table into our address space. This gives us * an easy way to randomly access all the strings, without * making the memory allocation permanent as with malloc/free * (i.e., munmap will return it to the system). */ if (usemalloc) { if ((strtab = malloc(symstrsize)) == NULL) return (-1); if (pread(fd, strtab, symstrsize, (off_t)symstroff) != symstrsize) { free(strtab); return (-1); } } else { strtab = mmap(NULL, (size_t)symstrsize, PROT_READ, MAP_SHARED|MAP_FILE, fd, (off_t) symstroff); if (strtab == MAP_FAILED) return (-1); } while (symsize >= sizeof(Elf_Sym)) { cc = MIN(symsize, sizeof(sbuf)); if (pread(fd, sbuf, cc, (off_t)symoff) != cc) break; symsize -= cc; symoff += cc; for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) { Elf_Word soff = s->st_name; if (soff == 0 || soff >= symstrsize) continue; left = symstrsize - soff; for (p = list; !ISLAST(p); p++) { char *sym; /* * First we check for the symbol as it was * provided by the user. If that fails * and the first char is an '_', skip over * the '_' and try again. * XXX - What do we do when the user really * wants '_foo' and there are symbols * for both 'foo' and '_foo' in the * table and 'foo' is first? */ sym = p->n_name; len = strlen(sym); if ((len >= left || strcmp(&strtab[soff], sym) != 0) && (sym[0] != '_' || len - 1 >= left || strcmp(&strtab[soff], sym + 1) != 0)) continue; p->n_value = s->st_value; /* XXX - type conversion */ /* is pretty rude. */ switch(ELF_ST_TYPE(s->st_info)) { case STT_NOTYPE: switch (s->st_shndx) { case SHN_UNDEF: p->n_type = N_UNDF; break; case SHN_ABS: p->n_type = N_ABS; break; case SHN_COMMON: p->n_type = N_COMM; break; default: p->n_type = N_COMM | N_EXT; break; } break; case STT_OBJECT: p->n_type = N_DATA; break; case STT_FUNC: p->n_type = N_TEXT; break; case STT_FILE: p->n_type = N_FN; break; } if (ELF_ST_BIND(s->st_info) == STB_LOCAL) p->n_type = N_EXT; p->n_desc = 0; p->n_other = 0; if (--nent <= 0) break; } } } elf_done: if (usemalloc) free(strtab); else munmap(strtab, symstrsize); return (nent); }
int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) { struct file_dedupe_range_info *info; struct inode *src = file_inode(file); u64 off; u64 len; int i; int ret; bool is_admin = capable(CAP_SYS_ADMIN); u16 count = same->dest_count; struct file *dst_file; loff_t dst_off; ssize_t deduped; if (!(file->f_mode & FMODE_READ)) return -EINVAL; if (same->reserved1 || same->reserved2) return -EINVAL; off = same->src_offset; len = same->src_length; ret = -EISDIR; if (S_ISDIR(src->i_mode)) goto out; ret = -EINVAL; if (!S_ISREG(src->i_mode)) goto out; ret = clone_verify_area(file, off, len, false); if (ret < 0) goto out; ret = 0; /* pre-format output fields to sane values */ for (i = 0; i < count; i++) { same->info[i].bytes_deduped = 0ULL; same->info[i].status = FILE_DEDUPE_RANGE_SAME; } for (i = 0, info = same->info; i < count; i++, info++) { struct inode *dst; struct fd dst_fd = fdget(info->dest_fd); dst_file = dst_fd.file; if (!dst_file) { info->status = -EBADF; goto next_loop; } dst = file_inode(dst_file); ret = mnt_want_write_file(dst_file); if (ret) { info->status = ret; goto next_loop; } dst_off = info->dest_offset; ret = clone_verify_area(dst_file, dst_off, len, true); if (ret < 0) { info->status = ret; goto next_file; } ret = 0; if (info->reserved) { info->status = -EINVAL; } else if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { info->status = -EINVAL; } else if (file->f_path.mnt != dst_file->f_path.mnt) { info->status = -EXDEV; } else if (S_ISDIR(dst->i_mode)) { info->status = -EISDIR; } else if (dst_file->f_op->dedupe_file_range == NULL) { info->status = -EINVAL; } else { deduped = dst_file->f_op->dedupe_file_range(file, off, len, dst_file, info->dest_offset); if (deduped == -EBADE) info->status = FILE_DEDUPE_RANGE_DIFFERS; else if (deduped < 0) info->status = deduped; else info->bytes_deduped += deduped; } next_file: mnt_drop_write_file(dst_file); next_loop: fdput(dst_fd); if (fatal_signal_pending(current)) goto out; } out: return ret; }
/* * Examine the header block that was just read. * This can specify the information for another file, or it can mark * the end of the tar file. */ static void readHeader(const TarHeader * hp, int fileCount, const char ** fileTable) { int mode; int uid; int gid; long size; time_t mtime; const char * name; int cc; BOOL hardLink; BOOL softLink; /* * If the block is completely empty, then this is the end of the * archive file. If the name is null, then just skip this header. */ name = hp->name; if (*name == '\0') { for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) { if (*name++) return; } eofFlag = TRUE; return; } /* * There is another file in the archive to examine. * Extract the encoded information and check it. */ mode = getOctal(hp->mode, sizeof(hp->mode)); uid = getOctal(hp->uid, sizeof(hp->uid)); gid = getOctal(hp->gid, sizeof(hp->gid)); size = getOctal(hp->size, sizeof(hp->size)); mtime = getOctal(hp->mtime, sizeof(hp->mtime)); if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) { if (!badHeader) fprintf(stderr, "Bad tar header, skipping\n"); badHeader = TRUE; return; } badHeader = FALSE; skipFileFlag = FALSE; /* * Check for the file modes. */ hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) || (hp->typeFlag == TAR_TYPE_HARD_LINK - '0')); softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) || (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0')); /* * Check for a directory or a regular file. */ if (name[strlen(name) - 1] == '/') mode |= S_IFDIR; else if ((mode & S_IFMT) == 0) mode |= S_IFREG; /* * Check for absolute paths in the file. * If we find any, then warn the user and make them relative. */ if (*name == '/') { while (*name == '/') name++; if (!warnedRoot) { fprintf(stderr, "Absolute path detected, removing leading slashes\n"); } warnedRoot = TRUE; } /* * See if we want this file to be restored. * If not, then set up to skip it. */ if (!wantFileName(name, fileCount, fileTable)) { if (!hardLink && !softLink && S_ISREG(mode)) { inHeader = (size == 0); dataCc = size; } skipFileFlag = TRUE; return; } /* * This file is to be handled. * If we aren't extracting then just list information about the file. */ if (!extractFlag) { if (verboseFlag) { printf("%s %3d/%-d %9ld %s %s", modeString(mode), uid, gid, size, timeString(mtime), name); } else printf("%s", name); if (hardLink) printf(" (link to \"%s\")", hp->linkName); else if (softLink) printf(" (symlink to \"%s\")", hp->linkName); else if (S_ISREG(mode)) { inHeader = (size == 0); dataCc = size; } printf("\n"); return; } /* * We really want to extract the file. */ if (verboseFlag) printf("x %s\n", name); if (hardLink) { if (link(hp->linkName, name) < 0) perror(name); return; } if (softLink) { #ifdef S_ISLNK if (symlink(hp->linkName, name) < 0) perror(name); #else fprintf(stderr, "Cannot create symbolic links\n"); #endif return; } /* * If the file is a directory, then just create the path. */ if (S_ISDIR(mode)) { createPath(name, mode); return; } /* * There is a file to write. * First create the path to it if necessary with a default permission. */ createPath(name, 0777); inHeader = (size == 0); dataCc = size; /* * Start the output file. */ outFd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode); if (outFd < 0) { perror(name); skipFileFlag = TRUE; return; } /* * If the file is empty, then that's all we need to do. */ if (size == 0) { (void) close(outFd); outFd = -1; } }
int web_main(void * _ed, struct MHD_Connection * con, const char * url, const char * method, const char * version, const char *upload_data, size_t * upload_data_size, void ** con_cls){ UNUSED(url); UNUSED(version); UNUSED(upload_data); UNUSED(upload_data_size); UNUSED(method); UNUSED(con_cls); UNUSED(_ed); const char * file = "page.html"; bool style_loc = strcmp((char *) url + 1, "style.css") == 0; if(style_loc) file = "style.css"; else if(0 == strcmp((char *) url + 1, (char *) "favicon.png")) file = "favicon.png"; char fnamebuffer[100]; logd("'%s' %s %s %i\n", url, method, version, upload_data_size); logd("File: %s\n", file); if(url == strstr(url, "/sharesinfo")){ // Send back json code describing all the available shares. file = "shareinfo_data"; dirscan dir = scan_directories("shareinfo"); FILE * outfile = fopen(file, "w"); fprintf(outfile, "["); for(size_t i = 0; i < dir.cnt; i++){ logd("looking in: %s\n", dir.files[i]); char fnamebuffer2[100]; sprintf(fnamebuffer2, "shareinfo/%s", dir.files[i]); void * rdbuffer = read_file_to_string(fnamebuffer2); ASSERT(rdbuffer != NULL); void *ptr = rdbuffer; char * dirname = udpc_unpack_string(&ptr); char * name = udpc_unpack_string(&ptr); char * user = udpc_unpack_string(&ptr); fprintf(outfile, "{\"path\": \"%s\", \"name\":\"%s\", \"user\":\"%s\"}%s\n",dirname, name, user, (i == dir.cnt -1) ? "" : ","); dealloc(rdbuffer); } fprintf(outfile, "]"); fclose(outfile); dirscan_clean(&dir); }else if(url == strstr(url,"/shares/")){ // fetch the active shares item inside the shares folder char * shareid = (char *) url + strlen("/shares/"); logd("Shareid: %s\n", shareid); char * shareinfo_filename = fmtstr("shareinfo/%s", shareid); void * buffer = read_file_to_string(shareinfo_filename); if(buffer == NULL) goto error; void * bufptr = buffer; char * dir = udpc_unpack_string(&bufptr); char * name = udpc_unpack_string(&bufptr); char * user = udpc_unpack_string(&bufptr); service_descriptor sd; if(!udpc_get_service_descriptor(user, &sd)){ logd("Unable to parse service name: '%s'\n", user); dealloc(buffer); goto error; } logd("path: %s, name: %s, user: %s\n", dir, name, user); update_dirfile(dir, name, user); sprintf(fnamebuffer, "shares/%s.json", name); dealloc(buffer); logd("Sending: %s\n", fnamebuffer); file = fnamebuffer; } if(strcmp(url, "/add_share") == 0){ const char * path = MHD_lookup_connection_value(con, MHD_GET_ARGUMENT_KIND, "path"); const char * name = MHD_lookup_connection_value(con, MHD_GET_ARGUMENT_KIND, "name"); const char * user = MHD_lookup_connection_value(con, MHD_GET_ARGUMENT_KIND, "user"); logd("path: %s, name: %s, user: %s\n", path, name, user); if(path == NULL || name == NULL || user == NULL){ goto error; } service_descriptor sd; if(!udpc_get_service_descriptor(user, &sd)){ logd("Unable to parse service name: '%s'\n", user); goto error; } logd("Service descriptor seems ok \n"); ensure_directory("shareinfo/"); char * sharepath = fmtstr("shareinfo/%s", name); struct stat filest; stat(sharepath, &filest); dealloc(sharepath); if(S_ISREG(filest.st_mode)){ logd("File exists!\n"); }else{ struct stat dirst; stat(path, &dirst); if(!S_ISDIR(dirst.st_mode)){ logd("Dir does not exist.. creating a new one..\n"); int path_len = strlen(path); if(path[path_len] !='/'){ char * npath = fmtstr("%s/", path); ensure_directory(npath); dealloc(npath); }else{ ensure_directory(path); } } logd("Updating dirfile!\n"); update_dirfile(path, name, user); logd("Done..\n"); } const char * r = "\"OK\""; struct MHD_Response * response = MHD_create_response_from_data(strlen(r), (void *) r, 0, MHD_NO); int ret = MHD_queue_response(con, MHD_HTTP_OK, response); MHD_destroy_response(response); return ret; } size_t filesize = 0; void * pg = read_file_to_buffer(file, &filesize); struct MHD_Response * response = MHD_create_response_from_data(filesize, pg, 1, MHD_NO); int ret = MHD_queue_response(con, MHD_HTTP_OK, response); MHD_destroy_response(response); return ret; error:; const char * error_str = "<html><body>400</body></html>"; response = MHD_create_response_from_data(strlen(error_str) + 1, (void *) error_str, 0, MHD_NO); ret = MHD_queue_response(con, MHD_HTTP_BAD_REQUEST, response); MHD_destroy_response(response); return ret; }
void sink(int argc, char **argv) { static BUF buffer; struct stat stb; enum { YES, NO, DISPLAYED } wrerr; BUF *bp; off_t i; size_t j, count; int amt, exists, first, ofd; mode_t mode, omode, mask; off_t size, statbytes; int setimes, targisdir, wrerrno = 0; char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; struct timeval tv[2]; #define atime tv[0] #define mtime tv[1] #define SCREWUP(str) { why = str; goto screwup; } setimes = targisdir = 0; mask = umask(0); if (!pflag) (void) umask(mask); if (argc != 1) { run_err("ambiguous target"); exit(1); } targ = *argv; if (targetshouldbedirectory) verifydir(targ); (void) atomicio(vwrite, remout, "", 1); if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) targisdir = 1; for (first = 1;; first = 0) { cp = buf; if (atomicio(read, remin, cp, 1) != 1) return; if (*cp++ == '\n') SCREWUP("unexpected <newline>"); do { if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) SCREWUP("lost connection"); *cp++ = ch; } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); *cp = 0; if (verbose_mode) fprintf(stderr, "Sink: %s", buf); if (buf[0] == '\01' || buf[0] == '\02') { if (iamremote == 0) (void) atomicio(vwrite, STDERR_FILENO, buf + 1, strlen(buf + 1)); if (buf[0] == '\02') exit(1); ++errs; continue; } if (buf[0] == 'E') { (void) atomicio(vwrite, remout, "", 1); return; } if (ch == '\n') *--cp = 0; cp = buf; if (*cp == 'T') { setimes++; cp++; mtime.tv_sec = strtol(cp, &cp, 10); if (!cp || *cp++ != ' ') SCREWUP("mtime.sec not delimited"); mtime.tv_usec = strtol(cp, &cp, 10); if (!cp || *cp++ != ' ') SCREWUP("mtime.usec not delimited"); atime.tv_sec = strtol(cp, &cp, 10); if (!cp || *cp++ != ' ') SCREWUP("atime.sec not delimited"); atime.tv_usec = strtol(cp, &cp, 10); if (!cp || *cp++ != '\0') SCREWUP("atime.usec not delimited"); (void) atomicio(vwrite, remout, "", 1); continue; } if (*cp != 'C' && *cp != 'D') { /* * Check for the case "rcp remote:foo\* local:bar". * In this case, the line "No match." can be returned * by the shell before the rcp command on the remote is * executed so the ^Aerror_message convention isn't * followed. */ if (first) { run_err("%s", cp); exit(1); } SCREWUP("expected control record"); } mode = 0; for (++cp; cp < buf + 5; cp++) { if (*cp < '0' || *cp > '7') SCREWUP("bad mode"); mode = (mode << 3) | (*cp - '0'); } if (*cp++ != ' ') SCREWUP("mode not delimited"); for (size = 0; isdigit(*cp);) size = size * 10 + (*cp++ - '0'); if (*cp++ != ' ') SCREWUP("size not delimited"); if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) { run_err("error: unexpected filename: %s", cp); exit(1); } if (targisdir) { static char *namebuf; static size_t cursize; size_t need; need = strlen(targ) + strlen(cp) + 250; if (need > cursize) { free(namebuf); namebuf = xmalloc(need); cursize = need; } (void) snprintf(namebuf, need, "%s%s%s", targ, strcmp(targ, "/") ? "/" : "", cp); np = namebuf; } else np = targ; curfile = cp; exists = stat(np, &stb) == 0; if (buf[0] == 'D') { int mod_flag = pflag; if (!iamrecursive) SCREWUP("received directory without -r"); if (exists) { if (!S_ISDIR(stb.st_mode)) { errno = ENOTDIR; goto bad; } if (pflag) (void) chmod(np, mode); } else { /* Handle copying from a read-only directory */ mod_flag = 1; if (mkdir(np, mode | S_IRWXU) < 0) goto bad; } vect[0] = xstrdup(np); sink(1, vect); if (setimes) { setimes = 0; if (utimes(vect[0], tv) < 0) run_err("%s: set times: %s", vect[0], strerror(errno)); } if (mod_flag) (void) chmod(vect[0], mode); free(vect[0]); continue; } omode = mode; mode |= S_IWUSR; if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { bad: run_err("%s: %s", np, strerror(errno)); continue; } (void) atomicio(vwrite, remout, "", 1); if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) { (void) close(ofd); continue; } cp = bp->buf; wrerr = NO; statbytes = 0; if (showprogress) start_progress_meter(curfile, size, &statbytes); set_nonblock(remin); for (count = i = 0; i < size; i += bp->cnt) { amt = bp->cnt; if (i + amt > size) amt = size - i; count += amt; do { j = atomicio6(read, remin, cp, amt, scpio, &statbytes); if (j == 0) { run_err("%s", j != EPIPE ? strerror(errno) : "dropped connection"); exit(1); } amt -= j; cp += j; } while (amt > 0); if (count == bp->cnt) { /* Keep reading so we stay sync'd up. */ if (wrerr == NO) { if (atomicio(vwrite, ofd, bp->buf, count) != count) { wrerr = YES; wrerrno = errno; } } count = 0; cp = bp->buf; } } unset_nonblock(remin); if (showprogress) stop_progress_meter(); if (count != 0 && wrerr == NO && atomicio(vwrite, ofd, bp->buf, count) != count) { wrerr = YES; wrerrno = errno; } if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) && ftruncate(ofd, size) != 0) { run_err("%s: truncate: %s", np, strerror(errno)); wrerr = DISPLAYED; } if (pflag) { if (exists || omode != mode) #ifdef HAVE_FCHMOD if (fchmod(ofd, omode)) { #else /* HAVE_FCHMOD */ if (chmod(np, omode)) { #endif /* HAVE_FCHMOD */ run_err("%s: set mode: %s", np, strerror(errno)); wrerr = DISPLAYED; } } else { if (!exists && omode != mode) #ifdef HAVE_FCHMOD if (fchmod(ofd, omode & ~mask)) { #else /* HAVE_FCHMOD */ if (chmod(np, omode & ~mask)) { #endif /* HAVE_FCHMOD */ run_err("%s: set mode: %s", np, strerror(errno)); wrerr = DISPLAYED; } } if (close(ofd) == -1) { wrerr = YES; wrerrno = errno; } (void) response(); if (setimes && wrerr == NO) { setimes = 0; if (utimes(np, tv) < 0) { run_err("%s: set times: %s", np, strerror(errno)); wrerr = DISPLAYED; } } switch (wrerr) { case YES: run_err("%s: %s", np, strerror(wrerrno)); break; case NO: (void) atomicio(vwrite, remout, "", 1); break; case DISPLAYED: break; } } screwup: run_err("protocol error: %s", why); exit(1); } int response(void) { char ch, *cp, resp, rbuf[2048]; if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) lostconn(0); cp = rbuf; switch (resp) { case 0: /* ok */ return (0); default: *cp++ = resp; /* FALLTHROUGH */ case 1: /* error, followed by error msg */ case 2: /* fatal error, "" */ do { if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) lostconn(0); *cp++ = ch; } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); if (!iamremote) (void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf); ++errs; if (resp == 1) return (-1); exit(1); } /* NOTREACHED */ } void usage(void) { (void) fprintf(stderr, "usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" " [-l limit] [-o ssh_option] [-P port] [-S program]\n" " [[user@]host1:]file1 ... [[user@]host2:]file2\n"); exit(1); }
/* Consider adding a remove_leftovers() that runs in verify/fix in order to * allow this function to mkdtemp create folders for parallel build */ enum swupd_code do_staging(struct file *file, struct manifest *MoM) { char *statfile = NULL, *tmp = NULL, *tmp2 = NULL; char *dir, *base, *rel_dir; char *tarcommand = NULL; char *original = NULL; char *target = NULL; char *targetpath = NULL; char *rename_target = NULL; char *rename_tmpdir = NULL; char real_path[4096] = { 0 }; int ret; struct stat s; tmp = strdup_or_die(file->filename); tmp2 = strdup_or_die(file->filename); dir = dirname(tmp); base = basename(tmp2); rel_dir = dir; if (*dir == '/') { rel_dir = dir + 1; } string_or_die(&original, "%s/staged/%s", state_dir, file->hash); string_or_die(&targetpath, "%s%s", path_prefix, rel_dir); ret = stat(targetpath, &s); if ((ret == -1) && (errno == ENOENT)) { if (MoM) { warn("Update target directory does not exist: %s. Trying to fix it\n", targetpath); verify_fix_path(dir, MoM); } else { warn("Update target directory does not exist: %s. Auto-fix disabled\n", targetpath); } } else if (!S_ISDIR(s.st_mode)) { error("Update target exists but is NOT a directory: %s\n", targetpath); } if (!realpath(targetpath, real_path)) { ret = -1; goto out; } else if (strcmp(path_prefix, targetpath) != 0 && strcmp(targetpath, real_path) != 0) { /* * targetpath and real_path should always be equal but * in the case of the targetpath being the path_prefix * there is a trailing '/' in path_prefix but realpath * doesn't keep the trailing '/' so check for that case * specifically. */ ret = -1; goto out; } string_or_die(&target, "%s%s/.update.%s", path_prefix, rel_dir, base); ret = swupd_rm(target); if (ret < 0 && ret != -ENOENT) { error("Failed to remove %s\n", target); } string_or_die(&statfile, "%s%s", path_prefix, file->filename); memset(&s, 0, sizeof(struct stat)); ret = lstat(statfile, &s); if (ret == 0) { if ((file->is_dir && !S_ISDIR(s.st_mode)) || (file->is_link && !S_ISLNK(s.st_mode)) || (file->is_file && !S_ISREG(s.st_mode))) { //file type changed, move old out of the way for new ret = swupd_rm(statfile); if (ret < 0) { ret = SWUPD_COULDNT_REMOVE_FILE; goto out; } } } free_string(&statfile); if (file->is_dir || S_ISDIR(s.st_mode)) { /* In the btrfs only scenario there was an implicit * "create_or_update_dir()" via un-tar-ing a directory.tar after * download and the untar happens in the staging subvolume which * then gets promoted to a "real" usable subvolume. But for * a live rootfs the directory needs copied out of staged * and into the rootfs. Tar is a way to copy with * attributes and it includes internal logic that does the * right thing to overlay a directory onto something * pre-existing: */ /* In order to avoid tar transforms with directories, rename * the directory before and after the tar command */ string_or_die(&rename_tmpdir, "%s/tmprenamedir", state_dir); ret = create_staging_renamedir(rename_tmpdir); if (ret) { ret = SWUPD_COULDNT_CREATE_DIR; goto out; } string_or_die(&rename_target, "%s/%s", rename_tmpdir, base); if (rename(original, rename_target)) { ret = SWUPD_COULDNT_RENAME_DIR; goto out; } string_or_die(&tarcommand, TAR_COMMAND " -C '%s' " TAR_PERM_ATTR_ARGS " -cf - './%s' 2> /dev/null | " TAR_COMMAND " -C '%s%s' " TAR_PERM_ATTR_ARGS " -xf - 2> /dev/null", rename_tmpdir, base, path_prefix, rel_dir); ret = system(tarcommand); if (ret == -1) { ret = SWUPD_SUBPROCESS_ERROR; } if (WIFEXITED(ret)) { ret = WEXITSTATUS(ret); } free_string(&tarcommand); if (rename(rename_target, original)) { ret = SWUPD_COULDNT_RENAME_DIR; goto out; } if (ret) { ret = SWUPD_COULDNT_RENAME_DIR; goto out; } } else { /* (!file->is_dir && !S_ISDIR(stat.st_mode)) */ /* can't naively hard link(): Non-read-only files with same hash must remain * separate copies otherwise modifications to one instance of the file * propagate to all instances of the file perhaps causing subtle data corruption from * a user's perspective. In practice the rootfs is stateless and owned by us. * Additionally cross-mount hardlinks fail and it's hard to know what an admin * might have for overlaid mounts. The use of tar is a simple way to copy, but * inefficient. So prefer hardlink and fall back if needed: */ ret = -1; if (!file->is_config && !file->is_state && !file->use_xattrs) { ret = link(original, target); } if (ret < 0) { /* either the hardlink failed, or it was undesirable (config), do a tar-tar dance */ /* In order to avoid tar transforms, rename the file * before and after the tar command */ string_or_die(&rename_target, "%s/staged/.update.%s", state_dir, base); ret = rename(original, rename_target); if (ret) { ret = SWUPD_COULDNT_RENAME_FILE; goto out; } string_or_die(&tarcommand, TAR_COMMAND " -C '%s/staged' " TAR_PERM_ATTR_ARGS " -cf - '.update.%s' 2> /dev/null | " TAR_COMMAND " -C '%s%s' " TAR_PERM_ATTR_ARGS " -xf - 2> /dev/null", state_dir, base, path_prefix, rel_dir); ret = system(tarcommand); if (ret == -1) { ret = SWUPD_SUBPROCESS_ERROR; } if (WIFEXITED(ret)) { ret = WEXITSTATUS(ret); } free_string(&tarcommand); ret = rename(rename_target, original); if (ret) { ret = SWUPD_COULDNT_RENAME_FILE; goto out; } } struct stat buf; int err; free_string(&file->staging); string_or_die(&file->staging, "%s%s/.update.%s", path_prefix, rel_dir, base); err = lstat(file->staging, &buf); if (err != 0) { free_string(&file->staging); ret = SWUPD_COULDNT_CREATE_FILE; goto out; } } out: free_string(&target); free_string(&targetpath); free_string(&original); free_string(&rename_target); free_string(&rename_tmpdir); free_string(&tmp); free_string(&tmp2); return ret; }
void server_process_native_file( Server *s, int fd, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) { struct stat st; bool sealed; int r; /* Data is in the passed fd, since it didn't fit in a * datagram. */ assert(s); assert(fd >= 0); /* If it's a memfd, check if it is sealed. If so, we can just * use map it and use it, and do not need to copy the data * out. */ sealed = memfd_get_sealed(fd) > 0; if (!sealed && (!ucred || ucred->uid != 0)) { _cleanup_free_ char *sl = NULL, *k = NULL; const char *e; /* If this is not a sealed memfd, and the peer is unknown or * unprivileged, then verify the path. */ if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) { log_oom(); return; } r = readlink_malloc(sl, &k); if (r < 0) { log_error_errno(r, "readlink(%s) failed: %m", sl); return; } e = path_startswith(k, "/dev/shm/"); if (!e) e = path_startswith(k, "/tmp/"); if (!e) e = path_startswith(k, "/var/tmp/"); if (!e) { log_error("Received file outside of allowed directories. Refusing."); return; } if (!filename_is_valid(e)) { log_error("Received file in subdirectory of allowed directories. Refusing."); return; } } if (fstat(fd, &st) < 0) { log_error_errno(errno, "Failed to stat passed file, ignoring: %m"); return; } if (!S_ISREG(st.st_mode)) { log_error("File passed is not regular. Ignoring."); return; } if (st.st_size <= 0) return; if (st.st_size > ENTRY_SIZE_MAX) { log_error("File passed too large. Ignoring."); return; } if (sealed) { void *p; size_t ps; /* The file is sealed, we can just map it and use it. */ ps = PAGE_ALIGN(st.st_size); p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0); if (p == MAP_FAILED) { log_error_errno(errno, "Failed to map memfd, ignoring: %m"); return; } server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len); assert_se(munmap(p, ps) >= 0); } else { _cleanup_free_ void *p = NULL; struct statvfs vfs; ssize_t n; if (fstatvfs(fd, &vfs) < 0) { log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m"); return; } /* Refuse operating on file systems that have * mandatory locking enabled, see: * * https://github.com/systemd/systemd/issues/1822 */ if (vfs.f_flag & ST_MANDLOCK) { log_error("Received file descriptor from file system with mandatory locking enable, refusing."); return; } /* Make the fd non-blocking. On regular files this has * the effect of bypassing mandatory locking. Of * course, this should normally not be necessary given * the check above, but let's better be safe than * sorry, after all NFS is pretty confusing regarding * file system flags, and we better don't trust it, * and so is SMB. */ r = fd_nonblock(fd, true); if (r < 0) { log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m"); return; } /* The file is not sealed, we can't map the file here, since * clients might then truncate it and trigger a SIGBUS for * us. So let's stupidly read it */ p = malloc(st.st_size); if (!p) { log_oom(); return; } n = pread(fd, p, st.st_size, 0); if (n < 0) log_error_errno(errno, "Failed to read file, ignoring: %m"); else if (n > 0) server_process_native_message(s, p, n, ucred, tv, label, label_len); } }
static int file_open(struct archive *a, void *client_data) { struct stat st; struct read_file_data *mine = (struct read_file_data *)client_data; void *buffer; const char *filename = NULL; const wchar_t *wfilename = NULL; int fd; int is_disk_like = 0; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */ #elif defined(__NetBSD__) || defined(__OpenBSD__) struct disklabel dl; #elif defined(__DragonFly__) struct partinfo pi; #endif archive_clear_error(a); if (mine->filename_type == FNT_STDIN) { /* We used to delegate stdin support by * directly calling archive_read_open_fd(a,0,block_size) * here, but that doesn't (and shouldn't) handle the * end-of-file flush when reading stdout from a pipe. * Basically, read_open_fd() is intended for folks who * are willing to handle such details themselves. This * API is intended to be a little smarter for folks who * want easy handling of the common case. */ fd = 0; #if defined(__CYGWIN__) || defined(_WIN32) setmode(0, O_BINARY); #endif filename = ""; } else if (mine->filename_type == FNT_MBS) { filename = mine->filename.m; fd = open(filename, O_RDONLY | O_BINARY | O_CLOEXEC); __archive_ensure_cloexec_flag(fd); if (fd < 0) { archive_set_error(a, errno, "Failed to open '%s'", filename); return (ARCHIVE_FATAL); } } else { #if defined(_WIN32) && !defined(__CYGWIN__) wfilename = mine->filename.w; fd = _wopen(wfilename, O_RDONLY | O_BINARY); if (fd < 0 && errno == ENOENT) { wchar_t *fullpath; fullpath = __la_win_permissive_name_w(wfilename); if (fullpath != NULL) { fd = _wopen(fullpath, O_RDONLY | O_BINARY); free(fullpath); } } if (fd < 0) { archive_set_error(a, errno, "Failed to open '%S'", wfilename); return (ARCHIVE_FATAL); } #else archive_set_error(a, ARCHIVE_ERRNO_MISC, "Unexpedted operation in archive_read_open_filename"); return (ARCHIVE_FATAL); #endif } if (fstat(fd, &st) != 0) { if (mine->filename_type == FNT_WCS) archive_set_error(a, errno, "Can't stat '%S'", wfilename); else archive_set_error(a, errno, "Can't stat '%s'", filename); return (ARCHIVE_FATAL); } /* * Determine whether the input looks like a disk device or a * tape device. The results are used below to select an I/O * strategy: * = "disk-like" devices support arbitrary lseek() and will * support I/O requests of any size. So we get easy skipping * and can cheat on block sizes to get better performance. * = "tape-like" devices require strict blocking and use * specialized ioctls for seeking. * = "socket-like" devices cannot seek at all but can improve * performance by using nonblocking I/O to read "whatever is * available right now". * * Right now, we only specially recognize disk-like devices, * but it should be straightforward to add probes and strategy * here for tape-like and socket-like devices. */ if (S_ISREG(st.st_mode)) { /* Safety: Tell the extractor not to overwrite the input. */ archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); /* Regular files act like disks. */ is_disk_like = 1; } #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) /* FreeBSD: if it supports DIOCGMEDIASIZE ioctl, it's disk-like. */ else if (S_ISCHR(st.st_mode) && ioctl(fd, DIOCGMEDIASIZE, &mediasize) == 0 && mediasize > 0) { is_disk_like = 1; } #elif defined(__NetBSD__) || defined(__OpenBSD__) /* Net/OpenBSD: if it supports DIOCGDINFO ioctl, it's disk-like. */ else if ((S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) && ioctl(fd, DIOCGDINFO, &dl) == 0 && dl.d_partitions[DISKPART(st.st_rdev)].p_size > 0) { is_disk_like = 1; } #elif defined(__DragonFly__) /* DragonFly BSD: if it supports DIOCGPART ioctl, it's disk-like. */ else if (S_ISCHR(st.st_mode) && ioctl(fd, DIOCGPART, &pi) == 0 && pi.media_size > 0) { is_disk_like = 1; } #elif defined(__linux__) /* Linux: All block devices are disk-like. */ else if (S_ISBLK(st.st_mode) && lseek(fd, 0, SEEK_CUR) == 0 && lseek(fd, 0, SEEK_SET) == 0 && lseek(fd, 0, SEEK_END) > 0 && lseek(fd, 0, SEEK_SET) == 0) { is_disk_like = 1; } #endif /* TODO: Add an "is_tape_like" variable and appropriate tests. */ /* Disk-like devices prefer power-of-two block sizes. */ /* Use provided block_size as a guide so users have some control. */ if (is_disk_like) { size_t new_block_size = 64 * 1024; while (new_block_size < mine->block_size && new_block_size < 64 * 1024 * 1024) new_block_size *= 2; mine->block_size = new_block_size; } buffer = malloc(mine->block_size); if (mine == NULL || buffer == NULL) { archive_set_error(a, ENOMEM, "No memory"); free(mine); free(buffer); return (ARCHIVE_FATAL); } mine->buffer = buffer; mine->fd = fd; /* Remember mode so close can decide whether to flush. */ mine->st_mode = st.st_mode; /* Disk-like inputs can use lseek(). */ if (is_disk_like) mine->use_lseek = 1; return (ARCHIVE_OK); }
bool cgfs_list_keys(const char *controller, const char *cgroup, struct cgfs_files ***keys) { size_t len; char *dirname, *tmpc = find_mounted_controller(controller); char pathname[MAXPATHLEN]; size_t sz = 0, asz = 0; struct dirent dirent, *direntp; DIR *dir; int ret; *keys = NULL; if (!tmpc) return NULL; /* basedir / tmpc / cgroup \0 */ len = strlen(basedir) + strlen(tmpc) + strlen(cgroup) + 3; dirname = alloca(len); snprintf(dirname, len, "%s/%s/%s", basedir, tmpc, cgroup); dir = opendir(dirname); if (!dir) return false; while (!readdir_r(dir, &dirent, &direntp)) { struct stat mystat; int rc; if (!direntp) break; if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) continue; rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name); if (rc < 0 || rc >= MAXPATHLEN) { fprintf(stderr, "%s: pathname too long under %s\n", __func__, dirname); continue; } ret = lstat(pathname, &mystat); if (ret) { fprintf(stderr, "%s: failed to stat %s: %s\n", __func__, pathname, strerror(errno)); continue; } if (!S_ISREG(mystat.st_mode)) continue; if (sz+2 >= asz) { struct cgfs_files **tmp; asz += BATCH_SIZE; do { tmp = realloc(*keys, asz * sizeof(struct cgfs_files *)); } while (!tmp); *keys = tmp; } (*keys)[sz] = cgfs_get_key(controller, cgroup, direntp->d_name); (*keys)[sz+1] = NULL; if (!(*keys)[sz]) { fprintf(stderr, "%s: Error getting files under %s:%s\n", __func__, controller, cgroup); continue; } sz++; } if (closedir(dir) < 0) { fprintf(stderr, "%s: failed closedir for %s: %s\n", __func__, dirname, strerror(errno)); return false; } return true; }
EDIT_FILE *edit_file_open(const char *path, int flags, mode_t mode) { struct stat before_lock; struct stat after_lock; int saved_errno; EDIT_FILE *ep; /* * Initialize. Do not bother to optimize for the error case. */ EDIT_FILE_ALLOC(ep, path, mode); /* * As long as the output file can be opened under the temporary pathname, * this code can loop or block forever. * * Applications that are concerned about deadlock should protect the * edit_file_open() call with a watchdog timer. */ for ( /* void */ ; /* void */ ; (void) vstream_fclose(ep->tmp_fp)) { /* * Try to open the output file under the temporary pathname. This * succeeds or fails immediately. To avoid creating a shared-lock DOS * opportunity after we crash, we create the output file with no * group or other permissions, and set the final permissions at the * end (this is one reason why we try to get exclusive control over * the output file instead of the original file). We postpone file * truncation until we have obtained exclusive control over the file * content and temporary pathname. If the open operation fails, we * give up immediately. The caller can retry the call if desirable. * * XXX If we replace the vstream_fopen() call by safe_open(), then we * should replace the stat() call below by lstat(). */ if ((ep->tmp_fp = vstream_fopen(ep->tmp_path, flags & ~(O_TRUNC), EDIT_FILE_MODE)) == 0) { saved_errno = errno; EDIT_FILE_FREE(ep); errno = saved_errno; return (0); } /* * At this point we may have opened an existing output file that was * already locked. Try to lock the open file exclusively. This may * take some time. */ if (myflock(vstream_fileno(ep->tmp_fp), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) msg_fatal("lock %s: %m", ep->tmp_path); /* * At this point we have an exclusive lock, but some other process * may have renamed or removed the output file while we were waiting * for the lock. If that is the case, back out and try again. */ if (fstat(vstream_fileno(ep->tmp_fp), &before_lock) < 0) msg_fatal("open %s: %m", ep->tmp_path); if (stat(ep->tmp_path, &after_lock) < 0 || before_lock.st_dev != after_lock.st_dev || before_lock.st_ino != after_lock.st_ino #ifdef HAS_ST_GEN || before_lock.st_gen != after_lock.st_gen #endif /* No need to compare st_rdev or st_nlink here. */ ) { continue; } /* * At this point we have exclusive control over the output file * content and its temporary pathname (within the rules of the * cooperative protocol). But wait, there is more. * * There are many opportunies for trouble when opening a pre-existing * output file. Here are just a few. * * - Victor observes that a system crash in the middle of the * final-phase rename() operation may result in the output file * having both the temporary pathname and the final pathname. In that * case we must not write to the output file. * * - Wietse observes that crashes may also leave the output file in * other inconsistent states. To avoid permission-related trouble, we * simply refuse to work with an output file that has the wrong * temporary permissions. This won't stop the shared-lock DOS if we * crash after changing the file permissions, though. * * To work around these crash-related problems, remove the temporary * pathname, back out, and try again. */ if (!S_ISREG(after_lock.st_mode) #ifndef EDIT_FILE_REUSE_AFTER_CRASH || after_lock.st_size > 0 #endif || after_lock.st_nlink > 1 || (after_lock.st_mode & FILE_PERM_MASK) != EDIT_FILE_MODE) { if (unlink(ep->tmp_path) < 0 && errno != ENOENT) msg_fatal("unlink %s: %m", ep->tmp_path); continue; } /* * Settle the final details. */ #ifdef EDIT_FILE_REUSE_AFTER_CRASH if (ftruncate(vstream_fileno(ep->tmp_fp), 0) < 0) msg_fatal("truncate %s: %m", ep->tmp_path); #endif return (ep); } }
int read_full_stream(FILE *f, char **contents, size_t *size) { size_t n, l; _cleanup_free_ char *buf = NULL; struct stat st; assert(f); assert(contents); if (fstat(fileno(f), &st) < 0) return -errno; n = LINE_MAX; if (S_ISREG(st.st_mode)) { /* Safety check */ if (st.st_size > 4*1024*1024) return -E2BIG; /* Start with the right file size, but be prepared for * files from /proc which generally report a file size * of 0 */ if (st.st_size > 0) n = st.st_size; } l = 0; for (;;) { char *t; size_t k; t = realloc(buf, n+1); if (!t) return -ENOMEM; buf = t; k = fread(buf + l, 1, n - l, f); if (k <= 0) { if (ferror(f)) return -errno; break; } l += k; n *= 2; /* Safety check */ if (n > 4*1024*1024) return -E2BIG; } buf[l] = 0; *contents = buf; buf = NULL; /* do not free */ if (size) *size = l; return 0; }
/* * ar_close() * closes archive device, increments volume number, and prints i/o summary */ void ar_close(void) { int status; if (arfd < 0) { did_io = io_ok = flcnt = 0; return; } /* * Close archive file. This may take a LONG while on tapes (we may be * forced to wait for the rewind to complete) so tell the user what is * going on (this avoids the user hitting control-c thinking pax is * broken). */ if (vflag && (artyp == ISTAPE)) { if (vfpart) (void)putc('\n', listf); (void)fprintf(listf, "%s: Waiting for tape drive close to complete...", argv0); (void)fflush(listf); } /* * if nothing was written to the archive (and we created it), we remove * it */ if (can_unlnk && (fstat(arfd, &arsb) == 0) && (S_ISREG(arsb.st_mode)) && (arsb.st_size == 0)) { (void)unlink(arcname); can_unlnk = 0; } /* * for a quick extract/list, pax frequently exits before the child * process is done */ if ((act == LIST || act == EXTRACT) && nflag && zpid > 0) kill(zpid, SIGINT); (void)close(arfd); /* Do not exit before child to ensure data integrity */ if (zpid > 0) waitpid(zpid, &status, 0); if (vflag && (artyp == ISTAPE)) { (void)fputs("done.\n", listf); vfpart = 0; (void)fflush(listf); } arfd = -1; if (!io_ok && !did_io) { flcnt = 0; return; } did_io = io_ok = 0; /* * The volume number is only increased when the last device has data * and we have already determined the archive format. */ if (frmt != NULL) ++arvol; if (!vflag) { flcnt = 0; return; } /* * Print out a summary of I/O for this archive volume. */ if (vfpart) { (void)putc('\n', listf); vfpart = 0; } /* * If we have not determined the format yet, we just say how many bytes * we have skipped over looking for a header to id. there is no way we * could have written anything yet. */ if (frmt == NULL) { # ifdef NET2_STAT (void)fprintf(listf, "%s: unknown format, %lu bytes skipped.\n", argv0, rdcnt); # else (void)fprintf(listf, "%s: unknown format, %ju bytes skipped.\n", argv0, (uintmax_t)rdcnt); # endif (void)fflush(listf); flcnt = 0; return; } if (strcmp(NM_CPIO, argv0) == 0) (void)fprintf(listf, "%llu blocks\n", (unsigned long)((rdcnt ? rdcnt : wrcnt) / 5120)); else if (strcmp(NM_TAR, argv0) != 0) (void)fprintf(listf, # ifdef NET2_STAT "%s: %s vol %d, %lu files, %lu bytes read, %lu bytes written.\n", argv0, frmt->name, arvol-1, flcnt, rdcnt, wrcnt); # else "%s: %s vol %d, %ju files, %ju bytes read, %ju bytes written.\n", argv0, frmt->name, arvol-1, (uintmax_t)flcnt, (uintmax_t)rdcnt, (uintmax_t)wrcnt); # endif (void)fflush(listf); flcnt = 0; }
static int test_config(char *filename) { #if 0 struct stat st; char *file; #endif if (!(rc_conf_srv("authserver")->max)) { rc_log(LOG_ERR,"%s: no authserver specified", filename); return (-1); } if (!(rc_conf_srv("acctserver")->max)) { rc_log(LOG_ERR,"%s: no acctserver specified", filename); return (-1); } if (!rc_conf_str("servers")) { rc_log(LOG_ERR,"%s: no servers file specified", filename); return (-1); } if (!rc_conf_str("dictionary")) { rc_log(LOG_ERR,"%s: no dictionary specified", filename); return (-1); } if (rc_conf_int("radius_timeout") <= 0) { rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename); return (-1); } if (rc_conf_int("radius_retries") <= 0) { rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename); return (-1); } #if 0 file = rc_conf_str("login_local"); if (stat(file, &st) == 0) { if (!S_ISREG(st.st_mode)) { rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file); return (-1); } } else { rc_log(LOG_ERR,"%s: file not found: %s", filename, file); return (-1); } file = rc_conf_str("login_radius"); if (stat(file, &st) == 0) { if (!S_ISREG(st.st_mode)) { rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file); return (-1); } } else { rc_log(LOG_ERR,"%s: file not found: %s", filename, file); return (-1); } #endif if (rc_conf_int("login_tries") <= 0) { rc_log(LOG_ERR,"%s: login_tries <= 0 is illegal", filename); return (-1); } if (rc_conf_str("seqfile") == NULL) { rc_log(LOG_ERR,"%s: seqfile not specified", filename); return (-1); } if (rc_conf_int("login_timeout") <= 0) { rc_log(LOG_ERR,"%s: login_timeout <= 0 is illegal", filename); return (-1); } if (rc_conf_str("mapfile") == NULL) { rc_log(LOG_ERR,"%s: mapfile not specified", filename); return (-1); } if (rc_conf_str("nologin") == NULL) { rc_log(LOG_ERR,"%s: nologin not specified", filename); return (-1); } return 0; }
NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp, const DATA_BLOB old_cookie, TALLOC_CTX *mem_ctx, DATA_BLOB *new_cookie) { struct connection_struct *conn = fsp->conn; NTSTATUS status; enum ndr_err_code ndr_err; struct vfs_default_durable_cookie cookie; DATA_BLOB new_cookie_blob = data_blob_null; struct share_mode_lock *lck; bool ok; *new_cookie = data_blob_null; ZERO_STRUCT(cookie); ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie, (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); return status; } if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) { return NT_STATUS_INVALID_PARAMETER; } if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) { return NT_STATUS_INVALID_PARAMETER; } if (!file_id_equal(&fsp->file_id, &cookie.id)) { return NT_STATUS_INVALID_PARAMETER; } if (!BATCH_OPLOCK_TYPE(fsp->oplock_type)) { return NT_STATUS_NOT_SUPPORTED; } /* * For now let it be simple and do not keep * delete on close files durable open */ if (fsp->initial_delete_on_close) { return NT_STATUS_NOT_SUPPORTED; } if (fsp->delete_on_close) { return NT_STATUS_NOT_SUPPORTED; } if (!VALID_STAT(fsp->fsp_name->st)) { return NT_STATUS_NOT_SUPPORTED; } if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) { return NT_STATUS_NOT_SUPPORTED; } /* Ensure any pending write time updates are done. */ if (fsp->update_write_time_event) { update_write_time_handler(fsp->conn->sconn->ev_ctx, fsp->update_write_time_event, timeval_current(), (void *)fsp); } /* * The above checks are done in mark_share_mode_disconnected() too * but we want to avoid getting the lock if possible */ lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); if (lck != NULL) { struct smb_file_time ft; ZERO_STRUCT(ft); if (fsp->write_time_forced) { ft.mtime = lck->data->changed_write_time; } else if (fsp->update_write_time_on_close) { if (null_timespec(fsp->close_write_time)) { ft.mtime = timespec_current(); } else { ft.mtime = fsp->close_write_time; } } if (!null_timespec(ft.mtime)) { round_timespec(conn->ts_res, &ft.mtime); file_ntimes(conn, fsp->fsp_name, &ft); } ok = mark_share_mode_disconnected(lck, fsp); if (!ok) { TALLOC_FREE(lck); } } if (lck != NULL) { ok = brl_mark_disconnected(fsp); if (!ok) { TALLOC_FREE(lck); } } if (lck == NULL) { return NT_STATUS_NOT_SUPPORTED; } TALLOC_FREE(lck); status = vfs_stat_fsp(fsp); if (!NT_STATUS_IS_OK(status)) { return status; } ZERO_STRUCT(cookie); cookie.allow_reconnect = true; cookie.id = fsp->file_id; cookie.servicepath = conn->connectpath; cookie.base_name = fsp->fsp_name->base_name; cookie.initial_allocation_size = fsp->initial_allocation_size; cookie.position_information = fsp->fh->position_information; cookie.update_write_time_triggered = fsp->update_write_time_triggered; cookie.update_write_time_on_close = fsp->update_write_time_on_close; cookie.write_time_forced = fsp->write_time_forced; cookie.close_write_time = fsp->close_write_time; cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev; cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino; cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode; cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink; cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid; cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid; cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev; cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size; cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime; cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime; cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime; cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime; cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime; cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize; cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks; cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags; cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask; ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie, (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); return status; } status = fd_close(fsp); if (!NT_STATUS_IS_OK(status)) { data_blob_free(&new_cookie_blob); return status; } *new_cookie = new_cookie_blob; return NT_STATUS_OK; }
gt_input_file* gt_input_file_open(char* const file_name,const bool mmap_file) { GT_NULL_CHECK(file_name); // Allocate handler gt_input_file* input_file = gt_alloc(gt_input_file); // Input file struct stat stat_info; unsigned char tbuf[4]; int i; gt_cond_fatal_error(stat(file_name,&stat_info)==-1,FILE_STAT,file_name); input_file->file_name = file_name; input_file->file_size = stat_info.st_size; input_file->eof = (input_file->file_size==0); input_file->file_format = FILE_FORMAT_UNKNOWN; gt_cond_fatal_error(pthread_mutex_init(&input_file->input_mutex,NULL),SYS_MUTEX_INIT); if (mmap_file) { input_file->file = NULL; input_file->fildes = open(file_name,O_RDONLY,0); // TODO: O_NOATIME condCompl (Thanks Jordi Camps) gt_cond_fatal_error(input_file->fildes==-1,FILE_OPEN,file_name); input_file->file_buffer = (uint8_t*) mmap(0,input_file->file_size,PROT_READ,MAP_PRIVATE,input_file->fildes,0); gt_cond_fatal_error(input_file->file_buffer==MAP_FAILED,SYS_MMAP_FILE,file_name); input_file->file_type = MAPPED_FILE; } else { input_file->fildes = -1; gt_cond_fatal_error(!(input_file->file=fopen(file_name,"r")),FILE_OPEN,file_name); input_file->file_type = REGULAR_FILE; if(S_ISREG(stat_info.st_mode)) { // Regular file - check if gzip or bzip compressed i=(int)fread(tbuf,(size_t)1,(size_t)4,input_file->file); if(tbuf[0]==0x1f && tbuf[1]==0x8b && tbuf[2]==0x08) { input_file->file_type=GZIPPED_FILE; fclose(input_file->file); #ifdef HAVE_ZLIB gt_cond_fatal_error(!(input_file->file=(void *)gzopen(file_name,"r")),FILE_GZIP_OPEN,file_name); #else gt_fatal_error(FILE_GZIP_NO_ZLIB,file_name); #endif } else if(tbuf[0]=='B' && tbuf[1]=='Z' && tbuf[2]=='h' && tbuf[3]>='0' && tbuf[3]<='9') { fseek(input_file->file,0L,SEEK_SET); input_file->file_type=BZIPPED_FILE; #ifdef HAVE_BZLIB input_file->file=BZ2_bzReadOpen(&i,input_file->file,0,0,NULL,0); gt_cond_fatal_error(i!=BZ_OK,FILE_BZIP2_OPEN,file_name); #else gt_fatal_error(FILE_BZIP2_NO_BZLIB,file_name); #endif } else { fseek(input_file->file,0L,SEEK_SET); } } else { input_file->eof=0; } input_file->file_buffer = gt_malloc(GT_INPUT_BUFFER_SIZE); } // Auxiliary Buffer (for synch purposes) input_file->buffer_size = 0; input_file->buffer_begin = 0; input_file->buffer_pos = 0; input_file->global_pos = 0; input_file->processed_lines = 0; // ID generator input_file->processed_id = 0; // Detect file format gt_input_file_detect_file_format(input_file); return input_file; }
NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, struct smb_request *smb1req, struct smbXsrv_open *op, const DATA_BLOB old_cookie, TALLOC_CTX *mem_ctx, files_struct **result, DATA_BLOB *new_cookie) { struct share_mode_lock *lck; struct share_mode_entry *e; struct files_struct *fsp = NULL; NTSTATUS status; bool ok; int ret; int flags = 0; struct file_id file_id; struct smb_filename *smb_fname = NULL; enum ndr_err_code ndr_err; struct vfs_default_durable_cookie cookie; DATA_BLOB new_cookie_blob = data_blob_null; *result = NULL; *new_cookie = data_blob_null; if (!lp_durable_handles(SNUM(conn))) { return NT_STATUS_NOT_SUPPORTED; } /* * the checks for kernel oplocks * and similar things are done * in the vfs_default_durable_cookie() * call below. */ ZERO_STRUCT(cookie); ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie, (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); return status; } if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) { return NT_STATUS_INVALID_PARAMETER; } if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) { return NT_STATUS_INVALID_PARAMETER; } if (!cookie.allow_reconnect) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (strcmp(cookie.servicepath, conn->connectpath) != 0) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /* Create an smb_filename with stream_name == NULL. */ smb_fname = synthetic_smb_fname(talloc_tos(), cookie.base_name, NULL, NULL); if (smb_fname == NULL) { return NT_STATUS_NO_MEMORY; } ret = SMB_VFS_LSTAT(conn, smb_fname); if (ret == -1) { status = map_nt_error_from_unix_common(errno); DEBUG(1, ("Unable to lstat stream: %s => %s\n", smb_fname_str_dbg(smb_fname), nt_errstr(status))); return status; } if (!S_ISREG(smb_fname->st.st_ex_mode)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st); if (!file_id_equal(&cookie.id, &file_id)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /* * 1. check entry in locking.tdb */ lck = get_existing_share_mode_lock(mem_ctx, file_id); if (lck == NULL) { DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock " "not obtained from db\n")); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (lck->data->num_share_modes == 0) { DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode " "entry in existing share mode lock\n")); TALLOC_FREE(lck); return NT_STATUS_INTERNAL_DB_ERROR; } if (lck->data->num_share_modes > 1) { /* * It can't be durable if there is more than one handle * on the file. */ DEBUG(5, ("vfs_default_durable_reconnect: more than one " "share-mode entry - can not be durable\n")); TALLOC_FREE(lck); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } e = &lck->data->share_modes[0]; if (!server_id_is_disconnected(&e->pid)) { DEBUG(5, ("vfs_default_durable_reconnect: denying durable " "reconnect for handle that was not marked " "disconnected (e.g. smbd or cluster node died)\n")); TALLOC_FREE(lck); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (e->share_file_id != op->global->open_persistent_id) { DEBUG(5, ("vfs_default_durable_reconnect: denying durable " "share_file_id changed %llu != %llu" "(e.g. another client had opened the file)\n", (unsigned long long)e->share_file_id, (unsigned long long)op->global->open_persistent_id)); TALLOC_FREE(lck); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) && !CAN_WRITE(conn)) { DEBUG(5, ("vfs_default_durable_reconnect: denying durable " "share[%s] is not writeable anymore\n", lp_servicename(talloc_tos(), SNUM(conn)))); TALLOC_FREE(lck); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /* * 2. proceed with opening file */ status = fsp_new(conn, conn, &fsp); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("vfs_default_durable_reconnect: failed to create " "new fsp: %s\n", nt_errstr(status))); TALLOC_FREE(lck); return status; } fsp->fh->private_options = e->private_options; fsp->fh->gen_id = smbXsrv_open_hash(op); fsp->file_id = file_id; fsp->file_pid = smb1req->smbpid; fsp->vuid = smb1req->vuid; fsp->open_time = e->time; fsp->access_mask = e->access_mask; fsp->share_access = e->share_access; fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0); fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0); fsp->fnum = op->local_id; /* * TODO: * Do we need to store the modified flag in the DB? */ fsp->modified = false; /* * no durables for directories */ fsp->is_directory = false; /* * For normal files, can_lock == !is_directory */ fsp->can_lock = true; /* * We do not support aio write behind for smb2 */ fsp->aio_write_behind = false; fsp->oplock_type = e->op_type; fsp->initial_allocation_size = cookie.initial_allocation_size; fsp->fh->position_information = cookie.position_information; fsp->update_write_time_triggered = cookie.update_write_time_triggered; fsp->update_write_time_on_close = cookie.update_write_time_on_close; fsp->write_time_forced = cookie.write_time_forced; fsp->close_write_time = cookie.close_write_time; status = fsp_set_smb_fname(fsp, smb_fname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(lck); fsp_free(fsp); DEBUG(0, ("vfs_default_durable_reconnect: " "fsp_set_smb_fname failed: %s\n", nt_errstr(status))); return status; } op->compat = fsp; fsp->op = op; e->pid = messaging_server_id(conn->sconn->msg_ctx); e->op_mid = smb1req->mid; e->share_file_id = fsp->fh->gen_id; ok = brl_reconnect_disconnected(fsp); if (!ok) { status = NT_STATUS_INTERNAL_ERROR; DEBUG(1, ("vfs_default_durable_reconnect: " "failed to reopen brlocks: %s\n", nt_errstr(status))); TALLOC_FREE(lck); op->compat = NULL; fsp_free(fsp); return status; } /* * TODO: properly calculate open flags */ if (fsp->can_write && fsp->can_read) { flags = O_RDWR; } else if (fsp->can_write) { flags = O_WRONLY; } else if (fsp->can_read) { flags = O_RDONLY; } status = fd_open(conn, fsp, flags, 0 /* mode */); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(lck); DEBUG(1, ("vfs_default_durable_reconnect: failed to open " "file: %s\n", nt_errstr(status))); op->compat = NULL; fsp_free(fsp); return status; } /* * We now check the stat info stored in the cookie against * the current stat data from the file we just opened. * If any detail differs, we deny the durable reconnect, * because in that case it is very likely that someone * opened the file while the handle was disconnected, * which has to be interpreted as an oplock break. */ ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); if (ret == -1) { status = map_nt_error_from_unix_common(errno); DEBUG(1, ("Unable to fstat stream: %s => %s\n", smb_fname_str_dbg(smb_fname), nt_errstr(status))); ret = SMB_VFS_CLOSE(fsp); if (ret == -1) { DEBUG(0, ("vfs_default_durable_reconnect: " "SMB_VFS_CLOSE failed (%s) - leaking file " "descriptor\n", strerror(errno))); } TALLOC_FREE(lck); op->compat = NULL; fsp_free(fsp); return status; } if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) { ret = SMB_VFS_CLOSE(fsp); if (ret == -1) { DEBUG(0, ("vfs_default_durable_reconnect: " "SMB_VFS_CLOSE failed (%s) - leaking file " "descriptor\n", strerror(errno))); } TALLOC_FREE(lck); op->compat = NULL; fsp_free(fsp); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); if (!file_id_equal(&cookie.id, &file_id)) { ret = SMB_VFS_CLOSE(fsp); if (ret == -1) { DEBUG(0, ("vfs_default_durable_reconnect: " "SMB_VFS_CLOSE failed (%s) - leaking file " "descriptor\n", strerror(errno))); } TALLOC_FREE(lck); op->compat = NULL; fsp_free(fsp); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info, &fsp->fsp_name->st, fsp_str_dbg(fsp)); if (!ok) { ret = SMB_VFS_CLOSE(fsp); if (ret == -1) { DEBUG(0, ("vfs_default_durable_reconnect: " "SMB_VFS_CLOSE failed (%s) - leaking file " "descriptor\n", strerror(errno))); } TALLOC_FREE(lck); op->compat = NULL; fsp_free(fsp); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } status = set_file_oplock(fsp); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock " "after opening file: %s\n", nt_errstr(status))); ret = SMB_VFS_CLOSE(fsp); if (ret == -1) { DEBUG(0, ("vfs_default_durable_reconnect: " "SMB_VFS_CLOSE failed (%s) - leaking file " "descriptor\n", strerror(errno))); } TALLOC_FREE(lck); op->compat = NULL; fsp_free(fsp); return status; } status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(lck); DEBUG(1, ("vfs_default_durable_reconnect: " "vfs_default_durable_cookie - %s\n", nt_errstr(status))); op->compat = NULL; fsp_free(fsp); return status; } smb1req->chain_fsp = fsp; smb1req->smb2req->compat_chain_fsp = fsp; DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n", fsp_str_dbg(fsp))); /* * release the sharemode lock: this writes the changes */ lck->data->modified = true; TALLOC_FREE(lck); *result = fsp; *new_cookie = new_cookie_blob; return NT_STATUS_OK; }
static int ext4_destroy_inline_data_nolock(handle_t *handle, struct inode *inode) { struct ext4_inode_info *ei = EXT4_I(inode); struct ext4_xattr_ibody_find is = { .s = { .not_found = 0, }, }; struct ext4_xattr_info i = { .name_index = EXT4_XATTR_INDEX_SYSTEM, .name = EXT4_XATTR_SYSTEM_DATA, .value = NULL, .value_len = 0, }; int error; if (!ei->i_inline_off) return 0; error = ext4_get_inode_loc(inode, &is.iloc); if (error) return error; error = ext4_xattr_ibody_find(inode, &i, &is); if (error) goto out; error = ext4_journal_get_write_access(handle, is.iloc.bh); if (error) goto out; error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); if (error) goto out; memset((void *)ext4_raw_inode(&is.iloc)->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) { if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) { ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS); ext4_ext_tree_init(handle, inode); } } ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA); get_bh(is.iloc.bh); error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); EXT4_I(inode)->i_inline_off = 0; EXT4_I(inode)->i_inline_size = 0; ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); out: brelse(is.iloc.bh); if (error == -ENODATA) error = 0; return error; } static int ext4_read_inline_page(struct inode *inode, struct page *page) { void *kaddr; int ret = 0; size_t len; struct ext4_iloc iloc; BUG_ON(!PageLocked(page)); BUG_ON(!ext4_has_inline_data(inode)); BUG_ON(page->index); if (!EXT4_I(inode)->i_inline_off) { ext4_warning(inode->i_sb, "inode %lu doesn't have inline data.", inode->i_ino); goto out; } ret = ext4_get_inode_loc(inode, &iloc); if (ret) goto out; len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode)); kaddr = kmap_atomic(page); ret = ext4_read_inline_data(inode, kaddr, len, &iloc); flush_dcache_page(page); kunmap_atomic(kaddr); zero_user_segment(page, len, PAGE_CACHE_SIZE); SetPageUptodate(page); brelse(iloc.bh); out: return ret; }
handler_t http_response_prepare(server *srv, connection *con) { handler_t r; /* looks like someone has already done a decision */ if (con->mode == DIRECT && (con->http_status != 0 && con->http_status != 200)) { /* remove a packets in the queue */ if (con->file_finished == 0) { chunkqueue_reset(con->write_queue); } return HANDLER_FINISHED; } /* no decision yet, build conf->filename */ if (con->mode == DIRECT && buffer_is_empty(con->physical.path)) { char *qstr; /* we only come here when we have the parse the full request again * * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a * problem here as mod_setenv might get called multiple times * * fastcgi-auth might lead to a COMEBACK too * fastcgi again dead server too * * mod_compress might add headers twice too * * */ config_cond_cache_reset(srv, con); config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */ if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "run condition"); } /** * prepare strings * * - uri.path_raw * - uri.path (secure) * - uri.query * */ /** * Name according to RFC 2396 * * - scheme * - authority * - path * - query * * (scheme)://(authority)(path)?(query)#fragment * * */ /* initial scheme value. can be overwritten for example by mod_extforward later */ if (con->srv_socket->is_ssl) { buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https")); } else { buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http")); } buffer_copy_buffer(con->uri.authority, con->request.http_host); buffer_to_lower(con->uri.authority); /** their might be a fragment which has to be cut away */ if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) { buffer_string_set_length(con->request.uri, qstr - con->request.uri->ptr); } /** extract query string from request.uri */ if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) { buffer_copy_string (con->uri.query, qstr + 1); buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr); } else { buffer_reset (con->uri.query); buffer_copy_buffer(con->uri.path_raw, con->request.uri); } /* decode url to path * * - decode url-encodings (e.g. %20 -> ' ') * - remove path-modifiers (e.g. /../) */ if (con->request.http_method == HTTP_METHOD_OPTIONS && con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') { /* OPTIONS * ... */ buffer_copy_buffer(con->uri.path, con->uri.path_raw); } else { buffer_copy_buffer(srv->tmp_buf, con->uri.path_raw); buffer_urldecode_path(srv->tmp_buf); buffer_path_simplify(con->uri.path, srv->tmp_buf); } con->conditional_is_valid[COMP_SERVER_SOCKET] = 1; /* SERVERsocket */ con->conditional_is_valid[COMP_HTTP_SCHEME] = 1; /* Scheme: */ con->conditional_is_valid[COMP_HTTP_HOST] = 1; /* Host: */ con->conditional_is_valid[COMP_HTTP_REMOTE_IP] = 1; /* Client-IP */ con->conditional_is_valid[COMP_HTTP_REFERER] = 1; /* Referer: */ con->conditional_is_valid[COMP_HTTP_USER_AGENT] = /* User-Agent: */ con->conditional_is_valid[COMP_HTTP_LANGUAGE] = 1; /* Accept-Language: */ con->conditional_is_valid[COMP_HTTP_COOKIE] = 1; /* Cookie: */ con->conditional_is_valid[COMP_HTTP_REQUEST_METHOD] = 1; /* REQUEST_METHOD */ con->conditional_is_valid[COMP_HTTP_URL] = 1; /* HTTPurl */ con->conditional_is_valid[COMP_HTTP_QUERY_STRING] = 1; /* HTTPqs */ config_patch_connection(srv, con); #ifdef USE_OPENSSL if (con->srv_socket->is_ssl && con->conf.ssl_verifyclient) { https_add_ssl_entries(con); } #endif /* do we have to downgrade to 1.0 ? */ if (!con->conf.allow_http11) { con->request.http_version = HTTP_VERSION_1_0; } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- splitting Request-URI"); log_error_write(srv, __FILE__, __LINE__, "sb", "Request-URI : ", con->request.uri); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-scheme : ", con->uri.scheme); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-authority : ", con->uri.authority); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path (raw) : ", con->uri.path_raw); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path (clean): ", con->uri.path); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query); } /** * * call plugins * * - based on the raw URL * */ switch(r = plugins_call_handle_uri_raw(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r); break; } /** * * call plugins * * - based on the clean URL * */ switch(r = plugins_call_handle_uri_clean(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, ""); break; } if (con->request.http_method == HTTP_METHOD_OPTIONS && con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') { /* option requests are handled directly without checking of the path */ response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); con->http_status = 200; con->file_finished = 1; return HANDLER_FINISHED; } /*** * * border * * logical filename (URI) becomes a physical filename here * * * */ /* 1. stat() * ... ISREG() -> ok, go on * ... ISDIR() -> index-file -> redirect * * 2. pathinfo() * ... ISREG() * * 3. -> 404 * */ /* * SEARCH DOCUMENT ROOT */ /* set a default */ buffer_copy_buffer(con->physical.doc_root, con->conf.document_root); buffer_copy_buffer(con->physical.rel_path, con->uri.path); #if defined(__WIN32) || defined(__CYGWIN__) /* strip dots from the end and spaces * * windows/dos handle those filenames as the same file * * foo == foo. == foo..... == "foo... " == "foo.. ./" * * This will affect in some cases PATHINFO * * on native windows we could prepend the filename with \\?\ to circumvent * this behaviour. I have no idea how to push this through cygwin * * */ if (con->physical.rel_path->used > 1) { buffer *b = con->physical.rel_path; size_t len = buffer_string_length(b); /* strip trailing " /" or "./" once */ if (len > 1 && b->ptr[len - 1] == '/' && (b->ptr[len - 2] == ' ' || b->ptr[len - 2] == '.')) { len -= 2; } /* strip all trailing " " and "." */ while (len > 0 && ( ' ' == b->ptr[len-1] || '.' == b->ptr[len-1] ) ) --len; buffer_string_set_length(b, len); } #endif if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- before doc_root"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } /* the docroot plugin should set the doc_root and might also set the physical.path * for us (all vhost-plugins are supposed to set the doc_root) * */ switch(r = plugins_call_handle_docroot(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, ""); break; } /* MacOS X and Windows can't distiguish between upper and lower-case * * convert to lower-case */ if (con->conf.force_lowercase_filenames) { buffer_to_lower(con->physical.rel_path); } /* the docroot plugins might set the servername, if they don't we take http-host */ if (buffer_string_is_empty(con->server_name)) { buffer_copy_buffer(con->server_name, con->uri.authority); } /** * create physical filename * -> physical.path = docroot + rel_path * */ buffer_copy_buffer(con->physical.basedir, con->physical.doc_root); buffer_copy_buffer(con->physical.path, con->physical.doc_root); buffer_append_slash(con->physical.path); if (!buffer_string_is_empty(con->physical.rel_path) && con->physical.rel_path->ptr[0] == '/') { buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, buffer_string_length(con->physical.rel_path) - 1); } else { buffer_append_string_buffer(con->physical.path, con->physical.rel_path); } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } switch(r = plugins_call_handle_physical(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, ""); break; } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); log_error_write(srv, __FILE__, __LINE__, "sb", "Basedir :", con->physical.basedir); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } } /* * Noone catched away the file from normal path of execution yet (like mod_access) * * Go on and check of the file exists at all */ if (con->mode == DIRECT) { char *slash = NULL; char *pathinfo = NULL; int found = 0; stat_cache_entry *sce = NULL; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { /* file exists */ if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- file found"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } #ifdef HAVE_LSTAT if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { con->http_status = 403; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; }; #endif if (S_ISDIR(sce->st.st_mode)) { if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') { /* redirect to .../ */ http_response_redirect_to_directory(srv, con); return HANDLER_FINISHED; } #ifdef HAVE_LSTAT } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) { #else } else if (!S_ISREG(sce->st.st_mode)) { #endif /* any special handling of non-reg files ?*/ } } else { switch (errno) { case EACCES: con->http_status = 403; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; case ENAMETOOLONG: /* file name to be read was too long. return 404 */ case ENOENT: con->http_status = 404; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- file not found"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; case ENOTDIR: /* PATH_INFO ! :) */ break; default: /* we have no idea what happend. let's tell the user so. */ con->http_status = 500; buffer_reset(con->physical.path); log_error_write(srv, __FILE__, __LINE__, "ssbsb", "file not found ... or so: ", strerror(errno), con->uri.path, "->", con->physical.path); return HANDLER_FINISHED; } /* not found, perhaps PATHINFO */ buffer_copy_buffer(srv->tmp_buf, con->physical.path); do { if (slash) { buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr); } else { buffer_copy_buffer(con->physical.path, srv->tmp_buf); } if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { found = S_ISREG(sce->st.st_mode); break; } if (pathinfo != NULL) { *pathinfo = '\0'; } slash = strrchr(srv->tmp_buf->ptr, '/'); if (pathinfo != NULL) { /* restore '/' */ *pathinfo = '/'; } if (slash) pathinfo = slash; } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (buffer_string_length(con->physical.basedir) - 1))); if (found == 0) { /* no it really doesn't exists */ con->http_status = 404; if (con->conf.log_file_not_found) { log_error_write(srv, __FILE__, __LINE__, "sbsb", "file not found:", con->uri.path, "->", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; } #ifdef HAVE_LSTAT if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { con->http_status = 403; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; }; #endif /* we have a PATHINFO */ if (pathinfo) { size_t len = strlen(pathinfo), reqlen; if (con->conf.force_lowercase_filenames && len <= (reqlen = buffer_string_length(con->request.uri)) && 0 == strncasecmp(con->request.uri->ptr + reqlen - len, pathinfo, len)) { /* attempt to preserve case-insensitive PATH_INFO * (works in common case where mod_alias, mod_magnet, and other modules * have not modified the PATH_INFO portion of request URI, or did so * with exactly the PATH_INFO desired) */ buffer_copy_string_len(con->request.pathinfo, con->request.uri->ptr + reqlen - len, len); } else { buffer_copy_string_len(con->request.pathinfo, pathinfo, len); } /* * shorten uri.path */ buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - len); } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path); log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo); } } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } /* call the handlers */ switch(r = plugins_call_handle_subrequest_start(srv, con)) { case HANDLER_GO_ON: /* request was not handled */ break; case HANDLER_FINISHED: default: if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished"); } /* something strange happend */ return r; } /* if we are still here, no one wanted the file, status 403 is ok I think */ if (con->mode == DIRECT && con->http_status == 0) { switch (con->request.http_method) { case HTTP_METHOD_OPTIONS: con->http_status = 200; break; default: con->http_status = 403; } return HANDLER_FINISHED; } } switch(r = plugins_call_handle_subrequest(srv, con)) { case HANDLER_GO_ON: /* request was not handled, looks like we are done */ return HANDLER_FINISHED; case HANDLER_FINISHED: /* request is finished */ default: /* something strange happend */ return r; } /* can't happen */ return HANDLER_COMEBACK; }
static long do_sys_truncate(const char __user *pathname, loff_t length) { struct path path; struct inode *inode; int error; error = -EINVAL; if (length < 0) /* sorry, but loff_t says... */ goto out; error = user_path(pathname, &path); if (error) goto out; inode = path.dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ error = -EISDIR; if (S_ISDIR(inode->i_mode)) goto dput_and_out; error = -EINVAL; if (!S_ISREG(inode->i_mode)) goto dput_and_out; error = mnt_want_write(path.mnt); if (error) goto dput_and_out; error = inode_permission(inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; error = -EPERM; if (IS_APPEND(inode)) goto mnt_drop_write_and_out; error = get_write_access(inode); if (error) goto mnt_drop_write_and_out; /* * Make sure that there are no leases. get_write_access() protects * against the truncate racing with a lease-granting setlease(). */ error = break_lease(inode, O_WRONLY); if (error) goto put_write_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) error = security_path_truncate(&path); if (!error) error = do_truncate(path.dentry, length, 0, NULL); put_write_and_out: put_write_access(inode); mnt_drop_write_and_out: mnt_drop_write(path.mnt); dput_and_out: path_put(&path); out: return error; }
static int au_cmoo(struct dentry *dentry) { int err, cmoo; unsigned int udba; struct path h_path; struct au_pin pin; struct au_cp_generic cpg = { .dentry = dentry, .bdst = -1, .bsrc = -1, .len = -1, .pin = &pin, .flags = AuCpup_DTIME | AuCpup_HOPEN }; struct inode *inode, *delegated; struct super_block *sb; struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; pid_t pid; struct au_branch *br; struct dentry *parent; struct au_hinode *hdir; DiMustWriteLock(dentry); inode = dentry->d_inode; IiMustWriteLock(inode); err = 0; if (IS_ROOT(dentry)) goto out; cpg.bsrc = au_dbstart(dentry); if (!cpg.bsrc) goto out; sb = dentry->d_sb; sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; pid = au_fhsm_pid(fhsm); if (pid && (current->pid == pid || current->real_parent->pid == pid)) goto out; br = au_sbr(sb, cpg.bsrc); cmoo = au_br_cmoo(br->br_perm); if (!cmoo) goto out; if (!S_ISREG(inode->i_mode)) cmoo &= AuBrAttr_COO_ALL; if (!cmoo) goto out; parent = dget_parent(dentry); di_write_lock_parent(parent); err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); cpg.bdst = err; if (unlikely(err < 0)) { err = 0; /* there is no upper writable branch */ goto out_dgrade; } AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); /* do not respect the coo attrib for the target branch */ err = au_cpup_dirs(dentry, cpg.bdst); if (unlikely(err)) goto out_dgrade; di_downgrade_lock(parent, AuLock_IR); udba = au_opt_udba(sb); err = au_pin(&pin, dentry, cpg.bdst, udba, AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (unlikely(err)) goto out_parent; err = au_sio_cpup_simple(&cpg); au_unpin(&pin); if (unlikely(err)) goto out_parent; if (!(cmoo & AuBrWAttr_MOO)) goto out_parent; /* success */ err = au_pin(&pin, dentry, cpg.bsrc, udba, AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (unlikely(err)) goto out_parent; h_path.mnt = au_br_mnt(br); h_path.dentry = au_h_dptr(dentry, cpg.bsrc); hdir = au_hi(parent->d_inode, cpg.bsrc); delegated = NULL; err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); au_unpin(&pin); /* todo: keep h_dentry or not? */ if (unlikely(err == -EWOULDBLOCK)) { pr_warn("cannot retry for NFSv4 delegation" " for an internal unlink\n"); iput(delegated); } if (unlikely(err)) { pr_err("unlink %pd after coo failed (%d), ignored\n", dentry, err); err = 0; } goto out_parent; /* success */ out_dgrade: di_downgrade_lock(parent, AuLock_IR); out_parent: di_read_unlock(parent, AuLock_IR); dput(parent); out: AuTraceErr(err); return err; } int au_do_open(struct file *file, struct au_do_open_args *args) { int err, no_lock = args->no_lock; struct dentry *dentry; struct au_finfo *finfo; if (!no_lock) err = au_finfo_init(file, args->fidir); else { lockdep_off(); err = au_finfo_init(file, args->fidir); lockdep_on(); } if (unlikely(err)) goto out; dentry = file->f_dentry; AuDebugOn(IS_ERR_OR_NULL(dentry)); if (!no_lock) { di_write_lock_child(dentry); err = au_cmoo(dentry); di_downgrade_lock(dentry, AuLock_IR); if (!err) err = args->open(file, vfsub_file_flags(file), NULL); di_read_unlock(dentry, AuLock_IR); } else { err = au_cmoo(dentry); if (!err) err = args->open(file, vfsub_file_flags(file), args->h_file); if (!err && au_fbstart(file) != au_dbstart(dentry)) /* * cmoo happens after h_file was opened. * need to refresh file later. */ atomic_dec(&au_fi(file)->fi_generation); } finfo = au_fi(file); if (!err) { finfo->fi_file = file; au_sphl_add(&finfo->fi_hlist, &au_sbi(file->f_dentry->d_sb)->si_files); } if (!no_lock) fi_write_unlock(file); else { lockdep_off(); fi_write_unlock(file); lockdep_on(); } if (unlikely(err)) { finfo->fi_hdir = NULL; au_finfo_fin(file); } out: return err; }
/* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and * switching the fsuid/fsgid around to the real ones. */ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) { const struct cred *old_cred; struct cred *override_cred; struct path path; struct inode *inode; int res; unsigned int lookup_flags = LOOKUP_FOLLOW; if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL; override_cred = prepare_creds(); if (!override_cred) return -ENOMEM; override_cred->fsuid = override_cred->uid; override_cred->fsgid = override_cred->gid; if (!issecure(SECURE_NO_SETUID_FIXUP)) { /* Clear the capabilities if we switch to a non-root user */ kuid_t root_uid = make_kuid(override_cred->user_ns, 0); if (!uid_eq(override_cred->uid, root_uid)) cap_clear(override_cred->cap_effective); else override_cred->cap_effective = override_cred->cap_permitted; } old_cred = override_creds(override_cred); retry: res = user_path_at(dfd, filename, lookup_flags, &path); if (res) goto out; inode = path.dentry->d_inode; if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { /* * MAY_EXEC on regular files is denied if the fs is mounted * with the "noexec" flag. */ res = -EACCES; if (path.mnt->mnt_flags & MNT_NOEXEC) goto out_path_release; } res = inode_permission(inode, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; /* * This is a rare case where using __mnt_is_readonly() * is OK without a mnt_want/drop_write() pair. Since * no actual write to the fs is performed here, we do * not need to telegraph to that to anyone. * * By doing this, we accept that this access is * inherently racy and know that the fs may change * state before we even see this result. */ if (__mnt_is_readonly(path.mnt)) res = -EROFS; out_path_release: path_put(&path); if (retry_estale(res, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; goto retry; } out: revert_creds(old_cred); put_cred(override_cred); return res; }
bool sieve_binary_file_open (struct sieve_binary_file *file, struct sieve_instance *svinst, const char *path, enum sieve_error *error_r) { int fd; bool result = TRUE; struct stat st; if ( error_r != NULL ) *error_r = SIEVE_ERROR_NONE; if ( (fd=open(path, O_RDONLY)) < 0 ) { switch ( errno ) { case ENOENT: if ( error_r != NULL ) *error_r = SIEVE_ERROR_NOT_FOUND; break; case EACCES: sieve_sys_error(svinst, "binary open: failed to open: %s", eacces_error_get("open", path)); if ( error_r != NULL ) *error_r = SIEVE_ERROR_NO_PERMISSION; break; default: sieve_sys_error(svinst, "binary open: failed to open: " "open(%s) failed: %m", path); if ( error_r != NULL ) *error_r = SIEVE_ERROR_TEMP_FAILURE; break; } return FALSE; } if ( fstat(fd, &st) < 0 ) { if ( errno != ENOENT ) { sieve_sys_error(svinst, "binary open: fstat(fd=%s) failed: %m", path); } result = FALSE; } if ( result && !S_ISREG(st.st_mode) ) { sieve_sys_error(svinst, "binary open: %s is not a regular file", path); result = FALSE; } if ( !result ) { if ( close(fd) < 0 ) { sieve_sys_error(svinst, "binary open: close(fd=%s) failed after error: %m", path); } return FALSE; } file->svinst = svinst; file->fd = fd; file->st = st; return TRUE; }