/************************************************************************ * * * The path passed in is scanned via readdir(). For each file in the * * path, a menu item is created and inserted into a new menu. That * * new menu is made the PULLRIGHT_MENU of a newly created panel item * * for the path item originally passed it. Since this routine is * * recursive, a new menu is created for each subdirectory under the * * original path. * * */ static Menu_item add_path_to_menu(char *path, u_long addr_notify) { struct stat s_buf; /* file status */ Menu_item mi; /* menu item for pullright */ Menu next_menu; /* newly created menu */ char buf[MAXPATHLEN]; /* temporary buffer for filename */ static int recursion; /* number of depth */ char *fname; char *pc; /* don't add a folder to the list if user can't read it */ if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) return NULL; if (s_buf.st_mode & S_IFDIR) { int cnt = 0; int len; /* Only created pullright menu as necessary. Hence return it */ if (recursion) return (Menu_item)-1; recursion++; // Get an alphabetized list of the directory contents char **contents = get_dir_contents(path); /* don't bother adding to list if we can't scan it */ if ( ! contents ){ return NULL; } next_menu = (Menu)xv_create(XV_NULL, MENU, NULL); /* For each file, append it to the menu. If it is a directory */ /* append a pullright arrow. It is is unreadable file, make it */ /* inactive. */ char **dp; for (dp=contents; *dp; dp++){ if (strcmp(*dp, ".") && strcmp(*dp, "..")){ (void) sprintf(buf, "%s/%s", path, *dp); mi = add_path_to_menu(buf, addr_notify); if (!mi || mi == (Menu_item)-1) { int do_gen_pullright = (mi == (Menu_item)-1); mi = (Menu_item)xv_create(XV_NULL, MENUITEM, MENU_STRING, getfilename(*dp), MENU_RELEASE, MENU_RELEASE_IMAGE, MENU_NOTIFY_PROC, my_action_proc, XV_KEY_DATA, KEY_ADDR_DATA, addr_notify, NULL); if (do_gen_pullright) /* Append a pullright arrow and deactivate NOTIFY_PROC */ xv_set(mi, MENU_GEN_PULLRIGHT, gen_pullright, MENU_NOTIFY_PROC, NULL, NULL); else /* unreadable file or dir - deactivate item */ xv_set(mi, MENU_INACTIVE, TRUE, NULL); } xv_set(next_menu, MENU_APPEND_ITEM, mi, NULL); cnt++; } free(*dp); // Free filename memory } free((char *)contents); // Free pointer memory /* Create a menu item to be return to the caller */ mi = (Menu_item)xv_create(XV_NULL, MENUITEM, MENU_STRING, getfilename(path), MENU_RELEASE, MENU_RELEASE_IMAGE, MENU_NOTIFY_PROC, my_action_proc, XV_KEY_DATA, KEY_ADDR_DATA, addr_notify, NULL); if (!cnt) { /* Create an empty menu to indicate "No files" */ /* Note that no NOTIFY_PROC for this item */ Menu_item temp; temp = (Menu_item)xv_create(XV_NULL, MENUITEM, MENU_STRING, strdup("<No files>"), MENU_RELEASE, MENU_RELEASE_IMAGE, XV_KEY_DATA, KEY_ADDR_DATA, addr_notify, NULL); xv_set(next_menu, MENU_APPEND_ITEM, temp, NULL); } /* Truncate the path name for TITLE */ if ((len = strlen(path)) > 25) { (void)strcpy(title,"..."); (void)strcat(title, path + len - 25); } else (void)strcpy(title, path); xv_set(next_menu, MENU_TITLE_ITEM, title, MENU_CLIENT_DATA, strdup(path), NULL); xv_set(mi, MENU_PULLRIGHT, next_menu, NULL); recursion--; return mi; } /* Return a non directory file */ /* Translate any \ in file name to / */ fname = getfilename(path); /* Do not free--belongs to menu */ while (pc=strchr(fname, '\\') ){ *pc = '/'; } mi = (Menu_item)xv_create(NULL, MENUITEM, MENU_STRING, fname, MENU_RELEASE, MENU_RELEASE_IMAGE, MENU_NOTIFY_PROC, my_action_proc, XV_KEY_DATA, KEY_ADDR_DATA, addr_notify, NULL); return mi; }
void diff_archive (void) { register char *data; int check, namelen; int err; off_t offset; struct stat filestat; #ifndef __MSDOS__ dev_t dev; ino_t ino; #endif errno = EPIPE; /* FIXME, remove perrors */ saverec (&head); /* make sure it sticks around */ userec (head); /* and go past it in the archive */ decode_header (head, &hstat, &head_standard, 1); /* snarf fields */ /* Print the record from `head' and `hstat'. */ if (flag_verbose) { if (now_verifying) fprintf (stdlis, _("Verify ")); print_header (); } switch (head->header.linkflag) { default: WARN ((0, 0, _("Unknown file type '%c' for %s, diffed as normal file"), head->header.linkflag, current_file_name)); /* Fall through. */ case LF_OLDNORMAL: case LF_NORMAL: case LF_SPARSE: case LF_CONTIG: /* Appears to be a file. See if it's really a directory. */ namelen = strlen (current_file_name) - 1; if (current_file_name[namelen] == '/') goto really_dir; if (do_stat (&filestat)) { if (head->header.isextended) skip_extended_headers (); skip_file ((long) hstat.st_size); different++; goto quit; } if (!S_ISREG (filestat.st_mode)) { fprintf (stdlis, _("%s: Not a regular file\n"), current_file_name); skip_file ((long) hstat.st_size); different++; goto quit; } filestat.st_mode &= 07777; if (filestat.st_mode != hstat.st_mode) sigh (_("Mode")); if (filestat.st_uid != hstat.st_uid) sigh (_("Uid")); if (filestat.st_gid != hstat.st_gid) sigh (_("Gid")); if (filestat.st_mtime != hstat.st_mtime) sigh (_("Mod time")); if (head->header.linkflag != LF_SPARSE && filestat.st_size != hstat.st_size) { sigh (_("Size")); skip_file ((long) hstat.st_size); goto quit; } diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY); if (diff_fd < 0 && !flag_absolute_names) { char *tmpbuf = tar_xmalloc (strlen (current_file_name) + 2); *tmpbuf = '/'; strcpy (tmpbuf + 1, current_file_name); diff_fd = open (tmpbuf, O_NDELAY | O_RDONLY); free (tmpbuf); } if (diff_fd < 0) { ERROR ((0, errno, _("Cannot open %s"), current_file_name)); if (head->header.isextended) skip_extended_headers (); skip_file ((long) hstat.st_size); different++; goto quit; } /* Need to treat sparse files completely differently here. */ if (head->header.linkflag == LF_SPARSE) diff_sparse_files (hstat.st_size); else { if (flag_multivol) { assign_string (&save_name, current_file_name); save_totsize = hstat.st_size; /* save_size is set in wantbytes (). */ } wantbytes ((long) (hstat.st_size), compare_chunk); if (flag_multivol) assign_string (&save_name, NULL); } check = close (diff_fd); if (check < 0) ERROR ((0, errno, _("Error while closing %s"), current_file_name)); quit: break; #ifndef __MSDOS__ case LF_LINK: if (do_stat (&filestat)) break; dev = filestat.st_dev; ino = filestat.st_ino; err = stat (current_link_name, &filestat); if (err < 0) { if (errno == ENOENT) fprintf (stdlis, _("%s: Does not exist\n"), current_file_name); else WARN ((0, errno, _("Cannot stat file %s"), current_file_name)); different++; break; } if (filestat.st_dev != dev || filestat.st_ino != ino) { fprintf (stdlis, _("%s: Not linked to %s\n"), current_file_name, current_link_name); break; } break; #endif #ifdef S_ISLNK case LF_SYMLINK: { char linkbuf[NAMSIZ + 3]; /* FIXME: may be too short. */ check = readlink (current_file_name, linkbuf, (sizeof linkbuf) - 1); if (check < 0) { if (errno == ENOENT) fprintf (stdlis, _("%s: No such file or directory\n"), current_file_name); else WARN ((0, errno, _("Cannot read link %s"), current_file_name)); different++; break; } linkbuf[check] = '\0'; /* null-terminate it */ if (strncmp (current_link_name, linkbuf, (size_t) check) != 0) { fprintf (stdlis, _("%s: Symlink differs\n"), current_link_name); different++; } } break; #endif #ifdef S_IFCHR case LF_CHR: hstat.st_mode |= S_IFCHR; goto check_node; #endif #ifdef S_IFBLK /* If local system doesn't support block devices, use default case. */ case LF_BLK: hstat.st_mode |= S_IFBLK; goto check_node; #endif #ifdef S_ISFIFO /* If local system doesn't support FIFOs, use default case. */ case LF_FIFO: #ifdef S_IFIFO hstat.st_mode |= S_IFIFO; #endif hstat.st_rdev = 0; /* FIXME, do we need this? */ goto check_node; #endif check_node: /* FIXME, deal with umask. */ if (do_stat (&filestat)) break; if (hstat.st_rdev != filestat.st_rdev) { fprintf (stdlis, _("%s: Device numbers changed\n"), current_file_name); different++; break; } if ( #ifdef S_IFMT hstat.st_mode != filestat.st_mode #else /* POSIX lossage */ (hstat.st_mode & 07777) != (filestat.st_mode & 07777) #endif ) { fprintf (stdlis, _("%s: Mode or device-type changed\n"), current_file_name); different++; break; } break; case LF_DUMPDIR: data = diff_dir = get_dir_contents (current_file_name, 0); if (flag_multivol) { assign_string (&save_name, current_file_name); save_totsize = hstat.st_size; /* save_size is set in wantbytes (). */ } if (data) { wantbytes ((long) (hstat.st_size), compare_dir); free (data); } else wantbytes ((long) (hstat.st_size), no_op); if (flag_multivol) assign_string (&save_name, NULL); /* Fall through. */ case LF_DIR: /* Check for trailing /. */ namelen = strlen (current_file_name) - 1; really_dir: while (namelen && current_file_name[namelen] == '/') current_file_name[namelen--] = '\0'; /* zap / */ if (do_stat (&filestat)) break; if (!S_ISDIR (filestat.st_mode)) { fprintf (stdlis, _("%s: No longer a directory\n"), current_file_name); different++; break; } if ((filestat.st_mode & 07777) != (hstat.st_mode & 07777)) sigh (_("Mode")); break; case LF_VOLHDR: break; case LF_MULTIVOL: namelen = strlen (current_file_name) - 1; if (current_file_name[namelen] == '/') goto really_dir; if (do_stat (&filestat)) break; if (!S_ISREG (filestat.st_mode)) { fprintf (stdlis, _("%s: Not a regular file\n"), current_file_name); skip_file ((long) hstat.st_size); different++; break; } filestat.st_mode &= 07777; offset = from_oct (1 + 12, head->header.offset); if (filestat.st_size != hstat.st_size + offset) { sigh (_("Size")); skip_file ((long) hstat.st_size); different++; break; } diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY); if (diff_fd < 0) { WARN ((0, errno, _("Cannot open file %s"), current_file_name)); skip_file ((long) hstat.st_size); different++; break; } err = lseek (diff_fd, offset, 0); if (err != offset) { WARN ((0, errno, _("Cannot seek to %ld in file %s"), offset, current_file_name)); different++; break; } if (flag_multivol) { assign_string (&save_name, current_file_name); save_totsize = filestat.st_size; /* save_size is set in wantbytes (). */ } wantbytes ((long) (hstat.st_size), compare_chunk); if (flag_multivol) assign_string (&save_name, NULL); check = close (diff_fd); if (check < 0) ERROR ((0, errno, _("Error while closing %s"), current_file_name)); break; } /* We don't need to save it any longer. */ saverec ((union record **) 0); /* unsave it */ }