aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-02-08 19:23:42 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-02-08 19:23:42 +0200
commit90ea6a2cf2e646441b2c2ea4bf480fe8e4152de7 (patch)
tree612823f0f3983e47cde17b549a8d85d5913cb0b3
parent0c6bb13d6b5df94417f2878cd5a4aa4ddcd78a39 (diff)
downloadidest-90ea6a2cf2e646441b2c2ea4bf480fe8e4152de7.tar.gz
idest-90ea6a2cf2e646441b2c2ea4bf480fe8e4152de7.tar.bz2
Preparation for implementing set/delete operations.
* src/backup.c: New file. * gnulib.modules: Request backupfile, dirname and save-cwd. * src/Makefile.am (idest_SOURCES): Add backup.c * src/cmdline.opt: New options --backup and --backup-directory. * src/id3v2.c: Minor change. * src/idest.h: Include backupfile.h (backup_type, backup_dir): New externs. * src/main.c: Minor change.
-rw-r--r--gnulib.modules3
-rw-r--r--src/Makefile.am1
-rw-r--r--src/backup.c220
-rw-r--r--src/cmdline.opt13
-rw-r--r--src/id3v2.c8
-rw-r--r--src/idest.h6
-rw-r--r--src/main.c12
7 files changed, 257 insertions, 6 deletions
diff --git a/gnulib.modules b/gnulib.modules
index 3487fe9..4296821 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -2,9 +2,12 @@
# A module name per line. Empty lines and comments are ignored.
argmatch
+backupfile
+dirname
getopt
gitlog-to-changelog
error
linked-list
progname
+save-cwd
xalloc
diff --git a/src/Makefile.am b/src/Makefile.am
index 6f8066a..212e454 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,6 +16,7 @@
bin_PROGRAMS=idest
idest_SOURCES=\
+ backup.c\
idest.h\
id3v1.c\
id3v1.h\
diff --git a/src/backup.c b/src/backup.c
new file mode 100644
index 0000000..495d6ac
--- /dev/null
+++ b/src/backup.c
@@ -0,0 +1,220 @@
+/* This file is part of Idest.
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ Idest 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 3, or (at your option)
+ any later version.
+
+ Idest 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 Idest. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "idest.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "save-cwd.h"
+#include "dirname.h"
+#include "backupfile.h"
+
+#define MKDIR_PERMISSIONS 0777
+#define CREAT_PERMISSIONS 0666
+
+/* Concatenate BASE directory name, a single directory separator (/) and
+ NAME. Return in PBASELEN the length of BASE, not counting eventual trailing
+ slash. */
+char *
+concat_dir(const char *base, const char *name, size_t *pbaselen)
+{
+ size_t len = strlen(base);
+ size_t size;
+ char *dir;
+
+ while (len > 0 && base[len - 1] == '/')
+ len--;
+
+ size = len + 1 + strlen(name);
+ dir = xmalloc(size + 1);
+ memcpy(dir, base, len);
+ dir[len++] = '/';
+ strcpy(dir + len, name);
+
+ if (pbaselen)
+ *pbaselen = len;
+ return dir;
+}
+
+/* Create the directory DIR, eventually creating all intermediate directories
+ starting from DIR + BASELEN. */
+int
+create_hierarchy(char *dir, size_t baselen)
+{
+ int rc;
+ struct stat st;
+ char *p;
+
+ if (stat(dir, &st) == 0) {
+ if (!S_ISDIR(st.st_mode)) {
+ error(0, 0, "component %s is not a directory", dir);
+ return 1;
+ }
+ return 0;
+ } else if (errno != ENOENT) {
+ error(0, errno, "cannot stat file %s", dir);
+ return 1;
+ }
+
+ p = strrchr(dir, '/');
+ if (p) {
+ if (p - dir + 1 < baselen) {
+ error(0, 0, "base directory %s does not exist", dir);
+ return 1;
+ }
+ *p = 0;
+ }
+
+ rc = create_hierarchy(dir, baselen);
+ if (rc == 0) {
+ if (p)
+ *p = '/';
+ if (mkdir(dir, MKDIR_PERMISSIONS)) {
+ error(0, errno, "cannot create directory %s", dir);
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
+/* Create a directory BASE/NAME (with eventual intermediate directories in
+ NAME). */
+char *
+create_directory(const char *base, const char *name)
+{
+ size_t baselen;
+ char *dir = concat_dir(base, name, &baselen);
+
+ if (create_hierarchy(dir, baselen)) {
+ free(dir);
+ dir = NULL;
+ }
+ return dir;
+}
+
+
+/* Copy FILE to DST_FILE. */
+int
+copy_file(const char *file, const char *dst_file)
+{
+ int in_fd, out_fd;
+ struct stat st;
+ char *buf = NULL;
+ size_t bufsize;
+ size_t fsize;
+ int rc;
+
+ in_fd = open(file, O_RDONLY);
+
+ if (in_fd == -1) {
+ error(0, errno,
+ "cannot open source file %s for reading", file);
+ return 1;
+ }
+
+ if (fstat(in_fd, &st)) {
+ error(0, errno, "cannot stat source file %s", file);
+ close(in_fd);
+ return 1;
+ }
+
+ out_fd = creat(dst_file, CREAT_PERMISSIONS);
+ if (out_fd == -1) {
+ error(0, errno, "cannot create destination file %s", file);
+ close(in_fd);
+ return 1;
+ }
+
+ for (bufsize = fsize;
+ bufsize > 0 && (buf = malloc(bufsize)) == NULL;
+ bufsize /= 2);
+ if (bufsize == 0)
+ xalloc_die();
+
+ rc = 0;
+ fsize = st.st_size;
+ while (fsize > 0) {
+ size_t rest;
+ size_t rdbytes;
+
+ rest = fsize > bufsize ? bufsize : fsize;
+ rdbytes = read(in_fd, buf, rest);
+ if (rdbytes == -1) {
+ error(0, errno, "unexpected error reading %s", file);
+ rc = 1;
+ break;
+ }
+ rest = write(out_fd, buf, rdbytes);
+ if (rest == -1) {
+ error(0, errno, "unexpected error writing to %s",
+ dst_file);
+ rc = 1;
+ break;
+ } else if (rest != rdbytes) {
+ error(0, 0, "short write on %s", dst_file);
+ rc = 1;
+ }
+ fsize -= rdbytes;
+ }
+ free(buf);
+
+ close(in_fd);
+ close(out_fd);
+ if (rc) {
+ unlink(dst_file);
+ return 1;
+ }
+ return 0;
+}
+
+/* Backup a file */
+int
+backup_file(const char *file)
+{
+ int rc = 0;
+ char *adir;
+ char *new_name;
+
+ if (backup_dir) {
+ if (file[0] == '/')
+ new_name = concat_dir(backup_dir,
+ last_component(file), NULL);
+ else
+ new_name = concat_dir(backup_dir, file, NULL);
+ if (access(new_name, F_OK) == 0) {
+ if (backup_type == no_backups) {
+ if (unlink(new_name))
+ error(0, errno,
+ "cannot unlink backup file %s",
+ new_name);
+ /* Try to continue anyway */
+ } else {
+ char *bfn = find_backup_file_name(new_name,
+ backup_type);
+ copy_file(new_name, bfn);
+ /* Continue no matter what the result of
+ copy_file was */
+ }
+ }
+ } else if (backup_type == no_backups)
+ return 0;
+ else
+ new_name = find_backup_file_name(file, backup_type);
+
+ rc = copy_file(file, new_name);
+ free(new_name);
+ return rc;
+}
+
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 2df4cfd..8037afb 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -53,7 +53,6 @@ BEGIN
ed_list_add_assignment(optarg, p);
END
-
OPTION(id-version,V,VERSION,
[<set ID3 version>])
BEGIN
@@ -68,6 +67,18 @@ BEGIN
latin1_output = 1;
END
+OPTION(backup,,CONTROL,
+ [<backup before removal, choose version CONTROL>])
+BEGIN
+ backup_type = xget_version ("--backup", optarg);
+END
+
+OPTION(backup-directory,,DIR,
+ [<backup to given DIR>])
+BEGIN
+ backup_dir = optarg;
+END
+
OPTIONS_END
void
diff --git a/src/id3v2.c b/src/id3v2.c
index b8faa19..5ca9591 100644
--- a/src/id3v2.c
+++ b/src/id3v2.c
@@ -19,6 +19,14 @@
void
set_id3v2(const char *name)
{
+ struct id3_file *file;
+
+ file = id3_file_open(name, ID3_FILE_MODE_READWRITE);
+ if (!file)
+ error(1, errno, "cannot open file %s", name);
+ /*FIXME...*/
+ id3_file_close(file);
+ error(1, 0, "setting ID3 v2 frames is not yet implemented");
}
diff --git a/src/idest.h b/src/idest.h
index 9dc16d8..50effa8 100644
--- a/src/idest.h
+++ b/src/idest.h
@@ -24,6 +24,7 @@
#include <xalloc.h>
#include <gl_linked_list.h>
#include <argmatch.h>
+#include <backupfile.h>
#include <id3tag.h>
#define _(s) s
@@ -34,6 +35,8 @@
#define DEFAULT_ED_LIST "title,album,comment,artist,year,genre"
extern int latin1_output;
+extern enum backup_type backup_type;
+extern char *backup_dir;
void set_id3v1(const char *name, const struct id3v1_block *);
void query_id3v1(const char *name);
@@ -57,3 +60,6 @@ void ed_list_add_item(const char *id, gl_list_t list);
void ed_list_print(void);
void ed_list_add_assignment(const char *name, const char *value);
+
+/* backup.c */
+int backup_file(const char *file);
diff --git a/src/main.c b/src/main.c
index 2173147..9c34a93 100644
--- a/src/main.c
+++ b/src/main.c
@@ -18,13 +18,15 @@
unsigned version_option = 2;
int latin1_output = 0;
+enum backup_type backup_type;
+char *backup_dir;
struct ed_item {
- char *name;
- char id[5];
+ char *name; /* Printable name */
+ char id[5]; /* Item ID */
union {
- gl_list_t vlist;
- char *value;
+ gl_list_t vlist; /* List of strings, used with --query */
+ char *value; /* New value, used with --set */
} v;
};
@@ -336,7 +338,7 @@ set_id3(const char *name)
set_id3v1(name, &v1_block);
} else
- error(1, 0, "setting ID3 v2 frames is not yet implemented");
+ set_id3v2(name);
}
void

Return to:

Send suggestions and report system problems to the System administrator.