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 BPath orgPath(&er); 80 err = orgPath.InitCheck(); 81 if (err < 0) 82 return err; 83 original_path = orgPath.Path(); 84 BDirectory trashDir(trash_dir); 85 err = trashDir.InitCheck(); 86 if (err < 0) 87 return err; 88 for (nr = 0; ; nr++) { 89 if (nr > INT_MAX - 1) 90 return B_ERROR; 91 if (nr) 92 snprintf(trashed_file, B_PATH_NAME_LENGTH-1, "%s/%s %d", trash_dir, er.name, nr); 93 else 94 snprintf(trashed_file, B_PATH_NAME_LENGTH-1, "%s/%s", trash_dir, er.name); 95 if (!trashDir.Contains(trashed_file)) 96 break; 97 } 98 err = rename(original_path, trashed_file); 99 if (err < 0) 100 return err; 101 102 err = node.WriteAttr(kAttrOriginalPath, B_STRING_TYPE, 0LL, original_path, strlen(original_path)+1); 103 if (err < 0) 104 return err; 105 return 0; 106 } 107 108 status_t show_trashed_file(const char *f) 109 { 110 status_t err; 111 char original_path[B_PATH_NAME_LENGTH]; 112 BPath path(f); 113 BNode node(f); 114 err = node.ReadAttr(kAttrOriginalPath, B_STRING_TYPE, 0LL, original_path, B_PATH_NAME_LENGTH); 115 if (err < 0) 116 return 0; 117 //printf("%s\n\t[from] %s\n", f, original_path); 118 printf("%s\n\tas: %s\n", original_path, f); 119 return 0; 120 } 121 122 status_t foreach_in_trash(status_t (*iterator)(const char *)) 123 { 124 status_t err; 125 dev_t dev; 126 char trash_dir[B_PATH_NAME_LENGTH]; 127 for (dev = 0; ; ) { 128 if (next_dev(&dev) < B_OK) 129 break; 130 //for each in trash_dir 131 err = find_directory(B_TRASH_DIRECTORY, dev, false, trash_dir, B_PATH_NAME_LENGTH); 132 if (err) 133 continue; /* skip trashless volumes */ 134 BDirectory trashDir(trash_dir); 135 err = trashDir.InitCheck(); 136 if (err < 0) 137 return err; 138 entry_ref er; 139 while (trashDir.GetNextRef(&er) == B_OK) { 140 BPath path(&er); 141 if ((err = path.InitCheck())) 142 return err; 143 err = iterator(path.Path()); 144 if (err) 145 return err; 146 } 147 } 148 return B_OK; 149 } 150 151 152 int main(int argc, char **argv) 153 { 154 int dountrash = 0; 155 int i = 1; 156 int err = 0; 157 if (strstr(argv[0], "untrash") || strstr(argv[0], "restore")) 158 dountrash = 1; 159 if (argc < 2) 160 return usage(1); 161 if (!strcmp(argv[1], "--help")) 162 return usage(0); 163 if (!strcmp(argv[1], "--restore")) { 164 dountrash = 1; 165 i++; 166 } 167 if (!dountrash && !strcmp(argv[1], "--empty")) { 168 /* XXX: clean that */ 169 BMessage msg(B_DELETE_PROPERTY); 170 msg.AddSpecifier("Trash"); 171 BMessenger msgr(kTrackerSig); 172 err = msgr.SendMessage(&msg); 173 if (err < 0) { 174 fprintf(stderr, "Emptying Trash: %s\n", strerror(err)); 175 return 1; 176 } 177 return 0; 178 } 179 if (dountrash && !strcmp(argv[i], "--all")) { 180 /* restore all trashed files */ 181 err = foreach_in_trash(untrash); 182 if (err) { 183 fprintf(stderr, "untrash: %s\n", strerror(err)); 184 return 1; 185 } 186 return 0; 187 } 188 if (!strcmp(argv[i], "--list")) { 189 err = foreach_in_trash(show_trashed_file); 190 return 0; 191 } 192 /* restore files... */ 193 if (dountrash) { 194 for (; i < argc; i++) { 195 err = untrash(argv[i]); 196 if (err) { 197 fprintf(stderr, "%s: %s\n", argv[i], strerror(err)); 198 return 1; 199 } 200 } 201 return err; 202 } 203 /* or trash them */ 204 for (i = 1; i < argc; i++) { 205 err = trash(argv[i]); 206 if (err) { 207 fprintf(stderr, "%s: %s\n", argv[i], strerror(err)); 208 return 1; 209 } 210 } 211 212 return err; 213 214 } 215