def test_path(self): """ Return True if path exists """ value = self.get() if value: return os.path.exists(real_path(self.__root, value)) else: return False
def prepare_extraction_path(nzo): """Based on the information that we have, generate the extraction path and create the directory. Separated so it can be called from DirectUnpacker """ one_folder = False marker_file = None # Determine class directory catdir = config.get_categories(nzo.cat).dir() if catdir.endswith("*"): catdir = catdir.strip("*") one_folder = True complete_dir = real_path(cfg.complete_dir.get_path(), catdir) complete_dir = long_path(complete_dir) # TV/Movie/Date Renaming code part 1 - detect and construct paths if cfg.enable_meta(): file_sorter = Sorter(nzo, nzo.cat) else: file_sorter = Sorter(None, nzo.cat) complete_dir = file_sorter.detect(nzo.final_name, complete_dir) if file_sorter.sort_file: one_folder = False complete_dir = sanitize_and_trim_path(complete_dir) if one_folder: workdir_complete = create_all_dirs(complete_dir, apply_umask=True) else: workdir_complete = get_unique_path(os.path.join( complete_dir, nzo.final_name), create_dir=True) marker_file = set_marker(workdir_complete) if not workdir_complete or not os.path.exists(workdir_complete): logging.error( T("Cannot create final folder %s") % os.path.join(complete_dir, nzo.final_name)) raise IOError if cfg.folder_rename() and not one_folder: prefixed_path = prefix(workdir_complete, "_UNPACK_") tmp_workdir_complete = get_unique_path(prefix(workdir_complete, "_UNPACK_"), create_dir=False) try: renamer(workdir_complete, tmp_workdir_complete) except: pass # On failure, just use the original name # Is the unique path different? Then we also need to modify the final path if prefixed_path != tmp_workdir_complete: workdir_complete = workdir_complete + os.path.splitext( tmp_workdir_complete)[1] else: tmp_workdir_complete = workdir_complete return tmp_workdir_complete, workdir_complete, file_sorter, one_folder, marker_file
def check_incomplete_vs_complete(): """ Make sure "incomplete" and "complete" are not identical """ complete = cfg.complete_dir.get_path() if filesystem.same_file(cfg.download_dir.get_path(), complete): if filesystem.real_path("X", cfg.download_dir()) == cfg.download_dir(): # Abs path, so set an abs path too cfg.download_dir.set(os.path.join(complete, "incomplete")) else: cfg.download_dir.set("incomplete")
def get_path(self): """ Return full absolute path """ value = self.get() path = "" if value: path = real_path(self.__root, value) if self.__create and not os.path.exists(path): _, path, _ = create_real_path(self.ident()[1], self.__root, value, self.__apply_umask, self.__writable) return path
def check_incomplete_vs_complete(): """Make sure download_dir and complete_dir are not identical or that download_dir is not a subfolder of complete_dir""" complete = cfg.complete_dir.get_path() if filesystem.same_file(cfg.download_dir.get_path(), complete): if filesystem.real_path("X", cfg.download_dir()) == filesystem.long_path(cfg.download_dir()): # Abs path, so set download_dir as an abs path inside the complete_dir cfg.download_dir.set(os.path.join(complete, "incomplete")) else: cfg.download_dir.set("incomplete") return False return True
def validate_safedir(root, value, default): """Allow only when queues are empty and no UNC On Windows path should be small """ if sabnzbd.WIN32 and value and len(real_path(root, value)) >= MAX_WIN_DFOLDER: return T( "Error: Path length should be below %s.") % MAX_WIN_DFOLDER, None if sabnzbd.empty_queues(): return validate_no_unc(root, value, default) else: return T("Error: Queue not empty, cannot change folder."), None
def run(self): # Input and output linebuf = "" last_volume_linebuf = "" unrar_log = [] rarfiles = [] extracted = [] start_time = time.time() # Need to read char-by-char because there's no newline after new-disk message while 1: # We need to lock, so we don't crash if unpacker is deleted while we read with START_STOP_LOCK: if not self.active_instance or not self.active_instance.stdout: break char = platform_btou(self.active_instance.stdout.read(1)) if not char: # End of program break linebuf += char # Error? Let PP-handle it if linebuf.endswith(( "ERROR: ", "Cannot create", "in the encrypted file", "CRC failed", "checksum failed", "You need to start extraction from a previous volume", "password is incorrect", "Incorrect password", "Write error", "checksum error", "Cannot open", "start extraction from a previous volume", "Unexpected end of archive", )): logging.info("Error in DirectUnpack of %s: %s", self.cur_setname, linebuf.strip()) self.abort() if linebuf.endswith("\n"): # List files we used if linebuf.startswith("Extracting from"): filename = re.search(EXTRACTFROM_RE, linebuf.strip()).group(1) if filename not in rarfiles: rarfiles.append(filename) # List files we extracted m = re.search(EXTRACTED_RE, linebuf) if m: # In case of flat-unpack, UnRar still prints the whole path (?!) unpacked_file = m.group(2) if cfg.flat_unpack(): unpacked_file = os.path.basename(unpacked_file) extracted.append( real_path(self.unpack_dir_info[0], unpacked_file)) # Did we reach the end? if linebuf.endswith("All OK"): # Stop timer and finish self.unpack_time += time.time() - start_time ACTIVE_UNPACKERS.remove(self) # Add to success rarfile_path = os.path.join(self.nzo.downpath, self.rarfile_nzf.filename) self.success_sets[self.cur_setname] = ( rar_volumelist(rarfile_path, self.nzo.password, rarfiles), extracted, ) logging.info("DirectUnpack completed for %s", self.cur_setname) self.nzo.set_action_line(T("Direct Unpack"), T("Completed")) # List success in history-info msg = T("Unpacked %s files/folders in %s") % ( len(extracted), format_time_string(self.unpack_time)) msg = "%s - %s" % (T("Direct Unpack"), msg) self.nzo.set_unpack_info("Unpack", msg, self.cur_setname) # Write current log and clear unrar_log.append(linebuf.strip()) linebuf = "" last_volume_linebuf = "" logging.debug("DirectUnpack Unrar output %s", "\n".join(unrar_log)) unrar_log = [] rarfiles = [] extracted = [] # Are there more files left? while self.nzo.files and not self.next_sets: with self.next_file_lock: self.next_file_lock.wait() # Is there another set to do? if self.next_sets: # Start new instance nzf = self.next_sets.pop(0) self.reset_active() self.cur_setname = nzf.setname # Wait for the 1st volume to appear self.wait_for_next_volume() self.create_unrar_instance() start_time = time.time() else: self.killed = True break if linebuf.endswith("[C]ontinue, [Q]uit "): # Stop timer self.unpack_time += time.time() - start_time # Wait for the next one.. self.wait_for_next_volume() # Possible that the instance was deleted while locked if not self.killed: # If unrar stopped or is killed somehow, writing will cause a crash try: # Give unrar some time to do it's thing self.active_instance.stdin.write(b"C\n") start_time = time.time() time.sleep(0.1) except IOError: self.abort() break # Did we unpack a new volume? Sometimes UnRar hangs on 1 volume if not last_volume_linebuf or last_volume_linebuf != linebuf: # Next volume self.cur_volume += 1 self.nzo.set_action_line(T("Direct Unpack"), self.get_formatted_stats()) logging.info("DirectUnpacked volume %s for %s", self.cur_volume, self.cur_setname) # If lines did not change and we don't have the next volume, this download is missing files! # In rare occasions we can get stuck forever with repeating lines if last_volume_linebuf == linebuf: if not self.have_next_volume( ) or self.duplicate_lines > 10: logging.info( "DirectUnpack failed due to missing files %s", self.cur_setname) self.abort() else: logging.debug( 'Duplicate output line detected: "%s"', last_volume_linebuf) self.duplicate_lines += 1 else: self.duplicate_lines = 0 last_volume_linebuf = linebuf # Show the log if linebuf.endswith("\n"): unrar_log.append(linebuf.strip()) linebuf = "" # Add last line unrar_log.append(linebuf.strip()) logging.debug("DirectUnpack Unrar output %s", "\n".join(unrar_log)) # Make more space self.reset_active() if self in ACTIVE_UNPACKERS: ACTIVE_UNPACKERS.remove(self) # Set the thread to killed so it never gets restarted by accident self.killed = True