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(strncmp(path, string2, strlen(string2)))
00342
00343 {
00344 result = 1;
00345 token_done = 1;
00346 }
00347 else
00348 path += strlen(string2);
00349 }
00350
00351
00352 if(!subfilter2)
00353 {
00354 if(*path != 0)
00355 {
00356 result = 1;
00357 token_done = 1;
00358 }
00359 }
00360 }
00361 subfilter1 = subfilter2 + 1;
00362
00363 }while(!token_done && !result);
00364 }
00365 token_number++;
00366 }while(!done && result);
00367
00368 return result;
00369 }
00370
00371
00372 int FileSystem::update(char *new_dir)
00373 {
00374 DIR *dirstream;
00375 struct dirent64 *new_filename;
00376 struct stat ostat;
00377 struct tm *mod_time;
00378 int i, j, k, include_this;
00379 FileItem *new_file;
00380 char full_path[BCTEXTLEN], name_only[BCTEXTLEN];
00381 ArrayList<FileItem*>directories;
00382 ArrayList<FileItem*>files;
00383 int result = 0;
00384
00385 delete_directory();
00386 if(new_dir != 0) strcpy(current_dir, new_dir);
00387 dirstream = opendir(current_dir);
00388 if(!dirstream) return 1;
00389
00390 while(new_filename = readdir64(dirstream))
00391 {
00392 include_this = 1;
00393
00394
00395 if(!strcmp(new_filename->d_name, ".") ||
00396 !strcmp(new_filename->d_name, "..")) include_this = 0;
00397
00398
00399 if(include_this && !show_all_files && new_filename->d_name[0] == '.') include_this = 0;
00400
00401
00402 if(include_this)
00403 {
00404 new_file = new FileItem;
00405 sprintf(full_path, "%s", current_dir);
00406 if(!is_root_dir(current_dir)) strcat(full_path, "/");
00407 strcat(full_path, new_filename->d_name);
00408 strcpy(name_only, new_filename->d_name);
00409 new_file->set_path(full_path);
00410 new_file->set_name(name_only);
00411
00412
00413 if(!stat(full_path, &ostat))
00414 {
00415 new_file->size = ostat.st_size;
00416 mod_time = localtime(&(ostat.st_mtime));
00417 new_file->month = mod_time->tm_mon + 1;
00418 new_file->day = mod_time->tm_mday;
00419 new_file->year = mod_time->tm_year + 1900;
00420 new_file->calendar_time = ostat.st_mtime;
00421
00422 if(S_ISDIR(ostat.st_mode))
00423 {
00424 strcat(name_only, "/");
00425 new_file->is_dir = 1;
00426 }
00427
00428
00429 if(include_this && test_filter(new_file)) include_this = 0;
00430
00431
00432
00433 if(include_this && want_directory && !new_file->is_dir) include_this = 0;
00434 }
00435 else
00436 {
00437
00438 printf("FileSystem::update %s: %s\n",
00439 full_path,
00440 strerror(errno));
00441 include_this = 0;
00442 result = 1;
00443 }
00444
00445
00446 if(include_this)
00447 {
00448 if(new_file->is_dir) directories.append(new_file);
00449 else files.append(new_file);
00450 }
00451 else
00452 delete new_file;
00453 }
00454 }
00455
00456 closedir(dirstream);
00457
00458 combine(&directories, &files);
00459
00460 directories.remove_all();
00461 files.remove_all();
00462
00463 return result;
00464
00465 }
00466
00467 int FileSystem::set_filter(char *new_filter)
00468 {
00469 strcpy(filter, new_filter);
00470 return 0;
00471 }
00472
00473 int FileSystem::set_show_all()
00474 {
00475 show_all_files = 1;
00476 return 0;
00477 }
00478
00479 int FileSystem::set_want_directory()
00480 {
00481 want_directory = 1;
00482 return 0;
00483 }
00484
00485 int FileSystem::is_dir(const char *path)
00486 {
00487 if(!strlen(path)) return 0;
00488
00489 char new_dir[BCTEXTLEN];
00490 struct stat ostat;
00491
00492 strcpy(new_dir, path);
00493 complete_path(new_dir);
00494 if(!stat(new_dir, &ostat) && S_ISDIR(ostat.st_mode))
00495 return 1;
00496 else
00497 return 0;
00498 }
00499
00500 int FileSystem::create_dir(char *new_dir_)
00501 {
00502 char new_dir[BCTEXTLEN];
00503 strcpy(new_dir, new_dir_);
00504 complete_path(new_dir);
00505
00506 mkdir(new_dir, S_IREAD | S_IWRITE | S_IEXEC);
00507 return 0;
00508 }
00509
00510 int FileSystem::parse_tildas(char *new_dir)
00511 {
00512 if(new_dir[0] == 0) return 1;
00513
00514
00515 if(new_dir[0] == '~')
00516 {
00517
00518 if(new_dir[1] == '/' || new_dir[1] == 0)
00519 {
00520
00521 char *home;
00522 char string[BCTEXTLEN];
00523 home = getenv("HOME");
00524
00525
00526 if(home) sprintf(string, "%s%s", home, &new_dir[1]);
00527 strcpy(new_dir, string);
00528 return 0;
00529 }
00530 else
00531
00532 {
00533 char string[BCTEXTLEN], new_user[BCTEXTLEN];
00534 struct passwd *pw;
00535 int i, j;
00536
00537 for(i = 1, j = 0; new_dir[i] != 0 && new_dir[i] != '/'; i++, j++)
00538 {
00539 new_user[j] = new_dir[i];
00540 }
00541 new_user[j] = 0;
00542
00543 setpwent();
00544 while(pw = getpwent())
00545 {
00546
00547 if(!strcmp(pw->pw_name, new_user))
00548 {
00549
00550 sprintf(string, "%s%s", pw->pw_dir, &new_dir[i]);
00551 strcpy(new_dir, string);
00552 break;
00553 }
00554 }
00555 endpwent();
00556 return 0;
00557 }
00558 }
00559 return 0;
00560 }
00561
00562 int FileSystem::parse_directories(char *new_dir)
00563 {
00564
00565 if(new_dir[0] != '/')
00566 {
00567
00568 char string[BCTEXTLEN];
00569
00570 if(!strlen(current_dir))
00571 {
00572
00573 strcpy(string, new_dir);
00574 }
00575 else
00576 if(!is_root_dir(current_dir))
00577 {
00578
00579 if(current_dir[strlen(current_dir) - 1] == '/')
00580
00581 sprintf(string, "%s%s", current_dir, new_dir);
00582 else
00583
00584 sprintf(string, "%s/%s", current_dir, new_dir);
00585 }
00586 else
00587 sprintf(string, "%s%s", current_dir, new_dir);
00588
00589
00590 strcpy(new_dir, string);
00591
00592 }
00593 return 0;
00594 }
00595
00596 int FileSystem::parse_dots(char *new_dir)
00597 {
00598
00599 int changed = 1;
00600 while(changed)
00601 {
00602 int i, j, len;
00603 len = strlen(new_dir);
00604 changed = 0;
00605 for(i = 0, j = 1; !changed && j < len; i++, j++)
00606 {
00607 if(new_dir[i] == '.' && new_dir[j] == '.')
00608 {
00609 changed = 1;
00610 while(new_dir[i] != '/' && i > 0)
00611 {
00612
00613 i--;
00614 }
00615
00616
00617 if(i > 0) i--;
00618 while(new_dir[i] != '/' && i > 0)
00619 {
00620
00621 i--;
00622 }
00623
00624
00625
00626 while(new_dir[j] != '/' && j < len)
00627 {
00628 j++;
00629 }
00630
00631
00632 while(j < len)
00633 {
00634 new_dir[i++] = new_dir[j++];
00635 }
00636
00637 new_dir[i] = 0;
00638
00639 if((new_dir[0]) == 0) sprintf(new_dir, "/");
00640 break;
00641 }
00642 }
00643 }
00644 return 0;
00645 }
00646
00647 int FileSystem::complete_path(char *filename)
00648 {
00649
00650 if(!strlen(filename)) return 1;
00651
00652 parse_tildas(filename);
00653
00654 parse_directories(filename);
00655
00656 parse_dots(filename);
00657
00658
00659 return 0;
00660 }
00661
00662 int FileSystem::extract_dir(char *out, const char *in)
00663 {
00664 strcpy(out, in);
00665 if(!is_dir(in))
00666 {
00667
00668 int i;
00669
00670 complete_path(out);
00671
00672 for(i = strlen(out); i > 0 && out[i - 1] != '/'; i--)
00673 {
00674 ;
00675 }
00676 if(i >= 0) out[i] = 0;
00677 }
00678 return 0;
00679 }
00680
00681 int FileSystem::extract_name(char *out, const char *in, int test_dir)
00682 {
00683 int i;
00684
00685 if(test_dir && is_dir(in))
00686 sprintf(out, "");
00687 else
00688 {
00689 for(i = strlen(in)-1; i > 0 && in[i] != '/'; i--)
00690 {
00691 ;
00692 }
00693 if(in[i] == '/') i++;
00694 strcpy(out, &in[i]);
00695 }
00696 return 0;
00697 }
00698
00699 int FileSystem::join_names(char *out, char *dir_in, char *name_in)
00700 {
00701 strcpy(out, dir_in);
00702 int len = strlen(out);
00703 int result = 0;
00704
00705 while(!result)
00706 if(len == 0 || out[len] != 0) result = 1; else len--;
00707
00708 if(len != 0)
00709 {
00710 if(out[len] != '/') strcat(out, "/");
00711 }
00712
00713 strcat(out, name_in);
00714 return 0;
00715 }
00716
00717 int64_t FileSystem::get_date(char *filename)
00718 {
00719 struct stat file_status;
00720 bzero(&file_status, sizeof(struct stat));
00721 stat(filename, &file_status);
00722 return file_status.st_mtime;
00723 }
00724
00725 int64_t FileSystem::get_size(char *filename)
00726 {
00727 struct stat file_status;
00728 bzero(&file_status, sizeof(struct stat));
00729 stat(filename, &file_status);
00730 return file_status.st_size;
00731 }
00732
00733 int FileSystem::change_dir(char *new_dir)
00734 {
00735 char new_dir_full[BCTEXTLEN];
00736
00737 strcpy(new_dir_full, new_dir);
00738
00739 complete_path(new_dir_full);
00740
00741 if(strcmp(new_dir_full, "/") &&
00742 new_dir_full[strlen(new_dir_full) - 1] == '/')
00743 new_dir_full[strlen(new_dir_full) - 1] = 0;
00744 update(new_dir_full);
00745 return 0;
00746 }
00747
00748 int FileSystem::set_current_dir(char *new_dir)
00749 {
00750 strcpy(current_dir, new_dir);
00751 return 0;
00752 }
00753
00754 int FileSystem::add_end_slash(char *new_dir)
00755 {
00756 if(new_dir[strlen(new_dir) - 1] != '/') strcat(new_dir, "/");
00757 return 0;
00758 }
00759
00760 char* FileSystem::get_current_dir()
00761 {
00762 return current_dir;
00763 }
00764
00765 int FileSystem::total_files()
00766 {
00767 return dir_list.total;
00768 }
00769
00770
00771 FileItem* FileSystem::get_entry(int entry)
00772 {
00773 return dir_list.values[entry];
00774 }