int EDirectory::FmRmFile(char const* Name) { char FilePath[256]; strcpy(FilePath, Path); Slash(FilePath, 1); strcat(FilePath, Name); int choice = View->MView->Win->Choice(GPC_CONFIRM, "Remove File", 2, "O&K", "&Cancel", "Remove %s?", Name); if (choice == 0) { if (unlink(FilePath) == 0) { // put the cursor to the previous row --Row; // There has to be a more efficient way of doing this ... return RescanDir(); } else if (rmdir(FilePath) == 0) { --Row; return RescanDir(); } else { Msg(S_INFO, "Failed to remove %s", Name); return 0; } } else { Msg(S_INFO, "Cancelled"); return 0; } }
int EDirectory::FmMkDir() { char Dir[MAXPATH]; char Dir2[MAXPATH]; strcpy(Dir, Path); if (View->MView->Win->GetStr("New directory name", sizeof(Dir), Dir, HIST_PATH) == 0) { return 0; } if (ExpandPath(Dir, Dir2, sizeof(Dir2)) == -1) { Msg(S_INFO, "Failed to create directory, path did not expand"); return 0; } #if defined(MSVC) || defined(BCPP) || defined(WATCOM) || defined(__WATCOM_CPLUSPLUS__) int status = mkdir(Dir2); #else int status = mkdir(Dir2, 509); #endif if (status == 0) { return RescanDir(); } Msg(S_INFO, "Failed to create directory %s", Dir2); return 0; }
int EDirectory::FmMvFile(const char *Name) { char FullName[MAXPATH]; char Dir[MAXPATH]; char Dir2[MAXPATH]; strcpy(FullName, Path); Slash(FullName, 1); strcat(FullName, Name); strcpy(Dir, Path); if (View->MView->Win->GetStr("New file name", sizeof(Dir), Dir, HIST_PATH) == 0) { return 0; } if (ExpandPath(Dir, Dir2, sizeof(Dir2)) == -1) { Msg(S_INFO, "Failed to expand destination %s", Name); return 0; } int status = rename(FullName, Dir2); if (status == 0) { RescanDir(); return 1; } const char *msg = strerror(errno); Msg(S_INFO, "Failed to rename %s: %s", FullName, msg); return 0; }
int EDirectory::ChangeDir(ExState &State) { char Dir[MAXPATH]; char Dir2[MAXPATH]; if (State.GetStrParam(View, Dir, sizeof(Dir)) == 0) { strcpy(Dir, Path); if (View->MView->Win->GetStr("Set directory", sizeof(Dir), Dir, HIST_PATH) == 0) return 0; } if (ExpandPath(Dir, Dir2, sizeof(Dir2)) == -1) return 0; #if 0 // is this needed for other systems as well ? Slash(Dir2, 1); #endif if (Path) free(Path); Path = strdup(Dir2); Row = -1; UpdateTitle(); return RescanDir(); }
static void do_expire(char *datadir) { bookkeeper_t *books; dirstat_t *dirstat, oldstat; int ret, bookkeeper_stat, do_rescan; syslog(LOG_INFO, "Run expire on '%s'", datadir); do_rescan = 0; ret = ReadStatInfo(datadir, &dirstat, CREATE_AND_LOCK); switch (ret) { case STATFILE_OK: break; case ERR_NOSTATFILE: dirstat->low_water = 95; case FORCE_REBUILD: syslog(LOG_INFO, "Force rebuild stat record"); do_rescan = 1; break; case ERR_FAIL: syslog(LOG_ERR, "expire failed: can't read stat record"); return; /* not reached */ break; default: syslog(LOG_ERR, "expire failed: unexpected return code %i reading stat record", ret); return; /* not reached */ } bookkeeper_stat = AccessBookkeeper(&books, datadir); if ( do_rescan ) { RescanDir(datadir, dirstat); if ( bookkeeper_stat == BOOKKEEPER_OK ) { ClearBooks(books, NULL); // release the books below } } if ( bookkeeper_stat == BOOKKEEPER_OK ) { bookkeeper_t tmp_books; ClearBooks(books, &tmp_books); UpdateBookStat(dirstat, &tmp_books); ReleaseBookkeeper(books, DETACH_ONLY); } else { syslog(LOG_ERR, "Error %i: can't access book keeping records", ret); } syslog(LOG_INFO, "Limits: Filesize %s, Lifetime %s, Watermark: %llu%%\n", dirstat->max_size ? ScaleValue(dirstat->max_size) : "<none>", dirstat->max_lifetime ? ScaleTime(dirstat->max_lifetime) : "<none>", (unsigned long long)dirstat->low_water); syslog(LOG_INFO, "Current size: %s, Current lifetime: %s, Number of files: %llu", ScaleValue(dirstat->filesize), ScaleTime(dirstat->last - dirstat->first), (unsigned long long)dirstat->numfiles); oldstat = *dirstat; if ( dirstat->max_size || dirstat->max_lifetime ) ExpireDir(datadir, dirstat, dirstat->max_size, dirstat->max_lifetime, 0); WriteStatInfo(dirstat); if ( (oldstat.numfiles - dirstat->numfiles) > 0 ) { syslog(LOG_INFO, "expire completed"); syslog(LOG_INFO, " expired files: %llu", (unsigned long long)(oldstat.numfiles - dirstat->numfiles)); syslog(LOG_INFO, " expired time slot: %s", ScaleTime(dirstat->first - oldstat.first)); syslog(LOG_INFO, " expired file size: %s", ScaleValue(oldstat.filesize - dirstat->filesize)); syslog(LOG_INFO, "New size: %s, New lifetime: %s, Number of files: %llu", ScaleValue(dirstat->filesize), ScaleTime(dirstat->last - dirstat->first), (unsigned long long)dirstat->numfiles); } else { syslog(LOG_INFO, "expire completed - nothing to expire."); } ReleaseStatInfo(dirstat); } // End of do_expire
int EDirectory::ExecCommand(int Command, ExState &State) { switch (Command) { case ExActivateInOtherWindow: SearchLen = 0; Msg(S_INFO, ""); if (Files && Row >= 0 && Row < FCount) { if (isDir(Row)) { } else { return FmLoad(Files[Row]->Name(), View->Next); } } return ErFAIL; case ExRescan: if (RescanDir() == 0) return ErFAIL; return ErOK; case ExDirGoUp: SearchLen = 0; Msg(S_INFO, ""); FmChDir(SDOT SDOT); return ErOK; case ExDirGoDown: SearchLen = 0; Msg(S_INFO, ""); if (Files && Row >= 0 && Row < FCount) { if (isDir(Row)) { FmChDir(Files[Row]->Name()); return ErOK; } } return ErFAIL; case ExDirGoto: SearchLen = 0; Msg(S_INFO, ""); return ChangeDir(State); case ExDirGoRoot: SearchLen = 0; Msg(S_INFO, ""); FmChDir(SSLASH); return ErOK; case ExDirSearchCancel: // Kill search when moving SearchLen = 0; Msg(S_INFO, ""); return ErOK; case ExDirSearchNext: // Find next matching file, search is case in-sensitive while sorting is sensitive if (SearchLen) { for (int i = Row + 1; i < FCount; i++) { if (strnicmp(SearchName, Files[i]->Name(), SearchLen) == 0) { Row = i; break; } } } return ErOK; case ExDirSearchPrev: // Find prev matching file, search is case in-sensitive while sorting is sensitive if (SearchLen) { for (int i = Row - 1; i >= 0; i--) { if (strnicmp(SearchName, Files[i]->Name(), SearchLen) == 0) { Row = i; break; } } } return ErOK; case ExDeleteFile: SearchLen = 0; Msg(S_INFO, ""); return FmRmDir(Files[Row]->Name()); } return EList::ExecCommand(Command, State); }
int EDirectory::ExecCommand(int Command, ExState &State) { switch (Command) { case ExActivateInOtherWindow: SearchLen = 0; Msg(S_INFO, ""); if (Files && Row >= 0 && Row < FCount) { if (isDir(Row)) { } else { return FmLoad(Files[Row]->Name(), View->Next); } } return ErFAIL; case ExRescan: if (RescanDir() == 0) return ErFAIL; return ErOK; case ExDirGoUp: SearchLen = 0; Msg(S_INFO, ""); FmChDir(SDOT SDOT); return ErOK; case ExDirGoDown: SearchLen = 0; Msg(S_INFO, ""); if (Files && Row >= 0 && Row < FCount) { if (isDir(Row)) { FmChDir(Files[Row]->Name()); return ErOK; } } return ErFAIL; case ExDirGoto: SearchLen = 0; Msg(S_INFO, ""); return ChangeDir(State); case ExDirGoRoot: SearchLen = 0; Msg(S_INFO, ""); FmChDir(SSLASH); return ErOK; case ExDirSearchCancel: // Kill search when moving SearchLen = 0; Msg(S_INFO, ""); return ErOK; case ExDirSearchNext: // Find next matching file, search is case in-sensitive while sorting is sensitive if (SearchLen) { int found = GetMatchForward(Row + 1); if (found != -1) { Row = found; break; } } return ErOK; case ExDirSearchPrev: // Find prev matching file, search is case in-sensitive while sorting is sensitive if (SearchLen) { int found = GetMatchBackward(Row - 1); if (found != -1) { Row = found; break; } } return ErOK; case ExRenameFile: SearchLen = 0; Msg(S_INFO, ""); return FmMvFile(Files[Row]->Name()); case ExDeleteFile: SearchLen = 0; Msg(S_INFO, ""); return FmRmFile(Files[Row]->Name()); case ExMakeDirectory: SearchLen = 0; Msg(S_INFO, ""); return FmMkDir(); } return EList::ExecCommand(Command, State); }
int main( int argc, char **argv ) { struct stat fstat; int c, err, maxsize_set, maxlife_set; int do_rescan, do_expire, do_list, print_stat, do_update_param, print_books, is_profile, nfsen_format; char *maxsize_string, *lifetime_string, *datadir; uint64_t maxsize, lifetime, low_water; uint32_t runtime; channel_t *channel, *current_channel; maxsize_string = lifetime_string = NULL; datadir = NULL; maxsize = lifetime = 0; do_rescan = 0; do_expire = 0; do_list = 0; do_update_param = 0; is_profile = 0; print_stat = 0; print_books = 0; maxsize_set = 0; maxlife_set = 0; low_water = 0; nfsen_format = 0; runtime = 0; while ((c = getopt(argc, argv, "e:hl:L:T:Ypr:s:t:u:w:")) != EOF) { switch (c) { case 'h': usage(argv[0]); exit(0); break; case 'l': CheckDataDir(datadir); datadir = optarg; do_list = 1; print_stat = 1; break; case 'L': CheckDataDir(datadir); datadir = optarg; print_stat = 1; print_books = 1; break; case 'p': is_profile = 1; break; case 'r': CheckDataDir(datadir); do_rescan = 1; print_stat = 1; datadir = optarg; break; case 'e': CheckDataDir(datadir); datadir = optarg; do_expire = 1; print_stat = 1; break; case 's': if ( ParseSizeDef(optarg, &maxsize ) == 0 ) exit(250); maxsize_set = 1; break; case 't': if ( ParseTimeDef(optarg, &lifetime ) == 0 ) exit(250); maxlife_set = 1; break; case 'u': CheckDataDir(datadir); datadir = optarg; do_update_param = 1; break; case 'w': low_water = strtoll(optarg, NULL, 10); if ( low_water > 100 ) { fprintf(stderr, "Water mark > 100%%\n"); exit(250); } if ( low_water == 0 ) low_water = 100; break; case 'T': runtime = strtoll(optarg, NULL, 10); if ( runtime > 3600 ) { fprintf(stderr, "Runtime > 3600 (1h)\n"); exit(250); } break; case 'Y': nfsen_format = 1; break; default: usage(argv[0]); exit(250); } } datadir = AbsolutePath(datadir); if ( !datadir ) { fprintf(stderr, "Missing data directory\n"); usage(argv[0]); exit(250); } err = stat(datadir, &fstat); if ( !(fstat.st_mode & S_IFDIR) ) { fprintf(stderr, "No such directory: %s\n", datadir); exit(250); } channel = GetChannelList(datadir, is_profile, do_rescan); // GetChannelList(datadir, is_profile, do_rescan); if ( !channel ) { exit(250); } // printf("Size: %llu, time: %llu\n", maxsize, lifetime); // update water mark only, when not listing if ( !is_profile && !do_list && low_water ) channel->dirstat->low_water = low_water; /* process do_list first: if the UpdateBookStat results in a FORCE_REBUILD, * this will immediately done afterwards * do_expire will need accurate books as well, so update the books here as well */ if ( do_list || do_expire ) { current_channel = channel; while ( current_channel ) { if ( current_channel->books_stat == BOOKKEEPER_OK ) { bookkeeper_t tmp_books; printf("Include nfcapd bookeeping record in %s\n", current_channel->datadir); ClearBooks(current_channel->books, &tmp_books); UpdateBookStat(current_channel->dirstat, &tmp_books); if ( current_channel->dirstat->status == FORCE_REBUILD ) current_channel->do_rescan = 1; } current_channel = current_channel->next; } } // process do_rescan: make sure stats are up to date, if required current_channel = channel; while ( current_channel ) { if ( current_channel->do_rescan ) { int i; uint64_t last_sequence; /* detect new files: If nfcapd adds a new file while we are rescanning the directory * this results in inconsistent data for the rescan. Therefore check at the begin and end * of the rescan for the sequence number, which reflects the accesss/change to the bookkeeping record * It's assumed, that such an event does not occure more than once. However, loop 3 times max */ for ( i=0; i<3; i++ ) { last_sequence = BookSequence(current_channel->books); printf("Scanning files in %s .. ", current_channel->datadir); RescanDir(current_channel->datadir, current_channel->dirstat); if ( current_channel->dirstat->numfiles == 0 ) { //nothing found current_channel->status = NOFILES; } if ( BookSequence(current_channel->books) == last_sequence ) break; printf("Rescan again, due to file changes in directory!\n"); } if ( BookSequence(current_channel->books) != last_sequence ) { fprintf(stderr, "Could not savely rescan the directory. Data is not consistent.\n"); ReleaseBookkeeper(current_channel->books, DETACH_ONLY); if ( current_channel->status == OK ) WriteStatInfo(current_channel->dirstat); exit(250); } printf("done.\n"); if ( current_channel->books_stat == BOOKKEEPER_OK ) { printf("Updating nfcapd bookeeping records\n"); ClearBooks(channel->books, NULL); } } current_channel = current_channel->next; } // now process do_expire if required if ( do_expire ) { dirstat_t old_stat, current_stat; if ( is_profile ) { current_stat.status = 0; current_stat.max_lifetime = lifetime; current_stat.max_size = maxsize; current_stat.low_water = low_water ? low_water : 98; // sum up all channels in the profile current_channel = channel; current_stat.numfiles = current_channel->dirstat->numfiles; current_stat.filesize = current_channel->dirstat->filesize; current_stat.first = current_channel->dirstat->first; current_stat.last = current_channel->dirstat->last; current_channel = current_channel->next; while ( current_channel ) { current_stat.numfiles += current_channel->dirstat->numfiles; current_stat.filesize += current_channel->dirstat->filesize; if ( current_channel->dirstat->first && (current_channel->dirstat->first < current_stat.first) ) current_stat.first = current_channel->dirstat->first; if ( current_channel->dirstat->last > current_stat.last ) current_stat.last = current_channel->dirstat->last; current_channel = current_channel->next; } old_stat = current_stat; ExpireProfile(channel, ¤t_stat, maxsize, lifetime, runtime); } else { // cmd args override dirstat values if ( maxsize_set ) channel->dirstat->max_size = maxsize; else maxsize = channel->dirstat->max_size; if ( maxlife_set ) channel->dirstat->max_lifetime = lifetime; else lifetime = channel->dirstat->max_lifetime; old_stat = *(channel->dirstat); ExpireDir(channel->datadir, channel->dirstat, maxsize, lifetime, runtime); current_stat = *(channel->dirstat); } // Report, what we have done printf("Expired files: %llu\n", (unsigned long long)(old_stat.numfiles - current_stat.numfiles)); printf("Expired file size: %s\n", ScaleValue(old_stat.filesize - current_stat.filesize)); printf("Expired time range: %s\n\n", ScaleTime(current_stat.first - old_stat.first)); } if ( !is_profile && do_update_param ) { switch (channel->books_stat) { case BOOKKEEPER_OK: if ( maxsize_set ) channel->dirstat->max_size = maxsize; else maxsize = channel->dirstat->max_size; if ( maxlife_set ) channel->dirstat->max_lifetime = lifetime; else lifetime = channel->dirstat->max_lifetime; printf("Update collector process running for directory: '%s'\n", datadir); UpdateBooksParam(channel->books, (time_t)lifetime, maxsize); print_stat = 1; break; case ERR_NOTEXISTS: if ( maxsize_set ) channel->dirstat->max_size = maxsize; if ( maxlife_set ) channel->dirstat->max_lifetime = lifetime; print_stat = 1; break; default: // should never be reached as already cought earlier printf("Error %i while connecting to collector\n", channel->books_stat); } if ( channel->status == OK || channel->status == NOFILES ) WriteStatInfo(channel->dirstat); } if ( !is_profile && print_books ) { switch (channel->books_stat) { case BOOKKEEPER_OK: PrintBooks(channel->books); break; case ERR_NOTEXISTS: printf("No collector process running for directory: '%s'\n", channel->datadir); break; default: // should never be reached as already cought earlier printf("Error %i while connecting to collector\n", channel->books_stat); } } if ( print_stat ) { if ( is_profile ) { dirstat_t current_stat; current_stat.status = 0; current_stat.max_lifetime = lifetime; current_stat.max_size = maxsize; current_stat.low_water = low_water ? low_water : 98; // sum up all channels in the profile current_channel = channel; current_stat.numfiles = current_channel->dirstat->numfiles; current_stat.filesize = current_channel->dirstat->filesize; current_stat.first = current_channel->dirstat->first; current_stat.last = current_channel->dirstat->last; current_channel = current_channel->next; while ( current_channel ) { current_stat.numfiles += current_channel->dirstat->numfiles; current_stat.filesize += current_channel->dirstat->filesize; if ( current_channel->dirstat->first && (current_channel->dirstat->first < current_stat.first) ) current_stat.first = current_channel->dirstat->first; if ( current_channel->dirstat->last > current_stat.last ) current_stat.last = current_channel->dirstat->last; current_channel = current_channel->next; } if ( nfsen_format ) { printf("Stat|%llu|%llu|%llu\n", (unsigned long long)current_stat.filesize, (unsigned long long)current_stat.first, (unsigned long long)current_stat.last); } else PrintDirStat(¤t_stat); } else if ( nfsen_format ) printf("Stat|%llu|%llu|%llu\n", (unsigned long long)channel->dirstat->filesize, (unsigned long long)channel->dirstat->first, (unsigned long long)channel->dirstat->last ); else PrintDirStat(channel->dirstat); } current_channel = channel; while ( current_channel ) { ReleaseBookkeeper(current_channel->books, DETACH_ONLY); if ( current_channel->status == OK ) WriteStatInfo(current_channel->dirstat); current_channel = current_channel->next; } return 0; }