Beispiel #1
0
 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
Beispiel #2
0
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
Beispiel #3
0
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")
Beispiel #4
0
 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
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
    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