aboutsummaryrefslogtreecommitdiff
path: root/src/diskio.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-08-22 13:23:03 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-08-22 13:23:03 +0000
commit180ca1d87d2bf69d9dbb0acb76422e9ae15f930c (patch)
treeb14651206aaec8e03fdfdce9e04433068fa62648 /src/diskio.c
parent708a28a2f5bd2384e4c254a47d069ec4d9ef697e (diff)
downloadwydawca-180ca1d87d2bf69d9dbb0acb76422e9ae15f930c.tar.gz
wydawca-180ca1d87d2bf69d9dbb0acb76422e9ae15f930c.tar.bz2
Implement all directives
git-svn-id: file:///svnroot/wydawca/trunk@284 6bb4bd81-ecc2-4fd4-a2d4-9571d19c0d33
Diffstat (limited to 'src/diskio.c')
-rw-r--r--src/diskio.c305
1 files changed, 224 insertions, 81 deletions
diff --git a/src/diskio.c b/src/diskio.c
index 333c07e..6eaffa0 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -15,8 +15,7 @@
with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "wydawca.h"
-#include <sys/types.h>
-#include <sys/wait.h>
+#include "save-cwd.h"
#if defined USE_SENDFILE
# if defined __linux__ && defined HAVE_SYS_SENDFILE_H
# include <sys/sendfile.h>
@@ -25,6 +24,16 @@
# endif
#endif
+int
+sub_dir_p (char *arg, char *dir)
+{
+ int dlen = strlen (dir);
+
+ return strlen (arg) > dlen
+ && memcmp (dir, arg, dlen) == 0
+ && arg[dlen] == '/';
+}
+
char *
concat_dir (const char *base, const char *name, size_t *pbaselen)
{
@@ -255,9 +264,6 @@ do_move_file (const char *file, const char *dst_file, uid_t uid, gid_t gid)
int
tar_append_file (const char *archive, const char *file)
{
- FILE *fp;
- pid_t pid, npid;
- int i, status;
int rc;
const char *argv[6];
@@ -272,73 +278,19 @@ tar_append_file (const char *archive, const char *file)
argv[3] = "-r";
argv[4] = file;
argv[5] = NULL;
-
- fp = start_prog (6, argv, &pid);
- if (!fp)
- {
- logmsg (LOG_CRIT,
- "cannot start archiver program `%s'", tar_command_name);
- return 1;
- }
-
- for (i = 0; i < 5 && (npid = waitpid (pid, &status, WNOHANG)) == 0; i++)
- sleep (1);
- switch (npid)
+ switch (wydawca_exec (6, argv, NULL))
{
- case -1:
- logmsg (LOG_CRIT,
- "cannot execute archiver program `%s'; waitpid failed: %s",
- tar_command_name, strerror (errno));
- fclose (fp);
- return 1;
+ case exec_success:
+ return 0;
- case 0:
- logmsg (LOG_CRIT,
- "cannot execute archiver program `%s': "
- "program did not respond within 5 seconds: %s",
- tar_command_name, strerror (errno));
- kill (pid, SIGKILL);
- fclose (fp);
- return 1;
-
- default:
+ case exec_fail:
+ case exec_error:
+ logmsg (LOG_ERR, "cannot archive %s", file);
break;
}
- if (WIFEXITED (status))
- {
- rc = WEXITSTATUS (status);
- if (rc)
- {
- logmsg (LOG_ERR, "cannot archive %s: %s finished with code %d",
- file, tar_command_name, rc);
- log_output (LOG_ERR, argv[0], fp);
- }
- else if (debug_level > 1)
- log_output (LOG_DEBUG, argv[0], fp);
- }
- else
- {
- rc = 1;
- if (WIFSIGNALED (status))
- logmsg (LOG_ERR,
- "cannot archive %s: "
- "%s terminated on signal %d",
- file, tar_command_name, WTERMSIG (status));
- else if (WIFSTOPPED (status))
- logmsg (LOG_ERR,
- "cannot archive %s: "
- "%s stopped on signal %d",
- file, tar_command_name, WTERMSIG (status));
- else
- logmsg (LOG_ERR,
- "cannot archive %s: "
- "%s terminated with unrecognized status",
- file, tar_command_name);
- }
- fclose (fp);
- return rc;
+ return 1;
}
int
@@ -346,7 +298,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
struct archive_descr *archive, uid_t uid, gid_t gid,
const char *reldir)
{
- int rc;
+ int rc = 0;
char *adir;
char *file_name;
@@ -413,9 +365,9 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
}
int
-archive_file (const char *dst_file, const char *dst_dir, const char *file,
- struct archive_descr *archive, uid_t uid, gid_t gid,
- const char *reldir)
+do_archive_file (const char *dst_file, const char *dst_dir, const char *file,
+ struct archive_descr *archive, uid_t uid, gid_t gid,
+ const char *reldir)
{
switch (archive->type)
{
@@ -431,28 +383,219 @@ archive_file (const char *dst_file, const char *dst_dir, const char *file,
return 0;
}
-
int
-move_file (struct file_register *reg, enum file_type file_id,
- const char *dst_dir, const char *reldir,
- struct archive_descr *archive)
+move_file (struct file_triplet *trp, struct directory_pair *dpair,
+ enum file_type file_id, const char *reldir)
{
- char *dst_file = concat_dir (dst_dir, reg->file[file_id].name, NULL);
+ char *dst_file;
int rc = 0;
+ char *dst_dir = create_directory (dpair->dest_dir, reldir,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+
+ if (!dst_dir)
+ return 1;
+ dst_file = concat_dir (dst_dir, trp->file[file_id].name, NULL);
if (debug_level)
- logmsg (LOG_DEBUG, "installing %s to %s", reg->file[file_id].name,
+ logmsg (LOG_DEBUG, "installing %s to %s", trp->file[file_id].name,
dst_dir);
if (access (dst_file, F_OK) == 0)
- archive_file (dst_file, dst_dir, reg->file[file_id].name,
- archive, reg->file[file_id].uid, reg->gid, reldir);
+ rc = do_archive_file (dst_file, dst_dir, trp->file[file_id].name,
+ &dpair->archive,
+ TRIPLET_UID (trp), TRIPLET_GID (trp), reldir);
- if (!dry_run_mode)
- rc = do_move_file (reg->file[file_id].name, dst_file,
- reg->file[file_id].uid, reg->gid);
+ if (!dry_run_mode && rc == 0)
+ rc = do_move_file (trp->file[file_id].name, dst_file,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
free (dst_file);
+ free (dst_dir);
return rc;
}
+int
+archive_file (struct file_triplet *trp, struct directory_pair *dpair,
+ const char *file_name, const char *reldir)
+{
+ char *dst_file;
+ int rc = 0;
+ char *dst_dir = create_directory (dpair->dest_dir, reldir,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+
+ if (!dst_dir)
+ return 1;
+
+ dst_file = safe_file_name (concat_dir (dst_dir, file_name, NULL));
+ if (!sub_dir_p (dst_file, dpair->dest_dir))
+ {
+ logmsg (LOG_ERR, "file to be archived `%s' does not lie under `%s'",
+ dst_file, dpair->dest_dir);
+ free (dst_file);
+ free (dst_dir);
+ return 1;
+ }
+
+ if (access (dst_file, F_OK) == 0)
+ {
+ if (debug_level)
+ logmsg (LOG_DEBUG, "Archiving file `%s'", dst_file);
+ rc = do_archive_file (dst_file, dst_dir, file_name, &dpair->archive,
+ TRIPLET_UID (trp), TRIPLET_GID (trp), reldir);
+ }
+ else
+ logmsg (LOG_NOTICE, "Nothing to archive: file `%s' does not exist",
+ dst_file);
+
+ free (dst_file);
+ free (dst_dir);
+ return rc;
+}
+
+int
+symlink_file (struct file_triplet *trp, struct directory_pair *dpair,
+ const char *reldir,
+ const char *wanted_src, const char *wanted_dst)
+{
+ char *dst_file;
+ int rc = 0;
+ struct saved_cwd cwd;
+ char *dst_dir = create_directory (dpair->dest_dir, reldir,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+ char *src, *dst;
+
+ if (!dst_dir)
+ return 1;
+
+ if (save_cwd (&cwd))
+ {
+ logmsg (LOG_ERR, "cannot save current directory: %s",
+ strerror (errno));
+ return 1;
+ }
+
+ src = safe_file_name_alloc (wanted_src);
+ if (!sub_dir_p (src, dpair->dest_dir))
+ {
+ logmsg (LOG_ERR, "symlink source `%s' does not lie under `%s'",
+ src, dpair->dest_dir);
+ free (src);
+ return 1;
+ }
+
+ dst = safe_file_name_alloc (wanted_dst);
+ if (!sub_dir_p (dst, dpair->dest_dir))
+ {
+ logmsg (LOG_ERR, "symlink destination `%s' does not lie under `%s'",
+ dst, dpair->dest_dir);
+ free (src);
+ free (dst);
+ return 1;
+ }
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, "symlinking %s to %s in directory %s",
+ src, dst, dst_dir);
+
+ if (!dry_run_mode)
+ {
+ char *p = strrchr (dst, '/');
+ if (p > dst)
+ {
+ char *dir;
+
+ *p = 0;
+ dir = create_directory (dpair->dest_dir, dst,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+ if (!dir)
+ rc = 1;
+ else
+ free (dir);
+ *p = '/';
+ }
+
+ if (rc == 0)
+ {
+ rc = link (src, dst);
+ if (rc)
+ logmsg (LOG_ERR,
+ "symlinking %s to %s in directory %s failed: %s",
+ src, dst, dst_dir, strerror (errno));
+ }
+ }
+
+ if (restore_cwd (&cwd))
+ {
+ logmsg (LOG_EMERG, "cannot restore current directory: %s",
+ strerror (errno));
+ exit (1);
+ }
+
+ free (src);
+ free (dst);
+ free (dst_dir);
+ return rc;
+}
+
+static int
+do_rmsymlink_file (const char *dst_file)
+{
+ struct stat st;
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, "Removing symbolic link %s", dst_file);
+
+ if (stat (dst_file, &st))
+ {
+ if (errno == ENOENT)
+ {
+ logmsg (LOG_NOTICE, "Symlink `%s' does not exist", dst_file);
+ return 0;
+ }
+ if (!S_ISLNK (st.st_mode))
+ {
+ logmsg (LOG_ERR, "Refusing to unlink %s: is not a symlink",
+ dst_file);
+ return 1;
+ }
+ }
+ if (dry_run_mode)
+ return 0;
+ if (unlink (dst_file))
+ {
+ logmsg (LOG_ERR, "Cannot unlink %s: %s", dst_file, strerror (errno));
+ return 1;
+ }
+ return 0;
+}
+
+int
+rmsymlink_file (struct file_triplet *trp, struct directory_pair *dpair,
+ const char *reldir, const char *file_name)
+{
+ char *dst_file;
+ int rc = 0;
+ char *dst_dir = create_directory (dpair->dest_dir, reldir,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+
+ if (!dst_dir)
+ return 1;
+
+ dst_file = safe_file_name (concat_dir (dst_dir, file_name, NULL));
+ if (!sub_dir_p (dst_file, dpair->dest_dir))
+ {
+ logmsg (LOG_ERR, "refusing to remove a symlink `%s' that is not "
+ "located under `%s'",
+ dst_file, dpair->dest_dir);
+ free (dst_file);
+ free (dst_dir);
+ return 1;
+ }
+
+ rc = do_rmsymlink_file (dst_file);
+
+ free (dst_file);
+ free (dst_dir);
+ return rc;
+}
+

Return to:

Send suggestions and report system problems to the System administrator.