/* nwlistsalvage.c - Utility to list information about salvageagle files on NetWare volumes Copyright (c) 2005 Scott Bentley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Revision history: 0.00 2005 Scott Bentley Initial revision. */ #include #include #include #include #include #include #include "private/libintl.h" #define _(X) gettext(X) #ifdef N_PLAT_DOS #ifndef NTYPES_H typedef unsigned int nuint16; #endif typedef unsigned long nuint32; typedef unsigned int nuint; #else #endif static inline size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) { return strftime(s, max, fmt, tm); } static void doID(NWCONN_HANDLE conn, nuint32 id) { NWCCODE err; char user[MAX_DN_BYTES]; nuint16 type; if (!id) { printf(_("Nobody")); } else { #ifdef N_PLAT_DOS id = ntohl(id); #endif err = NWGetObjectName(conn, id, user, &type); if (err) { NWDSContextHandle ctx; sprintf(user, _("Unknown:N/A")); err = NWDSCreateContextHandle(&ctx); if (!err) { NWDSAddConnection(ctx, conn); err = NWDSMapIDToName(ctx, conn, id, user); if (err) sprintf(user, _("Unknown:<%s>"), strnwerror(err)); NWDSFreeContext(ctx); } } else { switch (type) { case OT_USER: printf(_("User:"));break; case OT_USER_GROUP: printf(_("Group:"));break; case OT_FILE_SERVER:printf(_("FileServer:"));break; default: printf(_("Unknown(%04X):"), type);break; } } printf("%s", user); } } static void dodate(nuint date) { static const time_t zero_time_t = 0; struct tm* tm; char text[100]; tm = gmtime(&zero_time_t); tm->tm_year = (date>>9)+80; tm->tm_mon = ((date>>5) & 0xF) - 1; tm->tm_mday = date & 0x1F; tm->tm_isdst = 0; my_strftime(text, sizeof(text), "%x", tm); printf("%s", text); } static void dotime(nuint dtime) { static const time_t zero_time_t = 0; struct tm* tm; char text[100]; tm = gmtime(&zero_time_t); tm->tm_hour = dtime >> 11; tm->tm_min = (dtime >> 5) & 0x3F; tm->tm_sec = (dtime << 1) & 0x3F; tm->tm_isdst = 0; my_strftime(text, sizeof(text), "%X", tm); printf("%s", text); } static void dodatesTimesID(NWCONN_HANDLE conn, nuint dtime, nuint date, nuint32 id) { if (dtime || date) { dodate(date); printf(" "); dotime(dtime); } else { printf("%-17s", _("never")); } if (id) { printf("%10s",""); doID(conn, id); } printf("\n"); } static void usage(void) { printf(_( "usage: nwlistsalvage [options] [directory]\n" "\n" "-h Print this help text\n" "-n Namespace for file access.\n" " DOS\n" " LONG - Default\n" " MAC\n" " NFS\n" " FTAM\n" "-v Verbose\n" "\n" "directory Directory to examine for salvageable files. Default is ./\n" "\n" )); } static int g_verbose = 0; static int g_files = 0; static int g_nwns = NW_NS_LONG; static void print_file_info(NWCONN_HANDLE conn, const struct ncp_deleted_file info, const struct NSI_Change deleted, const struct nw_info_struct3* vinfo) { NWCCODE err; struct NSI_Attributes attr; struct NSI_Name name; struct NSI_Modify modify; struct NSI_Change created; const char* type; //Get attributes err = ncp_ns_extract_info_field(vinfo,NSIF_ATTRIBUTES,&attr,sizeof(attr)); if (err) { printf("Cannot retrieve file attributes: %s\n",strnwerror(err)); return; } if (attr.Attributes & A_DIRECTORY) { type = "D"; } else { type = "F"; } //Get name err = ncp_ns_extract_info_field(vinfo,NSIF_NAME,&name,sizeof(name)); if (err) { printf(_("Cannot retrieve file name: %s\n"),strnwerror(err)); return; } // Show standard set of info printf("%2s%s %d %s\n", "", type, info.seq, name.Name); // Show verbose info if(g_verbose) { printf("%5sDeleted:\t\t",""); dodatesTimesID(conn,deleted.Time,deleted.Date,deleted.ID); printf("%5sCreated:\t\t",""); err = ncp_ns_extract_info_field(vinfo,NSIF_CREATION,&created,sizeof(created)); if (err) { printf(_("Cannot retrieve creation info: %s\n"),strnwerror(err)); return; } else { dodatesTimesID(conn,created.Time,created.Date,created.ID); } printf("%5sLast Modified:\t",""); err = ncp_ns_extract_info_field(vinfo,NSIF_MODIFY,&modify,sizeof(modify)); if (err) { printf(_("Cannot retrieve modified info: %s\n"),strnwerror(err)); return; } else { dodatesTimesID(conn,modify.Modify.Time,modify.Modify.Date,modify.Modify.ID); } } } static void list_salvageable_files(struct ncp_conn* conn, int volume, u_int32_t directory_id) { struct ncp_deleted_file info;//file info struct nw_info_struct3 vinfo;//verbose file info struct NSI_Change deleted; vinfo.len =0; vinfo.data = NULL; info.seq = -1;//Initialize the file id to start with first file while (!ncp_ns_scan_salvageable_file2(conn, g_nwns, 1, volume, directory_id, NULL, 0, &info, &deleted, IM_ALL, &vinfo, sizeof(vinfo) )) { print_file_info(conn,info,deleted,&vinfo); vinfo.len = 0; free(vinfo.data); vinfo.data = NULL; g_files++; } printf("\n"); } int main(int argc, char* argv[]) { struct NWCCRootEntry root; const char* mount_path; const char* opt_n; struct ncp_conn* conn; int err; int c; setlocale(LC_ALL, ""); bindtextdomain(NCPFS_PACKAGE, LOCALEDIR); textdomain(NCPFS_PACKAGE); while ((c = getopt(argc, argv, "hnv")) != -1) { switch (c) { case '?': case ':': case 'h':usage(); exit(2); case 'n': opt_n = argv[optind++]; if (strcasecmp(opt_n, "DOS") == 0) { g_nwns = NW_NS_DOS; } else if (strcasecmp(opt_n, "MAC") == 0) { g_nwns = NW_NS_MAC; } else if (strcasecmp(opt_n, "NFS") == 0) { g_nwns = NW_NS_NFS; } else if (strcasecmp(opt_n, "FTAM") == 0) { g_nwns = NW_NS_FTAM; } else if (strcasecmp(opt_n, "LONG") == 0) { g_nwns = NW_NS_LONG; } else { fprintf(stderr, _("Unrecognized namespace for option '-%c'\n"), c); exit(1); } break; case 'v':g_verbose = 1; break; default: fprintf(stderr, _("Unexpected option `-%c'\n"), c); break; } } if (optind < argc) { mount_path = argv[optind++]; } else { mount_path = "."; } err = ncp_open_mount(mount_path, &conn); if (err) { com_err("nwlistsalvage", err, _("in ncp_open_mount")); exit(1); } err = NWCCGetConnInfo(conn, NWCC_INFO_ROOT_ENTRY, sizeof(root), &root); if (err) { com_err("nwlistsalvage", err, _("when retrieving root entry")); ncp_close(conn); return 0; } list_salvageable_files(conn, root.volume, root.dirEnt); if (!g_files) { printf(_("No salvageable files were found.\n")); } else if (g_files == 1) { printf(_("1 salvageable file was found.\n")); } else { printf(_("%d salvageable files were found.\n"), g_files); } ncp_close(conn); return 0; }