| | 956 | // -------------------------------------------------------------------------- |
| | 957 | // |
| | 958 | // Function |
| | 959 | // Name: BackupQueries::FindFileID(const std::string& |
| | 960 | // rNameOrIdString, const bool *options, |
| | 961 | // int64_t *pDirIdOut, std::string* pFileNameOut) |
| | 962 | // Purpose: Locate a file on the store (either by name or by |
| | 963 | // object ID, depending on opts['i'], where name can |
| | 964 | // include a path) and return the file ID, placing the |
| | 965 | // directory ID in *pDirIdOut and the filename part |
| | 966 | // of the path (if not looking up by ID and not NULL) |
| | 967 | // in *pFileNameOut. |
| | 968 | // Created: 2008-09-12 |
| | 969 | // |
| | 970 | // -------------------------------------------------------------------------- |
| | 971 | int64_t BackupQueries::FindFileID(const std::string& rNameOrIdString, |
| | 972 | const bool *opts, int64_t *pDirIdOut, std::string* pFileNameOut, |
| | 973 | int16_t flagsInclude, int16_t flagsExclude, int16_t* pFlagsOut) |
| | 974 | { |
| | 975 | // Find object ID somehow |
| | 976 | int64_t fileId; |
| | 977 | int64_t dirId = GetCurrentDirectoryID(); |
| | 978 | std::string fileName = rNameOrIdString; |
| | 979 | |
| | 980 | if(!opts['i']) |
| | 981 | { |
| | 982 | // does this remote filename include a path? |
| | 983 | std::string::size_type index = fileName.rfind('/'); |
| | 984 | if(index != std::string::npos) |
| | 985 | { |
| | 986 | std::string dirName(fileName.substr(0, index)); |
| | 987 | fileName = fileName.substr(index + 1); |
| | 988 | |
| | 989 | dirId = FindDirectoryObjectID(dirName); |
| | 990 | if(dirId == 0) |
| | 991 | { |
| | 992 | BOX_ERROR("Directory '" << dirName << |
| | 993 | "' not found."); |
| | 994 | return 0; |
| | 995 | } |
| | 996 | } |
| | 997 | |
| | 998 | if(pFileNameOut) |
| | 999 | { |
| | 1000 | *pFileNameOut = fileName; |
| | 1001 | } |
| | 1002 | } |
| | 1003 | |
| | 1004 | BackupStoreFilenameClear fn(fileName); |
| | 1005 | |
| | 1006 | // Need to look it up in the current directory |
| | 1007 | mrConnection.QueryListDirectory( |
| | 1008 | dirId, flagsInclude, flagsExclude, |
| | 1009 | true /* do want attributes */); |
| | 1010 | |
| | 1011 | // Retrieve the directory from the stream following |
| | 1012 | BackupStoreDirectory dir; |
| | 1013 | std::auto_ptr<IOStream> dirstream(mrConnection.ReceiveStream()); |
| | 1014 | dir.ReadFromStream(*dirstream, mrConnection.GetTimeout()); |
| | 1015 | BackupStoreDirectory::Entry *en; |
| | 1016 | |
| | 1017 | if(opts['i']) |
| | 1018 | { |
| | 1019 | // Specified as ID. |
| | 1020 | fileId = ::strtoll(rNameOrIdString.c_str(), 0, 16); |
| | 1021 | if(fileId == std::numeric_limits<long long>::min() || |
| | 1022 | fileId == std::numeric_limits<long long>::max() || |
| | 1023 | fileId == 0) |
| | 1024 | { |
| | 1025 | BOX_ERROR("Not a valid object ID (specified in hex)."); |
| | 1026 | return 0; |
| | 1027 | } |
| | 1028 | |
| | 1029 | // Check that the item is actually in the directory |
| | 1030 | en = dir.FindEntryByID(fileId); |
| | 1031 | if(en == 0) |
| | 1032 | { |
| | 1033 | BOX_ERROR("File ID " << |
| | 1034 | BOX_FORMAT_OBJECTID(fileId) << |
| | 1035 | " not found in current directory on store.\n" |
| | 1036 | "(You can only access files by ID from the " |
| | 1037 | "current directory.)"); |
| | 1038 | return 0; |
| | 1039 | } |
| | 1040 | } |
| | 1041 | else |
| | 1042 | { |
| | 1043 | // Specified by name, find the object in the directory to get the ID |
| | 1044 | BackupStoreDirectory::Iterator i(dir); |
| | 1045 | en = i.FindMatchingClearName(fn); |
| | 1046 | if(en == 0) |
| | 1047 | { |
| | 1048 | BOX_ERROR("Filename '" << rNameOrIdString << "' " |
| | 1049 | "not found in current directory on store.\n" |
| | 1050 | "(Subdirectories in path not searched.)"); |
| | 1051 | return 0; |
| | 1052 | } |
| | 1053 | |
| | 1054 | fileId = en->GetObjectID(); |
| | 1055 | } |
| | 1056 | |
| | 1057 | *pDirIdOut = dirId; |
| | 1058 | |
| | 1059 | if(pFlagsOut) |
| | 1060 | { |
| | 1061 | *pFlagsOut = en->GetFlags(); |
| | 1062 | } |
| | 1063 | |
| | 1064 | return fileId; |
| | 1065 | } |
| | 1066 | |
| 967 | | for (std::vector<std::string>::iterator |
| 968 | | i = args.begin(); i != args.end(); i++) |
| 969 | | { |
| 970 | | std::string out; |
| 971 | | if(!ConvertConsoleToUtf8(i->c_str(), out)) |
| 972 | | { |
| 973 | | BOX_ERROR("Failed to convert encoding."); |
| 974 | | return; |
| 975 | | } |
| 976 | | *i = out; |
| 977 | | } |
| 978 | | #endif |
| 979 | | |
| 980 | | std::string fileName(args[0]); |
| 981 | | |
| 982 | | if(!opts['i']) |
| 983 | | { |
| 984 | | // does this remote filename include a path? |
| 985 | | std::string::size_type index = fileName.rfind('/'); |
| 986 | | if(index != std::string::npos) |
| 987 | | { |
| 988 | | std::string dirName(fileName.substr(0, index)); |
| 989 | | fileName = fileName.substr(index + 1); |
| 990 | | |
| 991 | | dirId = FindDirectoryObjectID(dirName); |
| 992 | | if(dirId == 0) |
| 993 | | { |
| 994 | | BOX_ERROR("Directory '" << dirName << |
| 995 | | "' not found."); |
| 996 | | return; |
| 997 | | } |
| 998 | | } |
| 999 | | } |
| 1000 | | |
| 1001 | | BackupStoreFilenameClear fn(fileName); |
| 1002 | | |
| 1003 | | // Need to look it up in the current directory |
| 1004 | | mrConnection.QueryListDirectory( |
| 1005 | | dirId, |
| 1006 | | BackupProtocolClientListDirectory::Flags_File, // just files |
| 1007 | | (opts['i'])?(BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING):(BackupProtocolClientListDirectory::Flags_OldVersion | BackupProtocolClientListDirectory::Flags_Deleted), // only current versions |
| 1008 | | false /* don't want attributes */); |
| 1009 | | |
| 1010 | | // Retrieve the directory from the stream following |
| 1011 | | BackupStoreDirectory dir; |
| 1012 | | std::auto_ptr<IOStream> dirstream(mrConnection.ReceiveStream()); |
| 1013 | | dir.ReadFromStream(*dirstream, mrConnection.GetTimeout()); |
| 1014 | | |
| 1015 | | if(opts['i']) |
| 1016 | | { |
| 1017 | | // Specified as ID. |
| 1018 | | fileId = ::strtoll(args[0].c_str(), 0, 16); |
| 1019 | | if(fileId == std::numeric_limits<long long>::min() || |
| 1020 | | fileId == std::numeric_limits<long long>::max() || |
| 1021 | | fileId == 0) |
| 1022 | | { |
| 1023 | | BOX_ERROR("Not a valid object ID (specified in hex)."); |
| 1024 | | return; |
| 1025 | | } |
| 1026 | | |
| 1027 | | // Check that the item is actually in the directory |
| 1028 | | if(dir.FindEntryByID(fileId) == 0) |
| 1029 | | { |
| 1030 | | BOX_ERROR("File ID " << |
| 1031 | | BOX_FORMAT_OBJECTID(fileId) << |
| 1032 | | " not found in current " |
| 1033 | | "directory on store.\n" |
| 1034 | | "(You can only download files by ID " |
| 1035 | | "from the current directory.)"); |
| 1036 | | return; |
| 1037 | | } |
| 1038 | | |
| 1039 | | // Must have a local name in the arguments (check at beginning of function ensures this) |
| | 1093 | for (std::vector<std::string>::iterator |
| | 1094 | i = args.begin(); i != args.end(); i++) |
| | 1095 | { |
| | 1096 | std::string out; |
| | 1097 | if(!ConvertConsoleToUtf8(i->c_str(), out)) |
| | 1098 | { |
| | 1099 | BOX_ERROR("Failed to convert encoding."); |
| | 1100 | return; |
| | 1101 | } |
| | 1102 | *i = out; |
| | 1103 | } |
| | 1104 | #endif |
| | 1105 | |
| | 1106 | int16_t flagsExclude; |
| | 1107 | |
| | 1108 | if(opts['i']) |
| | 1109 | { |
| | 1110 | // can retrieve anything by ID |
| | 1111 | flagsExclude = BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING; |
| | 1112 | } |
| | 1113 | else |
| | 1114 | { |
| | 1115 | // only current versions by name |
| | 1116 | flagsExclude = |
| | 1117 | BackupProtocolClientListDirectory::Flags_OldVersion | |
| | 1118 | BackupProtocolClientListDirectory::Flags_Deleted; |
| | 1119 | } |
| | 1120 | |
| | 1121 | |
| | 1122 | fileId = FindFileID(args[0], opts, &dirId, &localName, |
| | 1123 | BackupProtocolClientListDirectory::Flags_File, // just files |
| | 1124 | flagsExclude, NULL /* don't care about flags found */); |
| | 1125 | |
| | 1126 | if (fileId == 0) |
| | 1127 | { |
| | 1128 | // error already reported |
| | 1129 | return; |
| | 1130 | } |
| | 1131 | |
| | 1132 | if(opts['i']) |
| | 1133 | { |
| | 1134 | // Specified as ID. Must have a local name in the arguments |
| | 1135 | // (check at beginning of function ensures this) |
| | 1136 | localName = args[1]; |
| | 1137 | } |
| | 1138 | else |
| | 1139 | { |
| | 1140 | // Specified by name. Local name already set by FindFileID, |
| | 1141 | // but may be overridden by user supplying a second argument. |
| | 1142 | if(args.size() == 2) |
| | 1143 | { |
| 2226 | | |
| 2227 | | // Get directory ID |
| 2228 | | int64_t dirID = FindDirectoryObjectID(storeDirEncoded, |
| 2229 | | false /* no old versions */, true /* find deleted dirs */); |
| 2230 | | |
| 2231 | | // Allowable? |
| 2232 | | if(dirID == 0) |
| 2233 | | { |
| 2234 | | BOX_ERROR("Directory '" << args[0] << "' not found on server."); |
| 2235 | | return; |
| 2236 | | } |
| 2237 | | if(dirID == BackupProtocolClientListDirectory::RootDirectory) |
| 2238 | | { |
| 2239 | | BOX_ERROR("Cannot undelete the root directory."); |
| 2240 | | return; |
| 2241 | | } |
| 2242 | | |
| 2243 | | // Undelete |
| 2244 | | mrConnection.QueryUndeleteDirectory(dirID); |
| 2245 | | } |
| | 2314 | |
| | 2315 | // Find object ID somehow |
| | 2316 | int64_t fileId, parentId; |
| | 2317 | std::string fileName; |
| | 2318 | int16_t flagsOut; |
| | 2319 | |
| | 2320 | fileId = FindFileID(storeDirEncoded, opts, &parentId, &fileName, |
| | 2321 | /* include files and directories */ |
| | 2322 | BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, |
| | 2323 | /* include old and deleted files */ |
| | 2324 | BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, |
| | 2325 | &flagsOut); |
| | 2326 | |
| | 2327 | if (fileId == 0) |
| | 2328 | { |
| | 2329 | // error already reported |
| | 2330 | return; |
| | 2331 | } |
| | 2332 | |
| | 2333 | // Undelete it on the store |
| | 2334 | try |
| | 2335 | { |
| | 2336 | // Undelete object |
| | 2337 | if(flagsOut & BackupProtocolClientListDirectory::Flags_File) |
| | 2338 | { |
| | 2339 | mrConnection.QueryUndeleteFile(parentId, fileId); |
| | 2340 | } |
| | 2341 | else |
| | 2342 | { |
| | 2343 | mrConnection.QueryUndeleteDirectory(fileId); |
| | 2344 | } |
| | 2345 | } |
| | 2346 | catch (BoxException &e) |
| | 2347 | { |
| | 2348 | BOX_ERROR("Failed to undelete object: " << |
| | 2349 | e.what()); |
| | 2350 | } |
| | 2351 | catch(std::exception &e) |
| | 2352 | { |
| | 2353 | BOX_ERROR("Failed to undelete object: " << |
| | 2354 | e.what()); |
| | 2355 | } |
| | 2356 | catch(...) |
| | 2357 | { |
| | 2358 | BOX_ERROR("Failed to undelete object: unknown error"); |
| | 2359 | } |
| | 2360 | } |
| | 2361 | |
| | 2362 | // -------------------------------------------------------------------------- |
| | 2363 | // |
| | 2364 | // Function |
| | 2365 | // Name: BackupQueries::CommandDelete(const |
| | 2366 | // std::vector<std::string> &, const bool *) |
| | 2367 | // Purpose: Deletes a file |
| | 2368 | // Created: 23/11/03 |
| | 2369 | // |
| | 2370 | // -------------------------------------------------------------------------- |
| | 2371 | void BackupQueries::CommandDelete(const std::vector<std::string> &args, |
| | 2372 | const bool *opts) |
| | 2373 | { |
| | 2374 | if (!mReadWrite) |
| | 2375 | { |
| | 2376 | BOX_ERROR("This command requires a read-write connection. " |
| | 2377 | "Please reconnect with the -w option."); |
| | 2378 | return; |
| | 2379 | } |
| | 2380 | |
| | 2381 | // Check arguments |
| | 2382 | if(args.size() != 1) |
| | 2383 | { |
| | 2384 | BOX_ERROR("Incorrect usage. delete <name>"); |
| | 2385 | return; |
| | 2386 | } |
| | 2387 | |
| | 2388 | #ifdef WIN32 |
| | 2389 | std::string storeDirEncoded; |
| | 2390 | if(!ConvertConsoleToUtf8(args[0].c_str(), storeDirEncoded)) return; |
| | 2391 | #else |
| | 2392 | const std::string& storeDirEncoded(args[0]); |
| | 2393 | #endif |
| | 2394 | |
| | 2395 | // Find object ID somehow |
| | 2396 | int64_t fileId, parentId; |
| | 2397 | std::string fileName; |
| | 2398 | int16_t flagsOut; |
| | 2399 | |
| | 2400 | fileId = FindFileID(storeDirEncoded, opts, &parentId, &fileName, |
| | 2401 | /* include files and directories */ |
| | 2402 | BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, |
| | 2403 | /* exclude old and deleted files */ |
| | 2404 | BackupProtocolClientListDirectory::Flags_OldVersion | |
| | 2405 | BackupProtocolClientListDirectory::Flags_Deleted, |
| | 2406 | &flagsOut); |
| | 2407 | |
| | 2408 | if (fileId == 0) |
| | 2409 | { |
| | 2410 | // error already reported |
| | 2411 | return; |
| | 2412 | } |
| | 2413 | |
| | 2414 | BackupStoreFilenameClear fn(fileName); |
| | 2415 | |
| | 2416 | // Delete it on the store |
| | 2417 | try |
| | 2418 | { |
| | 2419 | // Delete object |
| | 2420 | if(flagsOut & BackupProtocolClientListDirectory::Flags_File) |
| | 2421 | { |
| | 2422 | mrConnection.QueryDeleteFile(parentId, fn); |
| | 2423 | } |
| | 2424 | else |
| | 2425 | { |
| | 2426 | mrConnection.QueryDeleteDirectory(fileId); |
| | 2427 | } |
| | 2428 | } |
| | 2429 | catch (BoxException &e) |
| | 2430 | { |
| | 2431 | BOX_ERROR("Failed to delete object: " << |
| | 2432 | e.what()); |
| | 2433 | } |
| | 2434 | catch(std::exception &e) |
| | 2435 | { |
| | 2436 | BOX_ERROR("Failed to delete object: " << |
| | 2437 | e.what()); |
| | 2438 | } |
| | 2439 | catch(...) |
| | 2440 | { |
| | 2441 | BOX_ERROR("Failed to delete object: unknown error"); |
| | 2442 | } |
| | 2443 | } |