1 /* 2 * [un]trash command for Haiku 3 * Copyright (c) 2004, Francois Revol - revol@free.fr 4 * provided under the MIT licence 5 */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <unistd.h> 10 #include <app/Message.h> 11 #include <app/Messenger.h> 12 #include <kernel/fs_attr.h> 13 #include <kernel/fs_info.h> 14 #include <storage/Directory.h> 15 #include <storage/Entry.h> 16 #include <storage/FindDirectory.h> 17 #include <storage/Node.h> 18 #include <storage/Path.h> 19 #include <support/TypeConstants.h> 20 21 static const char *kAttrOriginalPath = "_trk/original_path"; 22 static const char *kTrackerSig = "application/x-vnd.Be-TRAK"; 23 24 int usage(int ret) 25 { 26 printf("\nSend files to trash, or restore them.\nUsage:\n"); 27 printf("trash [--restore|--empty|--list] file ...\n"); 28 printf("\t--restore\trestore files (act as untrash)\n"); 29 printf("\t--empty\t\tempty the Trash\n"); 30 printf("\t--list\t\tlist what's already in the Trash\n"); 31 printf("untrash [--all] [file ...]\n"); 32 //printf("restore [--all] [file ...]\n"); 33 return ret; 34 } 35 36 status_t untrash(const char *f) 37 { 38 status_t err; 39 char original_path[B_PATH_NAME_LENGTH]; 40 BPath path(f); 41 BNode node(f); 42 err = node.InitCheck(); 43 if (err) 44 return err; 45 err = node.ReadAttr(kAttrOriginalPath, B_STRING_TYPE, 0LL, original_path, B_PATH_NAME_LENGTH); 46 if (err < 0) 47 return err; 48 err = rename(path.Path(), original_path); 49 if (err < 0) 50 return err; 51 node.RemoveAttr(kAttrOriginalPath); 52 return 0; 53 } 54 55 status_t trash(const char *f) 56 { 57 status_t err; 58 attr_info ai; 59 dev_t dev = -1; 60 int nr; 61 const char *original_path; 62 char trash_dir[B_PATH_NAME_LENGTH]; 63 char trashed_file[B_PATH_NAME_LENGTH]; 64 dev = dev_for_path(f); 65 err = find_directory(B_TRASH_DIRECTORY, dev, false, trash_dir, B_PATH_NAME_LENGTH); 66 if (err < 0) 67 return err; 68 BNode node(f); 69 err = node.InitCheck(); 70 if (err < 0) 71 return err; 72 err = node.GetAttrInfo(kAttrOriginalPath, &ai); 73 if (err == B_OK) 74 return EALREADY; 75 if (!strncmp(f, trash_dir, strlen(trash_dir))) 76 return EALREADY; 77 entry_ref er; 78 err = get_ref_for_path(f, &er); 79 if (err < 0) 80 return err; 81 BPath orgPath(&er); 82 err = orgPath.InitCheck(); 83 if (err < 0) 84 return err; 85 original_path = orgPath.Path(); 86 BDirectory trashDir(trash_dir); 87 err = trashDir.InitCheck(); 88 if (err < 0) 89 return err; 90 for (nr = 0; ; nr++) { 91 if (nr > INT_MAX - 1) 92 return B_ERROR; 93 if (nr) 94 snprintf(trashed_file, B_PATH_NAME_LENGTH-1, "%s/%s %d", trash_dir, er.name, nr); 95 else 96 snprintf(trashed_file, B_PATH_NAME_LENGTH-1, "%s/%s", trash_dir, er.name); 97 if (!trashDir.Contains(trashed_file)) 98 break; 99 } 100 err = rename(original_path, trashed_file); 101 if (err < 0) 102 return err; 103 104 err = node.WriteAttr(kAttrOriginalPath, B_STRING_TYPE, 0LL, original_path, strlen(original_path)+1); 105 if (err < 0) 106 return err; 107 return 0; 108 } 109 110 status_t show_trashed_file(const char *f) 111 { 112 status_t err; 113 char original_path[B_PATH_NAME_LENGTH]; 114 BPath path(f); 115 BNode node(f); 116 err = node.ReadAttr(kAttrOriginalPath, B_STRING_TYPE, 0LL, original_path, B_PATH_NAME_LENGTH); 117 if (err < 0) 118 return 0; 119 //printf("%s\n\t[from] %s\n", f, original_path); 120 printf("%s\n\tas: %s\n", original_path, f); 121 return 0; 122 } 123 124 status_t foreach_in_trash(status_t (*iterator)(const char *)) 125 { 126 status_t err; 127 dev_t dev; 128 char trash_dir[B_PATH_NAME_LENGTH]; 129 for (dev = 0; ; ) { 130 if (next_dev(&dev) < B_OK) 131 break; 132 //for each in trash_dir 133 err = find_directory(B_TRASH_DIRECTORY, dev, false, trash_dir, B_PATH_NAME_LENGTH); 134 if (err) 135 continue; /* skip trashless volumes */ 136 BDirectory trashDir(trash_dir); 137 err = trashDir.InitCheck(); 138 if (err < 0) 139 return err; 140 entry_ref er; 141 while (trashDir.GetNextRef(&er) == B_OK) { 142 BPath path(&er); 143 if ((err = path.InitCheck())) 144 return err; 145 err = iterator(path.Path()); 146 if (err) 147 return err; 148 } 149 } 150 return B_OK; 151 } 152 153 154 int main(int argc, char **argv) 155 { 156 int dountrash = 0; 157 int i = 1; 158 int err = 0; 159 if (strstr(argv[0], "untrash") || strstr(argv[0], "restore")) 160 dountrash = 1; 161 if (argc < 2) 162 return usage(1); 163 if (!strcmp(argv[1], "--help")) 164 return usage(0); 165 if (!strcmp(argv[1], "--restore")) { 166 dountrash = 1; 167 i++; 168 } 169 if (!dountrash && !strcmp(argv[1], "--empty")) { 170 /* XXX: clean that */ 171 BMessage msg(B_DELETE_PROPERTY); 172 msg.AddSpecifier("Trash"); 173 BMessenger msgr(kTrackerSig); 174 err = msgr.SendMessage(&msg); 175 if (err < 0) { 176 fprintf(stderr, "Emptying Trash: %s\n", strerror(err)); 177 return 1; 178 } 179 return 0; 180 } 181 if (dountrash && !strcmp(argv[i], "--all")) { 182 /* restore all trashed files */ 183 err = foreach_in_trash(untrash); 184 if (err) { 185 fprintf(stderr, "untrash: %s\n", strerror(err)); 186 return 1; 187 } 188 return 0; 189 } 190 if (!strcmp(argv[i], "--list")) { 191 err = foreach_in_trash(show_trashed_file); 192 return 0; 193 } 194 /* restore files... */ 195 if (dountrash) { 196 for (; i < argc; i++) { 197 err = untrash(argv[i]); 198 if (err) { 199 fprintf(stderr, "%s: %s\n", argv[i], strerror(err)); 200 return 1; 201 } 202 } 203 return err; 204 } 205 /* or trash them */ 206 for (i = 1; i < argc; i++) { 207 err = trash(argv[i]); 208 if (err) { 209 fprintf(stderr, "%s: %s\n", argv[i], strerror(err)); 210 return 1; 211 } 212 } 213 214 return err; 215 216 } 217