/* * Archiving related functions. * This one creates a list of files to be included into the archive and * sets up the libarchive context. */ int setup_archiver(pc_ctx_t *pctx, struct stat *sbuf) { char *tmpfile, *tmp; int err, fd; uchar_t *pbuf; struct archive *arc; struct fn_list *fn; /* * If sorting is enabled create the initial sort buffer. */ if (pctx->enable_archive_sort) { struct sort_buf *srt; srt = (struct sort_buf *)malloc(sizeof (struct sort_buf)); if (srt == NULL) { log_msg(LOG_ERR, 0, "Out of memory."); return (-1); } srt->next = NULL; srt->pos = 0; pctx->archive_sort_buf = srt; } /* * Create a temporary file to hold the generated list of pathnames to be archived. * Storing in a file saves memory usage and allows scalability. */ tmpfile = pctx->archive_members_file; tmp = get_temp_dir(); strcpy(tmpfile, tmp); free(tmp); strcat(tmpfile, "/.pcompXXXXXX"); if ((fd = mkstemp(tmpfile)) == -1) { log_msg(LOG_ERR, 1, "mkstemp errored."); return (-1); } add_fname(tmpfile); pbuf = malloc(pctx->chunksize); if (pbuf == NULL) { log_msg(LOG_ERR, 0, "Out of memory."); close(fd); unlink(tmpfile); return (-1); } /* * Use nftw() to scan all the directory hierarchies provided on the command * line and generate a consolidated list of pathnames to be archived. By * doing this we can sort the pathnames and estimate the total archive size. * Total archive size is needed by the subsequent compression stages. */ log_msg(LOG_INFO, 0, "Scanning files."); sbuf->st_size = 0; pctx->archive_size = 0; pctx->archive_members_count = 0; /* * nftw requires using global state variable. So we lock to be mt-safe. * This means only one directory tree scan can happen at a time. */ pthread_mutex_lock(&nftw_mutex); fn = pctx->fn; a_state.pbuf = pbuf; a_state.bufsiz = pctx->chunksize; a_state.bufpos = 0; a_state.fd = fd; a_state.srt = pctx->archive_sort_buf; a_state.srt_pos = 0; a_state.head = a_state.srt; a_state.pathlist_size = 0; while (fn) { struct stat sb; if (lstat(fn->filename, &sb) == -1) { log_msg(LOG_ERR, 1, "Ignoring %s.", fn->filename); fn = fn->next; continue; } a_state.arc_size = 0; a_state.fcount = 0; if (S_ISDIR(sb.st_mode)) { /* * Depth-First scan, FTW_DEPTH, is needed to handle restoring * all directory permissions correctly. */ err = nftw(fn->filename, add_pathname, 1024, FTW_PHYS | FTW_DEPTH); } else { int tflag; struct FTW ftwbuf; char *pos; if (S_ISLNK(sb.st_mode)) tflag = FTW_SL; else tflag = FTW_F; /* * Find out basename to mimic FTW. */ pos = strrchr(fn->filename, PATHSEP_CHAR); if (pos) ftwbuf.base = pos - fn->filename + 1; else ftwbuf.base = 0; add_pathname(fn->filename, &sb, tflag, &ftwbuf); a_state.arc_size = sb.st_size; } if (a_state.bufpos > 0) { ssize_t wrtn = Write(a_state.fd, a_state.pbuf, a_state.bufpos); if (wrtn < a_state.bufpos) { log_msg(LOG_ERR, 1, "Write failed."); close(fd); unlink(tmpfile); return (-1); } a_state.bufpos = 0; a_state.pathlist_size += wrtn; } pctx->archive_size += a_state.arc_size; pctx->archive_members_count += a_state.fcount; fn = fn->next; } if (a_state.srt == NULL) { pctx->enable_archive_sort = 0; } else { log_msg(LOG_INFO, 0, "Sorting ..."); a_state.srt->max = a_state.srt_pos - 1; qsort(a_state.srt->members, a_state.srt_pos, sizeof (member_entry_t), compare_members); pctx->archive_temp_size = a_state.pathlist_size; } pthread_mutex_unlock(&nftw_mutex); sbuf->st_size = pctx->archive_size; lseek(fd, 0, SEEK_SET); free(pbuf); sbuf->st_uid = geteuid(); sbuf->st_gid = getegid(); sbuf->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; arc = archive_write_new(); if (!arc) { log_msg(LOG_ERR, 1, "Unable to create libarchive context.\n"); close(fd); unlink(tmpfile); return (-1); } archive_write_set_format_pax_restricted(arc); archive_write_set_bytes_per_block(arc, 0); archive_write_open(arc, pctx, arc_open_callback, creat_write_callback, creat_close_callback); pctx->archive_ctx = arc; pctx->archive_members_fd = fd; if (pctx->enable_archive_sort) { pctx->temp_mmap_len = TEMP_MMAP_SIZE; pctx->temp_mmap_buf = mmap(NULL, pctx->temp_mmap_len, PROT_READ, MAP_SHARED, pctx->archive_members_fd, 0); if (pctx->temp_mmap_buf == NULL) { log_msg(LOG_WARN, 1, "Unable to mmap pathlist file, switching to read()."); pctx->temp_mmap_len = 0; } } else { pctx->temp_mmap_buf = NULL; pctx->temp_mmap_len = 0; } pctx->temp_mmap_pos = 0; pctx->arc_writing = 0; return (0); }
/* * Routine that creates a new directory in the specified window/path */ WORD fun_mkdir(WNODE *pw_node) { PNODE *pp_node; OBJECT *tree; WORD i, len, err; BYTE fnew_name[LEN_ZFNAME], unew_name[LEN_ZFNAME], *ptmp; BYTE path[MAXPATHLEN]; tree = G.a_trees[ADMKDBOX]; pp_node = pw_node->w_path; ptmp = path; strcpy(ptmp, pp_node->p_spec); i = 0; while (*ptmp++) { if (*ptmp == '\\') i++; } if (i > MAX_LEVEL) { fun_alert(1, STFO8DEE); return FALSE; } while(1) { fnew_name[0] = '\0'; inf_sset(tree, MKNAME, fnew_name); show_hide(FMD_START, tree); form_do(tree, 0); if (inf_what(tree, MKOK, MKCNCL) == 0) break; inf_sget(tree, MKNAME, fnew_name); unfmt_str(fnew_name, unew_name); if (unew_name[0] == '\0') break; ptmp = add_fname(path, unew_name); err = dos_mkdir(path); if (err == 0) /* mkdir succeeded */ { fun_rebld(pw_node); break; } /* * if we're getting a BIOS (rather than GEMDOS) error, the * critical error handler has already issued a message, so * just quit */ if (IS_BIOS_ERROR(err)) break; len = strlen(path); /* before we restore old path */ restore_path(ptmp); /* restore original path */ if (len >= LEN_ZPATH-3) { fun_alert(1,STDEEPPA); break; } /* * mkdir failed with a recoverable error: * prompt for Cancel or Retry */ if (fun_alert(2,STFOFAIL) == 1) /* Cancel */ break; } show_hide(FMD_FINISH, tree); return TRUE; }