/* nwdir.c - list contents of directory Copyright (c) 1998 Milan Vandrovec Copyright (c) 1999-2001 Petr Vandrovec 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 1998 Milan Vandrovec Initial revision. 0.01 1999 Petr Vandrovec Updated for new ncp_ns_* interface. 1.00 1999, November 20 Petr Vandrovec Added license. 1.01 2000, August 24 Petr Vandrovec Updated to ncp_ns_search_init/ncp_ns_search_next/ ncp_ns_search_end. Updated to ncp_ns_extract_info_field. 1.02 2000, August 27 Petr Vandrovec Added ncp_ea_enumerate code. 1.03 2001, January 27 Petr Vandrovec Updated to use getopt interface. Added ncp_ns_scan_connections_using_file dump code. 1.04 2001, February 4 Petr Vandrovec Added ncp_ns_scan_physical_locks_by_file dump code. 1.05 2001, May 31 Petr Vandrovec Use unistd.h and not getopt.h for getopt(). 1.06 2002, February 4 Petr Vandrovec Do not dump core when file opened for nothing is found. */ #include #include #include #include #include #include #include #include #include "private/libintl.h" #define _(X) gettext(X) #define N_(X) (X) #ifndef A_DONT_SUBALLOCATE #define A_DONT_SUBALLOCATE 0x00000800L #endif #ifdef N_PLAT_DOS #ifndef NTYPES_H typedef unsigned int nuint16; #endif typedef unsigned long nuint32; typedef unsigned int nuint; #define P08X "(%08lX)" #define P32U "lu" #else #define stricmp(A,B) strcasecmp(A,B) #define P08X "(%08X)" #define P32U "u" #endif static int opt_t = 0; static int opt_l = 0; static int opt_v = 0; static int opt_e = 0; static int opt_f = 0; static int opt_p = 0; static void ncpb_add_byte(unsigned char** c, int v) { *(*c)++ = v; } static void ncpb_add_word_lh(unsigned char** c, nuint v) { WSET_LH(*c, 0, v); (*c)+=2; } static void ncpb_add_dword_lh(unsigned char** c, nuint32 v) { DSET_LH(*c, 0, v); (*c)+=4; } static nuint16 ncpb_get_word_lh(unsigned char** c) { nuint16 tmp; tmp = WVAL_LH(*c, 0); (*c)+=2; return tmp; } u_int32_t img; struct nsInfo { struct NSI_Name name; struct NSI_Directory dir; int valid; }; static struct nsInfo os2, mac, nfs; static unsigned char buf[1024]; static unsigned char buf2[1024]; static NWCCODE NWNSEntryInfo2(NWCONN_HANDLE conn, nuint32 vol, nuint32 dosdir, nuint ns, struct NSI_Name* name, struct NSI_Directory* dir) { struct nw_info_struct3 info; NWCCODE err; info.len = 0; info.data = NULL; err = ncp_ns_obtain_entry_info(conn, NW_NS_DOS, SA_ALL, 1, vol, dosdir, NULL, 0, ns, RIM_NAME | RIM_DIRECTORY, &info, sizeof(info)); if (err) return err; err = ncp_ns_extract_info_field(&info, NSIF_NAME, name, sizeof(*name)); if (!err) { err = ncp_ns_extract_info_field(&info, NSIF_DIRECTORY, dir, sizeof(*dir)); } free(info.data); return err; } static NWCCODE NWNSScanForTrustees(NWCONN_HANDLE conn, nuint32 vol, nuint32 dosdir, nuint32* iter, nuint* no_tstees, TRUSTEE_INFO* tstees) { return ncp_ns_trustee_scan(conn, NW_NS_DOS, SA_ALL, 1, vol, dosdir, NULL, 0, iter, tstees, no_tstees); } static NWCCODE NWNSGetEffectiveRights(NWCONN_HANDLE conn, nuint32 vol, nuint32 dosdir, nuint16* eff) { unsigned char* c=buf2; NW_FRAGMENT rq; NW_FRAGMENT rp; NWCCODE err; ncpb_add_byte(&c, 0x1D); ncpb_add_byte(&c, NW_NS_DOS); ncpb_add_byte(&c, 0); /* ?? */ ncpb_add_word_lh(&c, SA_ALL); ncpb_add_dword_lh(&c, 0); /* ReturnInfoMask=0, we are not interested in anything */ ncpb_add_byte(&c, vol); ncpb_add_dword_lh(&c, dosdir); ncpb_add_byte(&c, 1); ncpb_add_byte(&c, 0); rq.fragAddress = buf2; rq.fragSize = c-buf2; rp.fragAddress = buf; rp.fragSize = sizeof(buf); err = NWRequest(conn, 0x57, 1, &rq, 1, &rp); if (err) return err; c = buf; *eff = ncpb_get_word_lh(&c); return 0; } static char* createMask311(nuint mask) { static char r[9]; r[0] = (mask&TR_SUPERVISOR) ?'S':'-'; r[1] = (mask&TR_READ) ?'R':'-', r[2] = (mask&TR_WRITE) ?'W':'-', r[3] = (mask&TR_CREATE) ?'C':'-', r[4] = (mask&TR_ERASE) ?'E':'-', r[5] = (mask&TR_MODIFY) ?'M':'-', r[6] = (mask&TR_SEARCH) ?'F':'-', r[7] = (mask&TR_ACCESS_CTRL)?'A':'-', r[8] = 0; return r; } static void doID(NWCONN_HANDLE conn, nuint32 id) { NWCCODE err; char user[MAX_DN_BYTES]; nuint16 type; if (opt_t) printf(P08X " ", id); 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 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 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(" "); doID(conn, id); } printf("\n"); } static void eaenum(NWCONN_HANDLE conn, u_int32_t volume, u_int32_t dirent) { unsigned char vv[2048]; size_t pos; struct ncp_ea_enumerate_info winfo; NWCCODE err; int sawtitle = 0; unsigned int eaid = 1; winfo.enumSequence = 0; err = ncp_ea_enumerate(conn, NWEA_FL_INFO1 | NWEA_FL_CLOSE_ERR | NWEA_FL_SRC_DIRENT, volume, dirent, -1, NULL, 0, &winfo, vv, sizeof(vv), &pos); do { size_t rinfo; const unsigned char* p; if (err) { //fprintf(stderr, "Enumeration failed: %s\n", // strnwerror(err)); return; } if (winfo.errorCode) { /* should not happen as we used NWEA_FL_CLOSE_ERR */ //fprintf(stderr, "Enumeration extended fail: %s\n", // strnwerror((winfo.errorCode & 0xFF) | NWE_SERVER_ERROR)); break; } /* no extended attributes */ if (!winfo.totalEAs) break; if (!sawtitle) { printf(_("Extended attributes: %lu attributes\n" " %lu bytes in keys, %lu bytes in data\n"), (unsigned long)winfo.totalEAs, (unsigned long)winfo.totalEAsKeySize, (unsigned long)winfo.totalEAsDataSize); sawtitle = 1; } p = vv; for (rinfo = 0; rinfo < winfo.returnedItems; rinfo++) { struct ncp_ea_info_level1 ppp; err = ncp_ea_extract_info_level1(p, vv + pos, &ppp, sizeof(ppp), NULL, &p); if (err) printf(" Key %u: Cannot retrieve: %s\n", eaid, strnwerror(err)); else { printf(_(" Key %u:\n" " Name: %s\n" " Access Flag: 0x%08zX\n" " Value Length: %lu\n"), eaid, ppp.key, ppp.accessFlag, (unsigned long)ppp.valueLength); } eaid++; } if (!winfo.enumSequence) break; err = ncp_ea_enumerate(conn, NWEA_FL_INFO1 | NWEA_FL_CLOSE_ERR | NWEA_FL_SRC_EAHANDLE, winfo.newEAhandle, 0, -1, NULL, 0, &winfo, vv, sizeof(vv), &pos); } while (1); if (winfo.newEAhandle) { err = ncp_ea_close(conn, winfo.newEAhandle); // if (err) { // fprintf(stderr, "Close EA failed: %s\n", // strnwerror(err)); // } } if (sawtitle) printf("\n"); } static void dumpDataSizes(const struct nw_info_struct3* info) { NWCCODE err; struct NSI_DatastreamLogicals* logical; size_t tmplen; if (!(img & RIM_DATASTREAM_LOGICALS)) { ncp_off64_t off; err = ncp_ns_extract_info_field(info, NSIF_DATA_SIZE, &off, sizeof(off)); if (err) { printf(_(" Cannot determine file size: %s\n"), strnwerror(err)); } else { printf(_(" File size: %10llu"), (unsigned long long)off); err = ncp_ns_extract_info_field(info, NSIF_SPACE_ALLOCATED, &off, sizeof(off)); if (!err) { printf(_(" (allocated %llu)"), off * 8ULL); } printf("\n"); } return; } err = ncp_ns_extract_info_field_size(info, NSIF_DATASTREAM_LOGICALS, &tmplen); if (err) return; logical = (struct NSI_DatastreamLogicals*)malloc(tmplen); if (!logical) return; err = ncp_ns_extract_info_field(info, NSIF_DATASTREAM_LOGICALS, logical, tmplen); if (err) { printf(_(" Cannot determine file size: %s\n"), strnwerror(err)); } else if (!logical->NumberOfDatastreams) { printf(_(" No datastream exist\n")); } else { struct NSI_DatastreamSizes* size; size_t i; size = NULL; err = ncp_ns_extract_info_field_size(info, NSIF_DATASTREAM_SIZES, &tmplen); if (!err) { size = (struct NSI_DatastreamSizes*)malloc(tmplen); if (size) { err = ncp_ns_extract_info_field(info, NSIF_DATASTREAM_SIZES, size, tmplen); if (err) { free(size); size = NULL; } } } for (i = 0; i < logical->NumberOfDatastreams; i++) { size_t j; u_int32_t num = logical->ds[i].Number; if (num) { printf(_(" Stream %3u size: %10llu"), num, (unsigned long long)logical->ds[i].Size); } else { printf(_(" File size: %10llu"), (unsigned long long)logical->ds[i].Size); } if (size) { for (j = 0; j < size->NumberOfDatastreams; j++) { if (size->ds[j].Number == num) { printf(_(" (allocated %llu)"), ((ncp_off64_t)size->ds[j].FATBlockSize) * 512ULL); break; } } } printf("\n"); } if (size) free(size); } free(logical); } static void dumpit(NWCONN_HANDLE conn, const struct nw_info_struct3* info) { NWCCODE err; struct NSI_Attributes attr; struct NSI_Name name; struct NSI_Directory dir; err = ncp_ns_extract_info_field(info, NSIF_ATTRIBUTES, &attr, sizeof(attr)); if (err) { fprintf(stderr, _("Cannot retrieve file attributes: %s\n"), strnwerror(err)); return; } err = ncp_ns_extract_info_field(info, NSIF_DIRECTORY, &dir, sizeof(dir)); if (err) { fprintf(stderr, _("Cannot retrieve file number: %s\n"), strnwerror(err)); return; } err = ncp_ns_extract_info_field(info, NSIF_NAME, &name, sizeof(name)); if (err) { fprintf(stderr, _("Cannot retrieve file name: %s\n"), strnwerror(err)); return; } if (attr.Attributes & A_DIRECTORY) { printf(_("Directory:\n")); } else { printf(_("File:\n")); } if (opt_v || opt_l) { err = NWNSEntryInfo2(conn, dir.volNumber, dir.DosDirNum, NW_NS_OS2, &os2.name, &os2.dir); os2.valid = err==0; err = NWNSEntryInfo2(conn, dir.volNumber, dir.DosDirNum, NW_NS_MAC, &mac.name, &mac.dir); mac.valid = err==0; err = NWNSEntryInfo2(conn, dir.volNumber, dir.DosDirNum, NW_NS_NFS, &nfs.name, &nfs.dir); nfs.valid = err==0; } else { os2.valid = 0; mac.valid = 0; nfs.valid = 0; } printf(_(" DOS: ")); if (opt_t) printf(P08X " ", dir.dirEntNum); printf("%s\n", name.Name); if (os2.valid) { printf(_(" OS/2: ")); if (opt_t) printf(P08X " ", os2.dir.dirEntNum); printf("%s\n", os2.name.Name); } if (nfs.valid) { printf(_(" NFS: ")); if (opt_t) printf(P08X " ", nfs.dir.dirEntNum); printf("%s\n", nfs.name.Name); } if (mac.valid) { printf(_(" MAC: ")); if (opt_t) printf(P08X " ", mac.dir.dirEntNum); printf("%s\n", mac.name.Name); } printf("\n"); if (opt_v) { u_int32_t inheritedRightsMask; printf(_("Rights:\n")); printf(_(" Inherited: ")); err = ncp_ns_extract_info_field(info, NSIF_RIGHTS, &inheritedRightsMask, sizeof(inheritedRightsMask)); if (err) { printf(_("Cannot determine: %s\n"), strnwerror(err)); } else { nuint32 eff32; if (opt_t) printf("(%04X) ", inheritedRightsMask); printf("[%s]\n", createMask311(inheritedRightsMask)); err = ncp_ns_extract_info_field(info, NSIF_EFFECTIVE_RIGHTS, &eff32, sizeof(eff32)); if (err) { nuint16 eff; err = NWNSGetEffectiveRights(conn, dir.volNumber, dir.DosDirNum, &eff); if (!err) { eff32 = eff; } } printf(_(" Effective: ")); if (err) { printf(_("Cannot determine: %s\n"), strnwerror(err)); } else { if (opt_t) printf("(%04X) ", eff32); printf("[%s]\n", createMask311(eff32)); } } printf("\n"); } if (opt_l || opt_v) { u_int32_t ns; printf(_("Owning namespace: ")); err = ncp_ns_extract_info_field(info, NSIF_OWNING_NAMESPACE, &ns, sizeof(ns)); if (err) { printf(_("Cannot determine: %s\n"), strnwerror(err)); } else { if (opt_t) printf("(%" P32U ") ", ns); printf("%s\n", ncp_namespace_to_str(NULL, ns)); } printf("\n"); } if (opt_v) { struct NSI_Modify modify; struct NSI_Change change; NWCCODE moderr; printf(_("Miscellaneous NetWare Information:\n")); printf(_(" Last update: ")); moderr = ncp_ns_extract_info_field(info, NSIF_MODIFY, &modify, sizeof(modify)); if (moderr) { printf(_("Cannot determine: %s\n"), strnwerror(moderr)); } else { dodatesTimesID(conn, modify.Modify.Time, modify.Modify.Date, modify.Modify.ID); } printf(_(" Last archived: ")); err = ncp_ns_extract_info_field(info, NSIF_ARCHIVE, &change, sizeof(change)); if (err) { printf(_("Cannot determine: %s\n"), strnwerror(err)); } else { dodatesTimesID(conn, change.Time, change.Date, change.ID); } if (1 || !(attr.Attributes&A_DIRECTORY)) { printf(_(" Last accessed: ")); if (moderr) { printf(_("Cannot determine: %s\n"), strnwerror(moderr)); } else { dodatesTimesID(conn, modify.LastAccess.Time, modify.LastAccess.Date, 0); } } printf(_(" Created/Copied: ")); err = ncp_ns_extract_info_field(info, NSIF_CREATION, &change, sizeof(change)); if (err) { printf(_("Cannot determine: %s\n"), strnwerror(err)); } else { dodatesTimesID(conn, change.Time, change.Date, change.ID); } printf(_(" Flags: [%s%s%s%s]"), (attr.Attributes&A_READ_ONLY )?"Ro":"Rw", (attr.Attributes&A_SYSTEM )?"Sy":"--", (attr.Attributes&A_HIDDEN )?"H" :"-", (attr.Attributes&A_NEEDS_ARCHIVED)?"A" :"-"); printf(" [%s%s%s%s" "%s%s%s" "%s" "%s%s%s%s%s]", (attr.Attributes&A_EXECUTE_ONLY )?"X" :"-", (attr.Attributes&A_TRANSACTIONAL )?"T" :"-", (attr.Attributes&A_IMMEDIATE_PURGE)?"P":"-", (attr.Attributes&A_SHAREABLE )?"Sh":"--", (attr.Attributes&A_DELETE_INHIBIT)?"Di":"--", (attr.Attributes&A_COPY_INHIBIT )?"Ci":"--", (attr.Attributes&A_RENAME_INHIBIT)?"Ri":"--", (attr.Attributes&A_DONT_COMPRESS )?"Dc": (attr.Attributes&A_IMMEDIATE_COMPRESS)?"Ic":"--", (attr.Attributes&A_DONT_MIGRATE )?"Dm":"--", (attr.Attributes&A_DONT_SUBALLOCATE)?"Ds":"--", (attr.Attributes&A_INDEXED )?"I":"--", (attr.Attributes&A_READ_AUDIT )?"Ra":"--", (attr.Attributes&A_WRITE_AUDIT )?"Wa":"--"); printf(" [%s%s]", (attr.Attributes&A_FILE_COMPRESSED)?"Co": (attr.Attributes&A_CANT_COMPRESS)?"Cc":"--", (attr.Attributes&A_FILE_MIGRATED )?"M":"-"); if (opt_t) printf(" " P08X, attr.Attributes); printf("\n"); if (!(attr.Attributes&A_DIRECTORY)) { dumpDataSizes(info); } printf("\n"); { nuint32 iter = 0; int first = 1; while (1) { nuint tcount; nuint i; TRUSTEE_INFO tstees[40]; tcount = 40; err = NWNSScanForTrustees(conn, dir.volNumber, dir.DosDirNum, &iter, &tcount, tstees); if (err) break; for (i=0; i= 0x400) { img |= RIM_COMPRESSED_INFO; if (opt_v) { img |= RIM_DATASTREAM_SIZES | RIM_DATASTREAM_LOGICALS; } } if (nwver >= 0x40B) { if (opt_v) { img |= RIM_MAC_FINDER_INFO | RIM_EFFECTIVE_RIGHTS | RIM_MAC_TIMES; } } if (nwver >= 0x500) { if (opt_v) { img |= RIM_LAST_ACCESS_TIME; } } if ((dosNS2.Attributes.Attributes & A_DIRECTORY) && !opt_d) { listdir(conn, dosNS2.Directory.volNumber, dosNS2.Directory.DosDirNum, dwild); } else { struct nw_info_struct3 info; info.len = 0; info.data = NULL; err = ncp_ns_obtain_entry_info(conn, NW_NS_DOS, SA_ALL, 1, dosNS2.Directory.volNumber, dosNS2.Directory.DosDirNum, NULL, 0, NW_NS_DOS, IM_ALL, &info, sizeof(info)); if (err) { fprintf(stderr, _("Cannot retrieve info: %s\n"), strnwerror(err)); } else { dumpit(conn, &info); free(info.data); } } return 0; }