/* wydawca - automatic release submission daemon Copyright (C) 2011-2013 Sergey Poznyakoff Wydawca 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 of the License, or (at your option) any later version. Wydawca 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 wydawca. If not, see . */ #include "wydawca.h" char const *simple_backup_suffix = "~"; static const char * split_filename(char const *file, char **pdir) { const char *p = strrchr(file, '/'); if (!p) { *pdir = grecs_strdup("."); p = file; } else { size_t len = p - file; char *dir = grecs_malloc(len + 1); memcpy(dir, file, len); dir[len] = 0; *pdir = dir; p++; } return p; } #define MINSUFSIZE 8 #define ISDIGIT(c) ('0' <= (c) && (c) <= '9') static char * get_backup_suffix(char const *file, enum backup_type type) { char *dirname; const char *basename; size_t baselen; DIR *dir; struct dirent *ent; char *lastsuf = NULL; size_t lastsuflen = 0; size_t lastsufsize = 0; int carry = 0; char *newsuf; char *q; if (type == simple_backups) return grecs_strdup(simple_backup_suffix); basename = split_filename(file, &dirname); baselen = strlen(basename); dir = opendir(dirname); if (!dir) { int ec = errno; free(dirname); errno = ec; return NULL; } while ((ent = readdir(dir))) { size_t len = strlen(ent->d_name); const char *p; size_t suflen; if (len < baselen + 4 || memcmp(ent->d_name, basename, baselen)) continue; p = ent->d_name + baselen; suflen = len - baselen; if (p[0] == '.' && p[1] == '~' && p[suflen - 1] == '~' && (suflen > lastsuflen || (suflen == lastsuflen && memcmp(p, lastsuf, lastsuflen) > 0))) { carry = 1; for (q = (char *)p + suflen - 2; q > p + 1 && ISDIGIT(*q); q--) if (*q != '9') carry = 0; q++; if (!ISDIGIT(*q)) continue; if (suflen > lastsufsize) { lastsufsize = suflen; if (!lastsuf) { if (lastsufsize < MINSUFSIZE) lastsufsize = MINSUFSIZE; lastsuf = grecs_malloc(lastsufsize); } else lastsuf = grecs_realloc(lastsuf, lastsufsize); } memcpy(lastsuf, p, suflen); lastsuflen = suflen; } } closedir(dir); free(dirname); if (lastsuf) { size_t newsuflen; newsuflen = lastsuflen + carry; newsuf = grecs_malloc(newsuflen + 1); newsuf[0] = '.'; newsuf[1] = '~'; newsuf[2] = '0'; memcpy(newsuf + 2 + carry, lastsuf + 2, lastsuflen - 3); newsuf[newsuflen - 1] = '~'; newsuf[newsuflen] = 0; for (q = newsuf + newsuflen - 2; *q == '9'; q--) *q = '0'; ++*q; free(lastsuf); } else if (type == numbered_existing_backups) newsuf = grecs_strdup(simple_backup_suffix); else newsuf = grecs_strdup(".~1~"); return newsuf; } char * find_backup_file_name(char const *file, enum backup_type type) { size_t flen; char *suffix; char *newname; if (type == no_backups) { errno = 0; return NULL; } suffix = get_backup_suffix(file, type); if (!suffix) return NULL; flen = strlen(file); newname = grecs_malloc(flen + strlen(suffix) + 1); memcpy(newname, file, flen); strcpy(newname + flen, suffix); free(suffix); return newname; }