From cbffab246997fb5a06211dfb706b54e5ae5bb59f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 16:58:51 +0200 Subject: Adding upstream version 1.21.22. Signed-off-by: Daniel Baumann --- lib/dpkg/file.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 lib/dpkg/file.c (limited to 'lib/dpkg/file.c') diff --git a/lib/dpkg/file.c b/lib/dpkg/file.c new file mode 100644 index 0000000..4d02520 --- /dev/null +++ b/lib/dpkg/file.c @@ -0,0 +1,257 @@ +/* + * libdpkg - Debian packaging suite library routines + * file.c - file handling functions + * + * Copyright © 1994, 1995 Ian Jackson + * Copyright © 2008-2012 Guillem Jover + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/** + * Check whether a filename is executable. + * + * @param filename The filename to check. + */ +bool +file_is_exec(const char *filename) +{ + struct stat st; + + if (stat(filename, &st) < 0) + return false; + + if (!S_ISREG(st.st_mode)) + return false; + + return st.st_mode & 0111; +} + +/** + * Copy file ownership and permissions from one file to another. + * + * @param src The source filename. + * @param dst The destination filename. + */ +void +file_copy_perms(const char *src, const char *dst) +{ + struct stat stab; + + if (stat(src, &stab) == -1) { + if (errno == ENOENT) + return; + ohshite(_("unable to stat source file '%.250s'"), src); + } + + if (chown(dst, stab.st_uid, stab.st_gid) == -1) + ohshite(_("unable to change ownership of target file '%.250s'"), + dst); + + if (chmod(dst, (stab.st_mode & ~S_IFMT)) == -1) + ohshite(_("unable to set mode of target file '%.250s'"), dst); +} + +static int +file_slurp_fd(int fd, const char *filename, struct varbuf *vb, + struct dpkg_error *err) +{ + struct stat st; + + if (fstat(fd, &st) < 0) + return dpkg_put_errno(err, _("cannot stat %s"), filename); + + if (!S_ISREG(st.st_mode)) + return dpkg_put_error(err, _("%s is not a regular file"), + filename); + + if (st.st_size == 0) + return 0; + + varbuf_init(vb, st.st_size); + if (fd_read(fd, vb->buf, st.st_size) < 0) + return dpkg_put_errno(err, _("cannot read %s"), filename); + vb->used = st.st_size; + + return 0; +} + +int +file_slurp(const char *filename, struct varbuf *vb, struct dpkg_error *err) +{ + int fd; + int rc; + + varbuf_init(vb, 0); + + fd = open(filename, O_RDONLY); + if (fd < 0) + return dpkg_put_errno(err, _("cannot open %s"), filename); + + rc = file_slurp_fd(fd, filename, vb, err); + + (void)close(fd); + + return rc; +} + +static void +file_lock_setup(struct flock *fl, short type) +{ + fl->l_type = type; + fl->l_whence = SEEK_SET; + fl->l_start = 0; + fl->l_len = 0; + fl->l_pid = 0; +} + +/** + * Unlock a previously locked file. + */ +void +file_unlock(int lockfd, const char *lockfile, const char *lockdesc) +{ + struct flock fl; + + if (lockfd < 0) + internerr("%s (%s) fd is %d < 0", lockdesc, lockfile, lockfd); + + file_lock_setup(&fl, F_UNLCK); + + if (fcntl(lockfd, F_SETLK, &fl) == -1) + ohshite(_("unable to unlock %s"), lockdesc); +} + +static void +file_unlock_cleanup(int argc, void **argv) +{ + int lockfd = *(int *)argv[0]; + const char *lockfile = argv[1]; + const char *lockdesc = argv[2]; + + file_unlock(lockfd, lockfile, lockdesc); +} + +/** + * Check if a file has a lock acquired. + * + * @param lockfd The file descriptor for the lock. + * @param filename The file name associated to the file descriptor. + */ +bool +file_is_locked(int lockfd, const char *filename) +{ + struct flock fl; + + file_lock_setup(&fl, F_WRLCK); + + if (fcntl(lockfd, F_GETLK, &fl) == -1) + ohshit(_("unable to check file '%s' lock status"), filename); + + if (fl.l_type == F_WRLCK && fl.l_pid != getpid()) + return true; + else + return false; +} + +/** + * Lock a file. + * + * @param lockfd The pointer to the lock file descriptor. It must be allocated + * statically as its addresses is passed to a cleanup handler. + * @param flags The lock flags specifying what type of locking to perform. + * @param filename The name of the file to lock. + * @param desc The description of the file to lock. + */ +void +file_lock(int *lockfd, enum file_lock_flags flags, const char *filename, + const char *desc) +{ + struct flock fl; + int lock_cmd; + + setcloexec(*lockfd, filename); + + file_lock_setup(&fl, F_WRLCK); + + if (flags == FILE_LOCK_WAIT) + lock_cmd = F_SETLKW; + else + lock_cmd = F_SETLK; + + if (fcntl(*lockfd, lock_cmd, &fl) == -1) { + const char *warnmsg; + + if (errno != EACCES && errno != EAGAIN) + ohshite(_("unable to lock %s"), desc); + + warnmsg = _("Note: removing the lock file is always wrong, " + "can damage the locked area\n" + "and the entire system. " + "See ."); + + file_lock_setup(&fl, F_WRLCK); + if (fcntl(*lockfd, F_GETLK, &fl) == -1) + ohshit(_("%s was locked by another process\n%s"), + desc, warnmsg); + + ohshit(_("%s was locked by another process with pid %d\n%s"), + desc, fl.l_pid, warnmsg); + } + + push_cleanup(file_unlock_cleanup, ~0, 3, lockfd, filename, desc); +} + +void +file_show(const char *filename) +{ + struct pager *pager; + struct dpkg_error err; + int fd, rc; + + if (filename == NULL) + internerr("filename is NULL"); + + fd = open(filename, O_RDONLY); + if (fd < 0) + ohshite(_("cannot open file %s"), filename); + + pager = pager_spawn(_("pager to show file")); + rc = fd_fd_copy(fd, STDOUT_FILENO, -1, &err); + pager_reap(pager); + + close(fd); + + if (rc < 0 && err.syserrno != EPIPE) { + errno = err.syserrno; + ohshite(_("cannot write file %s into the pager"), filename); + } +} -- cgit v1.2.3