/** Saves a playlist. */ public void exportM3U(Playlist playlist) { if (playlist == null) { return; } String suggestedName = CommonUtils.convertFileName(playlist.getName()); // get the user to select a new one.... avoid FrostWire installation folder. File suggested; File suggestedDirectory = FileChooserHandler.getLastInputDirectory(); if (suggestedDirectory.equals(CommonUtils.getCurrentDirectory())) { suggestedDirectory = new File(CommonUtils.getUserHomeDir(), "Desktop"); } suggested = new File(suggestedDirectory, suggestedName + ".m3u"); File selFile = FileChooserHandler.getSaveAsFile( GUIMediator.getAppFrame(), I18nMarker.marktr("Save Playlist As"), suggested, new PlaylistListFileFilter()); // didn't select a file? nothing we can do. if (selFile == null) { return; } // if the file already exists and not the one just opened, ask if it should be // overwritten. // TODO: this should be handled in the jfilechooser if (selFile.exists()) { DialogOption choice = GUIMediator.showYesNoMessage( I18n.tr( "Warning: a file with the name {0} already exists in the folder. Overwrite this file?", selFile.getName()), QuestionsHandler.PLAYLIST_OVERWRITE_OK, DialogOption.NO); if (choice != DialogOption.YES) return; } String path = selFile.getPath(); try { path = FileUtils.getCanonicalPath(selFile); } catch (IOException ignored) { // LOG.warn("unable to get canonical path for file: " + selFile, ignored); } // force m3u on the end. if (!path.toLowerCase().endsWith(".m3u")) path += ".m3u"; // create a new thread to handle saving the playlist to disk saveM3U(playlist, path); }
/** * Constructs the file system using the given BTData & hash information. If any of the information * is malformed, throws a ValueException. * * @param data contains all the data about a .torrent file * @param numHashes number of pieces the torrent was divided into * @param pieceLength size of divided up torrent file * @param infoHash a string of alphanumeric characters in the .torrent file that the client uses * to verify the data that is being transferred * @throws ValueException */ TorrentFileSystem(BTData data, int numHashes, long pieceLength, byte[] infoHash) throws IOException { // name of the torrent, also specifying the directory under which to save the torrents. _name = CommonUtils.convertFileName(data.getName()); // we need to check the name of the torrent, security risk! if (_name.length() == 0) throw new ValueException("bad torrent name"); _incompleteFile = new File( SharingSettings.INCOMPLETE_DIRECTORY.get(), Base32.encode(infoHash) + File.separator + _name); _completeFile = new File(SharingSettings.getSaveDirectory(_name), _name); if (!FileUtils.isReallyParent(SharingSettings.getSaveDirectory(_name), _completeFile)) { throw new SaveLocationException(LocationCode.SECURITY_VIOLATION, _completeFile); } if (data.getFiles() != null) { List<BTData.BTFileData> files = data.getFiles(); List<TorrentFile> torrents = new ArrayList<TorrentFile>(files.size()); long position = 0; for (BTData.BTFileData file : files) { String torrentPath = _name + file.getPath(); TorrentFile f = new TorrentFile( file.getLength(), new File(_completeFile, file.getPath()).getAbsolutePath(), torrentPath); f.setBeginPiece((int) (position / pieceLength)); f.setStartByte(position); position += f.length(); f.setEndPiece((int) (position / pieceLength)); f.setEndByte(position - 1); if (!FileUtils.isReallyInParentPath(_completeFile, f)) throw new SaveLocationException(LocationCode.SECURITY_VIOLATION, f); torrents.add(f); } if (files.size() == 0) throw new ValueException("bad metainfo, no files!"); _files = torrents; // add folders, for easier conflict checking later on for (String folderPath : data.getFolders()) _folders.add(new File(_completeFile, folderPath)); _folders.add(_completeFile); } else { String torrentPath = data.getName(); TorrentFile f = new TorrentFile(data.getLength(), _completeFile.getAbsolutePath(), torrentPath); f.setBeginPiece(0); f.setStartByte(0); f.setEndPiece(numHashes - 1); f.setEndByte(f.length()); _files = new ArrayList<TorrentFile>(1); _files.add(f); } _unmodFiles = Collections.unmodifiableList(_files); _totalSize = calculateTotalSize(_files); if (_totalSize <= 0) throw new ValueException("invalid size " + _totalSize); }
/** * Returns the fully-qualified temporary download file for the given file/location pair. If an * incomplete file already exists for this URN, that file is returned. Otherwise, the location of * the file is determined by the "incDir" variable. For example, getFile("test.txt", 1999) may * return "C:\Program Files\LimeWire\Incomplete\T-1999-Test.txt" if "incDir" is "C:\Program * Files\LimeWire\Incomplete". The disk is not modified, except for the file possibly being * created. * * <p>This method gives duplicate files the same temporary file, which is critical for resume and * swarmed downloads. That is, for all rfd_i and rfd_j * * <pre> * similar(rfd_i, rfd_j) <==> getFile(rfd_i).equals(getFile(rfd_j))<p> * </pre> * * It is imperative that the files are compared as in their canonical formats to preserve the * integrity of the filesystem. Otherwise, multiple downloads could be downloading to "FILE A", * and "file a", although only "file a" exists on disk and is being written to by both. * * @throws IOException if there was an IOError while determining the file's name. */ public synchronized File getFile(String name, URN sha1, long size, File incDir) throws IOException { boolean dirsMade = false; File baseFile = null; File canonFile = null; // make sure its created.. (the user might have deleted it) dirsMade = incDir.mkdirs(); String convertedName = CommonUtils.convertFileName(name); try { if (sha1 != null) { File file = hashes.get(sha1); if (file != null) { // File already allocated for hash return file; } else { // Allocate unique file for hash. By "unique" we mean not in // the value set of HASHES. Because we allow risky resumes, // there's no need to look at BLOCKS as well... for (int i = 1; ; i++) { file = new File(incDir, tempName(convertedName, size, i)); baseFile = file; file = canonicalize(file); canonFile = file; if (!hashes.values().contains(file)) break; } // ...and record the hash for later. hashes.put(sha1, file); // ...and make sure the file exists on disk, so that // future File.getCanonicalFile calls will match this // file. This was a problem on OSX, where // File("myfile") and File("MYFILE") aren't equal, // but File("myfile").getCanonicalFile() will only return // a File("MYFILE") if that already existed on disk. // This means that in order for the canonical-checking // within this class to work, the file must exist on disk. FileUtils.touch(file); return file; } } else { // No hash. File f = new File(incDir, tempName(convertedName, size, 0)); baseFile = f; f = canonicalize(f); canonFile = f; return f; } } catch (IOException ioe) { IOException ioe2 = new IOException( "dirsMade: " + dirsMade + "\ndirExist: " + incDir.exists() + "\nbaseFile: " + baseFile + "\ncannFile: " + canonFile); ioe2.initCause(ioe); throw ioe2; } }