00001 #include <dirent.h>
00002 #include <errno.h>
00003 #include <pwd.h>
00004 #include <stddef.h>
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include <sys/stat.h>
00009 #include <sys/types.h>
00010 #include <time.h>
00011 #include <unistd.h>
00012
00013 #include "filesystem.h"
00014
00015 FileItem::FileItem()
00016 {
00017 path = 0;
00018 name = 0;
00019 reset();
00020 }
00021
00022 FileItem::FileItem(char *path,
00023 char *name,
00024 int is_dir,
00025 int64_t size,
00026 int month,
00027 int day,
00028 int year,
00029 int64_t calendar_time)
00030 {
00031 this->path = new char[strlen(path)];
00032 this->name = new char[strlen(name)];
00033 if(this->path) strcpy(this->path, path);
00034 if(this->name) strcpy(this->name, name);
00035 this->is_dir = is_dir;
00036 this->size = size;
00037 this->month = month;
00038 this->day = day;
00039 this->year = year;
00040 this->calendar_time = calendar_time;
00041 }
00042
00043 FileItem::~FileItem()
00044 {
00045 reset();
00046 }
00047
00048 int FileItem::reset()
00049 {
00050 if(this->path) delete [] this->path;
00051 if(this->name) delete [] this->name;
00052 path = 0;
00053 name = 0;
00054 is_dir = 0;
00055 size = 0;
00056 month = 0;
00057 day = 0;
00058 year = 0;
00059 calendar_time = 0;
00060 return 0;
00061 }
00062
00063 int FileItem::set_path(char *path)
00064 {
00065 if(this->path) delete [] this->path;
00066 this->path = new char[strlen(path) + 1];
00067 strcpy(this->path, path);
00068 return 0;
00069 }
00070
00071 int FileItem::set_name(char *name)
00072 {
00073 if(this->name) delete [] this->name;
00074 this->name = new char[strlen(name) + 1];
00075 strcpy(this->name, name);
00076 return 0;
00077 }
00078
00079
00080 FileSystem::FileSystem()
00081 {
00082 reset_parameters();
00083 getcwd(current_dir, BCTEXTLEN);
00084
00085 }
00086
00087 FileSystem::~FileSystem()
00088 {
00089 delete_directory();
00090 }
00091
00092 int FileSystem::reset_parameters()
00093 {
00094 show_all_files = 0;
00095 want_directory = 0;
00096 strcpy(filter, "");
00097 strcpy(current_dir, "");
00098 sort_order = SORT_ASCENDING;
00099 sort_field = SORT_PATH;
00100 return 0;
00101 }
00102
00103 int FileSystem::delete_directory()
00104 {
00105 for(int i = 0; i < dir_list.total; i++)
00106 {
00107 delete dir_list.values[i];
00108 }
00109 dir_list.remove_all();
00110 return 0;
00111 }
00112
00113 int FileSystem::set_sort_order(int value)
00114 {
00115 this->sort_order = value;
00116 }
00117
00118 int FileSystem::set_sort_field(int field)
00119 {
00120 this->sort_field = field;
00121 }
00122
00123
00124
00125
00126
00127 int FileSystem::dot_reverse_filename(char *out, const char *in)
00128 {
00129 int i, i2, j=0, lastdot;
00130 lastdot = strlen(in);
00131 for (i = strlen(in); i >= 0; i--){
00132
00133 if (in[i] == '.') {
00134 i2 = i+1;
00135 while (i2 < lastdot)
00136 out[j++] = in[i2++];
00137 out[j++] = in[i];
00138 lastdot = i;
00139 }
00140 }
00141 i++;
00142 if (in[i] != '.') {
00143 while (i < lastdot) out[j++] = in[i++];
00144 }
00145 out[j++] = '\0';
00146 return 0;
00147 }
00148
00149 int FileSystem::compare_items(ArrayList<FileItem*> *dir_list,
00150 int item1,
00151 int item2)
00152 {
00153 int result = 0;
00154 FileItem *ptr1 = dir_list->values[item1];
00155 FileItem *ptr2 = dir_list->values[item2];
00156
00157
00158 switch(sort_field)
00159 {
00160 char dotreversedname1[BCTEXTLEN], dotreversedname2[BCTEXTLEN];
00161
00162 case SORT_PATH:
00163 result = (sort_order == SORT_ASCENDING) ?
00164 strcasecmp(ptr1->name, ptr2->name) :
00165 strcasecmp(ptr2->name, ptr1->name);
00166 break;
00167 case SORT_SIZE:
00168 if(ptr1->size == ptr2->size || ptr1->is_dir)
00169 result = strcasecmp(ptr1->name, ptr2->name);
00170 else
00171 result = (sort_order == SORT_ASCENDING) ?
00172 (ptr1->size > ptr2->size) :
00173 (ptr2->size > ptr1->size);
00174 break;
00175 case SORT_DATE:
00176 if(ptr1->calendar_time == ptr2->calendar_time)
00177 result = strcasecmp(ptr1->name, ptr2->name);
00178 else
00179 result = (sort_order == SORT_ASCENDING) ?
00180 (ptr1->calendar_time > ptr2->calendar_time) :
00181 (ptr2->calendar_time > ptr1->calendar_time);
00182 break;
00183 case SORT_EXTENSION:
00184 dot_reverse_filename(dotreversedname1,ptr1->name);
00185 dot_reverse_filename(dotreversedname2,ptr2->name);
00186
00187 result = (sort_order == SORT_ASCENDING) ?
00188 strcasecmp(dotreversedname1, dotreversedname2) :
00189 strcasecmp(dotreversedname2, dotreversedname1);
00190 break;
00191 }
00192 return result;
00193 }
00194
00195
00196 int FileSystem::sort_table(ArrayList<FileItem*> *dir_list)
00197 {
00198 int changed;
00199 FileItem *temp;
00200 int i;
00201
00202 changed = 1;
00203 while(changed)
00204 {
00205 changed = 0;
00206 for(i = 0; i < dir_list->total - 1; i++)
00207 {
00208 if(compare_items(dir_list, i, i + 1) > 0)
00209
00210 {
00211 temp = dir_list->values[i];
00212 dir_list->values[i] = dir_list->values[i+1];
00213 dir_list->values[i+1] = temp;
00214 changed = 1;
00215 }
00216 }
00217 }
00218 return 0;
00219 }
00220
00221 int FileSystem::combine(ArrayList<FileItem*> *dir_list, ArrayList<FileItem*> *file_list)
00222 {
00223 int i;
00224 FileItem *new_entry, *entry;
00225
00226 sort_table(dir_list);
00227 for(i = 0; i < dir_list->total; i++)
00228 {
00229 this->dir_list.append(dir_list->values[i]);
00230 }
00231
00232 sort_table(file_list);
00233 for(i = 0; i < file_list->total; i++)
00234 {
00235 this->dir_list.append(file_list->values[i]);
00236 }
00237 return 0;
00238 }
00239
00240 void FileSystem::alphabetize()
00241 {
00242 sort_table(&dir_list);
00243 }
00244
00245 int FileSystem::is_root_dir(char *path)
00246 {
00247 if(!strcmp(current_dir, "/")) return 1;
00248 return 0;
00249 }
00250
00251 int FileSystem::test_filter(FileItem *file)
00252 {
00253 char *filter1 = 0, *filter2 = filter, *subfilter1, *subfilter2;
00254 int total_filters = 0;
00255 int result = 0;
00256 int done = 0, token_done;
00257 int token_number = 0;
00258
00259
00260 if(file->is_dir) return 0;
00261
00262
00263 if(!file->name) return 1;
00264
00265 do
00266 {
00267
00268 filter1 = strchr(filter2, '[');
00269 string[0] = 0;
00270
00271
00272 if(filter1)
00273 {
00274 filter1++;
00275 filter2 = strchr(filter1, ']');
00276
00277 if(filter2)
00278 {
00279 int i;
00280 for(i = 0; filter1 + i < filter2; i++)
00281 string[i] = filter1[i];
00282 string[i] = 0;
00283 }
00284 else
00285 {
00286 strcpy(string, filter1);
00287 done = 1;
00288 }
00289 }
00290 else
00291 {
00292 if(!token_number)
00293 strcpy(string, filter);
00294 else
00295 done = 1;
00296 }
00297
00298
00299 if(string[0] != 0)
00300 {
00301 char *path = file->name;
00302 subfilter1 = string;
00303 token_done = 0;
00304 result = 0;
00305
00306 do
00307 {
00308 string2[0] = 0;
00309 subfilter2 = strchr(subfilter1, '*');
00310
00311 if(subfilter2)
00312 {
00313 int i;
00314 for(i = 0; subfilter1 + i < subfilter2; i++)
00315 string2[i] = subfilter1[i];
00316
00317 string2[i] = 0;
00318 }
00319 else
00320 {
00321 strcpy(string2, subfilter1);
00322 token_done = 1;
00323 }
00324
00325 if(string2[0] != 0)
00326 {
00327
00328 if(subfilter1 > string)
00329 {
00330 if(!strstr(path, string2))
00331 {
00332 result = 1;
00333 token_done = 1;
00334 }
00335 else
00336 path = strstr(path, string2) + strlen(string2);
00337 }
00338 else
00339
00340 {
00341 if(strncasecmp(path, string2, strlen(string2)))
00342 {
00343 result = 1;
00344 token_done = 1;
00345 }
00346 else
00347 path += strlen(string2);
00348 }
00349
00350
00351 if(!subfilter2)
00352 {
00353 if(*path != 0)
00354 {
00355 result = 1;
00356 token_done = 1;
00357 }
00358 }
00359 }
00360 subfilter1 = subfilter2 + 1;
00361
00362 }while(!token_done && !result);
00363 }
00364 token_number++;
00365 }while(!done && result);
00366
00367 return result;
00368 }
00369
00370
00371 int FileSystem::update(char *new_dir)
00372 {
00373 DIR *dirstream;
00374 struct dirent64 *new_filename;
00375 struct stat ostat;
00376 struct tm *mod_time;
00377 int i, j, k, include_this;
00378 FileItem *new_file;
00379 char full_path[BCTEXTLEN], name_only[BCTEXTLEN];
00380 ArrayList<FileItem*>directories;
00381 ArrayList<FileItem*>files;
00382 int result = 0;
00383
00384 delete_directory();
00385 if(new_dir != 0) strcpy(current_dir, new_dir);
00386 dirstream = opendir(current_dir);
00387 if(!dirstream) return 1;
00388
00389 while(new_filename = readdir64(dirstream))
00390 {
00391 include_this = 1;
00392
00393
00394 if(!strcmp(new_filename->d_name, ".") ||
00395 !strcmp(new_filename->d_name, "..")) include_this = 0;
00396
00397
00398 if(include_this && !show_all_files && new_filename->d_name[0] == '.') include_this = 0;
00399
00400
00401 if(include_this)
00402 {
00403 new_file = new FileItem;
00404 sprintf(full_path, "%s", current_dir);
00405 if(!is_root_dir(current_dir)) strcat(full_path, "/");
00406 strcat(full_path, new_filename->d_name);
00407 strcpy(name_only, new_filename->d_name);
00408 new_file->set_path(full_path);
00409 new_file->set_name(name_only);
00410
00411
00412 if(!stat(full_path, &ostat))
00413 {
00414 new_file->size = ostat.st_size;
00415 mod_time = localtime(&(ostat.st_mtime));
00416 new_file->month = mod_time->tm_mon + 1;
00417 new_file->day = mod_time->tm_mday;
00418 new_file->year = mod_time->tm_year + 1900;
00419 new_file->calendar_time = ostat.st_mtime;
00420
00421 if(S_ISDIR(ostat.st_mode))
00422 {
00423 strcat(name_only, "/");
00424 new_file->is_dir = 1;
00425 }
00426
00427
00428 if(include_this && test_filter(new_file)) include_this = 0;
00429
00430
00431
00432 if(include_this && want_directory && !new_file->is_dir) include_this = 0;
00433 }
00434 else
00435 {
00436
00437 printf("FileSystem::update %s: %s\n",
00438 full_path,
00439 strerror(errno));
00440 include_this = 0;
00441 result = 1;
00442 }
00443
00444
00445 if(include_this)
00446 {
00447 if(new_file->is_dir) directories.append(new_file);
00448 else files.append(new_file);
00449 }
00450 else
00451 delete new_file;
00452 }
00453 }
00454
00455 closedir(dirstream);
00456
00457 combine(&directories, &files);
00458
00459 directories.remove_all();
00460 files.remove_all();
00461
00462 return result;
00463
00464 }
00465
00466 int FileSystem::set_filter(char *new_filter)
00467 {
00468 strcpy(filter, new_filter);
00469 return 0;
00470 }
00471
00472 int FileSystem::set_show_all()
00473 {
00474 show_all_files = 1;
00475 return 0;
00476 }
00477
00478 int FileSystem::set_want_directory()
00479 {
00480 want_directory = 1;
00481 return 0;
00482 }
00483
00484 int FileSystem::is_dir(const char *path)
00485 {
00486 if(!strlen(path)) return 0;
00487
00488 char new_dir[BCTEXTLEN];
00489 struct stat ostat;
00490
00491 strcpy(new_dir, path);
00492 complete_path(new_dir);
00493 if(!stat(new_dir, &ostat) && S_ISDIR(ostat.st_mode)) return 0;
00494 return 1;
00495 }
00496
00497 int FileSystem::create_dir(char *new_dir_)
00498 {
00499 char new_dir[BCTEXTLEN];
00500 strcpy(new_dir, new_dir_);
00501 complete_path(new_dir);
00502
00503 mkdir(new_dir, S_IREAD | S_IWRITE | S_IEXEC);
00504 return 0;
00505 }
00506
00507 int FileSystem::parse_tildas(char *new_dir)
00508 {
00509 if(new_dir[0] == 0) return 1;
00510
00511
00512 if(new_dir[0] == '~')
00513 {
00514
00515 if(new_dir[1] == '/' || new_dir[1] == 0)
00516 {
00517
00518 char *home;
00519 char string[BCTEXTLEN];
00520 home = getenv("HOME");
00521
00522
00523 if(home) sprintf(string, "%s%s", home, &new_dir[1]);
00524 strcpy(new_dir, string);
00525 return 0;
00526 }
00527 else
00528
00529 {
00530 char string[BCTEXTLEN], new_user[BCTEXTLEN];
00531 struct passwd *pw;
00532 int i, j;
00533
00534 for(i = 1, j = 0; new_dir[i] != 0 && new_dir[i] != '/'; i++, j++)
00535 {
00536 new_user[j] = new_dir[i];
00537 }
00538 new_user[j] = 0;
00539
00540 setpwent();
00541 while(pw = getpwent())
00542 {
00543
00544 if(!strcmp(pw->pw_name, new_user))
00545 {
00546
00547 sprintf(string, "%s%s", pw->pw_dir, &new_dir[i]);
00548 strcpy(new_dir, string);
00549 break;
00550 }
00551 }
00552 endpwent();
00553 return 0;
00554 }
00555 }
00556 return 0;
00557 }
00558
00559 int FileSystem::parse_directories(char *new_dir)
00560 {
00561
00562 if(new_dir[0] != '/')
00563 {
00564
00565 char string[BCTEXTLEN];
00566
00567 if(!strlen(current_dir))
00568 {
00569
00570 strcpy(string, new_dir);
00571 }
00572 else
00573 if(!is_root_dir(current_dir))
00574 {
00575
00576 if(current_dir[strlen(current_dir) - 1] == '/')
00577
00578 sprintf(string, "%s%s", current_dir, new_dir);
00579 else
00580
00581 sprintf(string, "%s/%s", current_dir, new_dir);
00582 }
00583 else
00584 sprintf(string, "%s%s", current_dir, new_dir);
00585
00586
00587 strcpy(new_dir, string);
00588
00589 }
00590 return 0;
00591 }
00592
00593 int FileSystem::parse_dots(char *new_dir)
00594 {
00595
00596 int changed = 1;
00597 while(changed)
00598 {
00599 int i, j, len;
00600 len = strlen(new_dir);
00601 changed = 0;
00602 for(i = 0, j = 1; !changed && j < len; i++, j++)
00603 {
00604 if(new_dir[i] == '.' && new_dir[j] == '.')
00605 {
00606 changed = 1;
00607 while(new_dir[i] != '/' && i > 0)
00608 {
00609
00610 i--;
00611 }
00612
00613
00614 if(i > 0) i--;
00615 while(new_dir[i] != '/' && i > 0)
00616 {
00617
00618 i--;
00619 }
00620
00621
00622
00623 while(new_dir[j] != '/' && j < len)
00624 {
00625 j++;
00626 }
00627
00628
00629 while(j < len)
00630 {
00631 new_dir[i++] = new_dir[j++];
00632 }
00633
00634 new_dir[i] = 0;
00635
00636 if((new_dir[0]) == 0) sprintf(new_dir, "/");
00637 break;
00638 }
00639 }
00640 }
00641 return 0;
00642 }
00643
00644 int FileSystem::complete_path(char *filename)
00645 {
00646
00647 if(!strlen(filename)) return 1;
00648
00649 parse_tildas(filename);
00650
00651 parse_directories(filename);
00652
00653 parse_dots(filename);
00654
00655
00656 return 0;
00657 }
00658
00659 int FileSystem::extract_dir(char *out, const char *in)
00660 {
00661 strcpy(out, in);
00662 if(is_dir(in))
00663 {
00664
00665 int i;
00666
00667 complete_path(out);
00668
00669 for(i = strlen(out); i > 0 && out[i - 1] != '/'; i--)
00670 {
00671 ;
00672 }
00673 if(i >= 0) out[i] = 0;
00674 }
00675 return 0;
00676 }
00677
00678 int FileSystem::extract_name(char *out, const char *in, int test_dir)
00679 {
00680 int i;
00681
00682 if(test_dir && !is_dir(in))
00683 sprintf(out, "");
00684 else
00685 {
00686 for(i = strlen(in)-1; i > 0 && in[i] != '/'; i--)
00687 {
00688 ;
00689 }
00690 if(in[i] == '/') i++;
00691 strcpy(out, &in[i]);
00692 }
00693 return 0;
00694 }
00695
00696 int FileSystem::join_names(char *out, char *dir_in, char *name_in)
00697 {
00698 strcpy(out, dir_in);
00699 int len = strlen(out);
00700 int result = 0;
00701
00702 while(!result)
00703 if(len == 0 || out[len] != 0) result = 1; else len--;
00704
00705 if(len != 0)
00706 {
00707 if(out[len] != '/') strcat(out, "/");
00708 }
00709
00710 strcat(out, name_in);
00711 return 0;
00712 }
00713
00714 long FileSystem::get_date(char *filename)
00715 {
00716 struct stat file_status;
00717 bzero(&file_status, sizeof(struct stat));
00718 stat(filename, &file_status);
00719 return file_status.st_mtime;
00720 }
00721
00722 int64_t FileSystem::get_size(char *filename)
00723 {
00724 struct stat file_status;
00725 bzero(&file_status, sizeof(struct stat));
00726 stat(filename, &file_status);
00727 return file_status.st_size;
00728 }
00729
00730 int FileSystem::change_dir(char *new_dir)
00731 {
00732 char new_dir_full[BCTEXTLEN];
00733
00734 strcpy(new_dir_full, new_dir);
00735
00736 complete_path(new_dir_full);
00737
00738 if(strcmp(new_dir_full, "/") &&
00739 new_dir_full[strlen(new_dir_full) - 1] == '/')
00740 new_dir_full[strlen(new_dir_full) - 1] = 0;
00741 update(new_dir_full);
00742 return 0;
00743 }
00744
00745 int FileSystem::set_current_dir(char *new_dir)
00746 {
00747 strcpy(current_dir, new_dir);
00748 return 0;
00749 }
00750
00751 int FileSystem::add_end_slash(char *new_dir)
00752 {
00753 if(new_dir[strlen(new_dir) - 1] != '/') strcat(new_dir, "/");
00754 return 0;
00755 }
00756
00757 char* FileSystem::get_current_dir()
00758 {
00759 return current_dir;
00760 }
00761
00762 int FileSystem::total_files()
00763 {
00764 return dir_list.total;
00765 }
00766
00767
00768 FileItem* FileSystem::get_entry(int entry)
00769 {
00770 return dir_list.values[entry];
00771 }