This is proc.c in view mode; [Download] [Up]
/* * proc.c * * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke * * 28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per * * Modified for big endian support by Christian Starkjohann. */ #include <linux/config.h> #include <linux/fs.h> #include <linux/smbno.h> #include <linux/smb_fs.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/malloc.h> #include <linux/stat.h> #include <linux/fcntl.h> #include <asm/segment.h> #include <asm/string.h> #ifdef __LITTLE_ENDIAN__ #define ARCH i386 #else #define ARCH m68k #endif #define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN) #define SMB_CMD(packet) ((packet)[8]) #define SMB_WCT(packet) ((packet)[SMB_HEADER_LEN - 1]) #define SMB_BCC(packet) smb_bcc(packet) #define SMB_BUF(packet) ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2) #define SMB_DIRINFO_SIZE 43 #define SMB_STATUS_SIZE 21 #define HI_WORD(l) ((word)(l >> 16)) #define LO_WORD(l) ((word)(l % 0xFFFF)) void smb_printerr(int class, int num); static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc); /* * The following is an evil hack to make debugging in "proc.c" configurable * from the commandline. */ #undef DPRINTK #undef DDPRINTK #include "my_defines.h" #define DPRINTK(format, args...) \ if(debug_mode & DEBUG_PROC) printk(format, ## args) #define DDPRINTK(format, args...) \ if(debug_mode & DEBUG_PROC_NOISY) printk(format , ## args) /*****************************************************************************/ /* */ /* Encoding/Decoding section */ /* */ /*****************************************************************************/ static byte * smb_encode_word(byte *p, word data) { #if (ARCH == i386) *((word *)p) = data; #else p[0] = data & 0x00ffU; p[1] = (data & 0xff00U) >> 8; #endif return &p[2]; } static byte * smb_decode_word(byte *p, word *data) { #if (ARCH == i386) *data = *(word *)p; #else *data = (word) p[0] | p[1] << 8; #endif return &p[2]; } byte * smb_encode_smb_length(byte *p, dword len) { p[0] = p[1] = 0; p[2] = (len & 0xFF00) >> 8; p[3] = (len & 0xFF); if (len > 0xFFFF) p[1] |= 0x01; return &p[4]; } static byte * smb_encode_dialect(byte *p, const byte *name, int len) { *p ++ = 2; strcpy(p, name); return p + len + 1; } static byte * smb_encode_ascii(byte *p, const byte *name, int len) { *p ++ = 4; strcpy(p, name); return p + len + 1; } static byte * smb_encode_vblock(byte *p, const byte *data, word len, int fs) { *p ++ = 5; p = smb_encode_word(p, len); if (fs) memcpy_fromfs(p, data, len); else memcpy(p, data, len); return p + len; } static byte * smb_decode_data(byte *p, byte *data, word *data_len, int fs) { word len; if (!(*p == 1 || *p == 5)) { printk("smb_decode_data: Warning! Data block not starting " "with 1 or 5\n"); } len = WVAL(p, 1); p += 3; if (fs) memcpy_tofs(data, p, len); else memcpy(data, p, len); *data_len = len; return p + len; } static byte * smb_name_mangle(byte *p, const byte *name) { int len, pad = 0; len = strlen(name); if (len < 16) pad = 16 - len; *p ++ = 2 * (len + pad); while (*name) { *p ++ = (*name >> 4) + 'A'; *p ++ = (*name & 0x0F) + 'A'; name ++; } while (pad --) { *p ++ = 'C'; *p ++ = 'A'; } *p++ = '\0'; return p; } /* The following are taken directly from msdos-fs */ /* Linear day numbers of the respective 1sts in non-leap years. */ static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ extern struct timezone sys_tz; static int utc2local(int time) { return time - sys_tz.tz_minuteswest*60; } static int local2utc(int time) { return time + sys_tz.tz_minuteswest*60; } /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ static int date_dos2unix(unsigned short time,unsigned short date) { int month,year,secs; month = ((date >> 5) & 15)-1; year = date >> 9; secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && month < 2 ? 1 : 0)+3653); /* days since 1.1.70 plus 80's leap day */ return local2utc(secs); } /* Convert linear UNIX date to a MS-DOS time/date pair. */ static void date_unix2dos(int unix_date,unsigned short *time, unsigned short *date) { int day,year,nl_day,month; unix_date = utc2local(unix_date); *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ (((unix_date/3600) % 24) << 11); day = unix_date/86400-3652; year = day/365; if ((year+3)/4+365*year > day) year--; day -= (year+3)/4+365*year; if (day == 59 && !(year & 3)) { nl_day = day; month = 2; } else { nl_day = (year & 3) || day <= 59 ? day : day-1; for (month = 0; month < 12; month++) if (day_n[month] > nl_day) break; } *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9); } /*****************************************************************************/ /* */ /* Support section. */ /* */ /*****************************************************************************/ dword smb_len(byte *packet) { return ((packet[1] & 0x1) << 16L) | (packet[2] << 8L) | (packet[3]); } static word smb_bcc(byte *packet) { int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word); #if (ARCH == i386) return *((word *)((byte *)packet + pos)); #else return packet[pos] | packet[pos+1] << 8; #endif } /* smb_valid_packet: We check if packet fulfills the basic requirements of a smb packet */ static int smb_valid_packet(byte *packet) { DDPRINTK("len: %ld, wct: %d, bcc: %d\n", smb_len(packet), SMB_WCT(packet), SMB_BCC(packet)); return ( packet[4] == 0xff && packet[5] == 'S' && packet[6] == 'M' && packet[7] == 'B' && (smb_len(packet) + 4 == SMB_HEADER_LEN + SMB_WCT(packet) * 2 + SMB_BCC(packet))); } /* smb_verify: We check if we got the answer we expected, and if we got enough data. If bcc == -1, we don't care. */ static int smb_verify(byte *packet, int command, int wct, int bcc) { return (SMB_CMD(packet) == command && SMB_WCT(packet) >= wct && (bcc == -1 || SMB_BCC(packet) >= bcc)) ? 0 : -EIO; } static int smb_errno(int errcls, int error) { if(debug_mode & DEBUG_PROC_NOISY){ if (errcls) { printk("smb_errno: "); smb_printerr(errcls, error); printk("\n"); } } if (errcls == ERRDOS) switch (error) { case ERRbadfunc: return EINVAL; case ERRbadfile: return ENOENT; case ERRbadpath: return ENOENT; case ERRnofids: return EMFILE; case ERRnoaccess: return EACCES; case ERRbadfid: return EBADF; case ERRbadmcb: return EREMOTEIO; case ERRnomem: return ENOMEM; case ERRbadmem: return EFAULT; case ERRbadenv: return EREMOTEIO; case ERRbadformat: return EREMOTEIO; case ERRbadaccess: return EACCES; case ERRbaddata: return E2BIG; case ERRbaddrive: return ENXIO; case ERRremcd: return EREMOTEIO; case ERRdiffdevice: return EXDEV; case ERRnofiles: return 0; case ERRbadshare: return ETXTBSY; case ERRlock: return EDEADLK; case ERRfilexists: return EEXIST; case 87: return 0; /* Unknown error!! */ /* This next error seems to occur on an mv when * the destination exists */ case 183: return EEXIST; default: return EIO; } else if (errcls == ERRSRV) switch (error) { case ERRerror: return ENFILE; case ERRbadpw: return EINVAL; case ERRbadtype: return EIO; case ERRaccess: return EACCES; default: return EIO; } else if (errcls == ERRHRD) switch (error) { case ERRnowrite: return EROFS; case ERRbadunit: return ENODEV; case ERRnotready: return EUCLEAN; case ERRbadcmd: return EIO; case ERRdata: return EIO; case ERRbadreq: return ERANGE; case ERRbadshare: return ETXTBSY; case ERRlock: return EDEADLK; default: return EIO; } else if (errcls == ERRCMD) return EIO; return 0; } static char print_char(char c) { if ((c < ' ') || (c > '~')) return '.'; return c; } static void smb_dump_packet(byte *packet) { int i, j, len; int errcls, error; errcls = (int)packet[9]; error = (int)(int)(packet[11]|packet[12]<<8); printk("smb_len = %d valid = %d \n", len = smb_len(packet), smb_valid_packet(packet)); printk("smb_cmd = %d smb_wct = %d smb_bcc = %d\n", packet[8], SMB_WCT(packet), SMB_BCC(packet)); printk("smb_rcls = %d smb_err = %d\n", errcls, error); if (errcls) { smb_printerr(errcls, error); printk("\n"); } if (len > 100) len = 100; for (i = 0; i < len; i += 10) { printk("%03d:", i); for (j = i; j < i+10; j++) if (j < len) printk("%02x ", packet[j]); else printk(" "); printk(": "); for (j = i; j < i+10; j++) if (j < len) printk("%c", print_char(packet[j])); printk("\n"); } } static void smb_lock_server(struct smb_server *server) { while (server->lock) sleep_on(&server->wait); server->lock = 1; } static void smb_unlock_server(struct smb_server *server) { if (server->lock != 1) { printk("smb_unlock_server: was not locked!\n"); } server->lock = 0; wake_up(&server->wait); } /* smb_request_ok: We expect the server to be locked. Then we do the request and check the answer completely. When smb_request_ok returns 0, you can be quite sure that everything went well. When the answer is <=0, the returned number is a valid unix errno. */ static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc) { int result = 0; s->rcls = 0; s->err = 0; if (smb_request(s) < 0) { DPRINTK("smb_request failed\n"); result = -EIO; } else if (smb_valid_packet(s->packet) != 0) { DPRINTK("not a valid packet!\n"); result = -EIO; } else if (s->rcls != 0) { result = -smb_errno(s->rcls, s->err); } else if (smb_verify(s->packet, command, wct, bcc) != 0) { DPRINTK("smb_verify failed\n"); result = -EIO; } return result; } /* smb_retry: This function should be called when smb_request_ok has indicated an error. If the error was indicated because the connection was killed, we try to reconnect. If smb_retry returns 0, the error was indicated for another reason, so a retry would not be of any use. */ static int smb_retry(struct smb_server *server) { if (server->state == CONN_VALID) { return 0; } if (smb_release(server) < 0) { DPRINTK("smb_retry: smb_release failed\n"); server->state = CONN_RETRIED; return 0; } if(smb_proc_reconnect(server) < 0) { DPRINTK("smb_proc_reconnect failed\n"); server->state = CONN_RETRIED; return 0; } server->state = CONN_VALID; return 1; } static int smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc) { int result = smb_request_ok(s, command, wct, bcc); smb_unlock_server(s); return result; } /* smb_setup_header: We completely set up the packet. You only have to insert the command-specific fields */ static byte * smb_setup_header(struct smb_server *server, byte command, word wct, word bcc) { dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2; byte *p = server->packet; byte *buf = server->packet; p = smb_encode_smb_length(p, xmit_len); BSET(p,0,0xff); BSET(p,1,'S'); BSET(p,2,'M'); BSET(p,3,'B'); BSET(p,4,command); p += 5; memset(p, '\0', 19); p += 19; p += 8; WSET(buf, smb_tid, server->tid); WSET(buf, smb_pid, server->pid); WSET(buf, smb_uid, server->server_uid); WSET(buf, smb_mid, server->mid); if (server->protocol > PROTOCOL_CORE) { BSET(buf, smb_flg, 0x8); WSET(buf, smb_flg2, 0x3); } *p++ = wct; /* wct */ p += 2*wct; WSET(p, 0, bcc); return p+2; } /* smb_setup_header_exclusive waits on server->lock and locks the server, when it's free. You have to unlock it manually when you're finished with server->packet! */ static byte * smb_setup_header_exclusive(struct smb_server *server, byte command, word wct, word bcc) { smb_lock_server(server); return smb_setup_header(server, command, wct, bcc); } /*****************************************************************************/ /* */ /* File operation section. */ /* */ /*****************************************************************************/ int smb_proc_open(struct smb_server *server, const char *pathname, int len, struct smb_dirent *entry) { int error; char* p; char* buf = server->packet; const word o_attr = aSYSTEM | aHIDDEN | aDIR; DPRINTK("smb_proc_open: path=%s\n", pathname); smb_lock_server(server); retry: p = smb_setup_header(server, SMBopen, 2, 2 + len); WSET(buf, smb_vwv0, 0x42); /* read/write */ WSET(buf, smb_vwv1, o_attr); smb_encode_ascii(p, pathname, len); if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) { if (smb_retry(server)) { goto retry; } if (error != -EACCES) { smb_unlock_server(server); return error; } p = smb_setup_header(server, SMBopen, 2, 2 + len); WSET(buf, smb_vwv0, 0x40); /* read only */ WSET(buf, smb_vwv1, o_attr); smb_encode_ascii(p, pathname, len); if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) { if (smb_retry(server)) { goto retry; } smb_unlock_server(server); return error; } } /* We should now have data in vwv[0..6]. */ entry->fileid = WVAL(buf, smb_vwv0); entry->attr = WVAL(buf, smb_vwv1); entry->ctime = entry->atime = entry->mtime = local2utc(DVAL(buf, smb_vwv2)); entry->size = DVAL(buf, smb_vwv4); entry->access = WVAL(buf, smb_vwv6); entry->opened = 1; entry->access &= 3; smb_unlock_server(server); DPRINTK("smb_proc_open: entry->access = %d\n", entry->access); return 0; } /* smb_proc_close: in finfo->mtime we can send a modification time to the server */ int smb_proc_close(struct smb_server *server, __u16 fileid, __u32 mtime) { char *buf = server->packet; smb_setup_header_exclusive(server, SMBclose, 3, 0); WSET(buf, smb_vwv0, fileid); DSET(buf, smb_vwv1, utc2local(mtime)); return smb_request_ok_unlock(server, SMBclose, 0, 0); } /* In smb_proc_read and smb_proc_write we do not retry, because the file-id would not be valid after a reconnection. */ /* smb_proc_read: fs indicates if it should be copied with memcpy_tofs. */ int smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data, int fs) { word returned_count, data_len; char *buf = server->packet; int error; smb_setup_header_exclusive(server, SMBread, 5, 0); WSET(buf, smb_vwv0, finfo->fileid); WSET(buf, smb_vwv1, count); DSET(buf, smb_vwv2, offset); WSET(buf, smb_vwv4, 0); if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0) { smb_unlock_server(server); return error; } returned_count = WVAL(buf, smb_vwv0); smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs); smb_unlock_server(server); if (returned_count != data_len) { printk("smb_proc_read: Warning, returned_count != data_len\n"); printk("smb_proc_read: ret_c=%d, data_len=%d\n", returned_count, data_len); } return data_len; } /* count must be <= 65535. No error number is returned. A result of 0 indicates an error, which has to be investigated by a normal read call. */ int smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data) { char *buf = server->packet; int result; if ((count <= 0) || (count > 65535)) { return -EINVAL; } smb_setup_header_exclusive(server, SMBreadbraw, 8, 0); WSET(buf, smb_vwv0, finfo->fileid); DSET(buf, smb_vwv1, offset); WSET(buf, smb_vwv3, count); WSET(buf, smb_vwv4, 0); DSET(buf, smb_vwv5, 0); result = smb_request_read_raw(server, data, count); smb_unlock_server(server); return result; } int smb_proc_write(struct smb_server *server, struct smb_dirent *finfo, off_t offset, int count, const char *data) { int res = 0; char *buf = server->packet; byte *p; p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3); WSET(buf, smb_vwv0, finfo->fileid); WSET(buf, smb_vwv1, count); DSET(buf, smb_vwv2, offset); WSET(buf, smb_vwv4, 0); *p++ = 1; WSET(p, 0, count); memcpy_fromfs(p+2, data, count); if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0) { res = WVAL(buf, smb_vwv0); } smb_unlock_server(server); return res; } /* count must be <= 65535 */ int smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, const char *data) { char *buf = server->packet; int result; if ((count <= 0) || (count > 65535)) { return -EINVAL; } smb_setup_header_exclusive(server, SMBwritebraw, 11, 0); WSET(buf, smb_vwv0, finfo->fileid); WSET(buf, smb_vwv1, count); WSET(buf, smb_vwv2, 0); /* reserved */ DSET(buf, smb_vwv3, offset); DSET(buf, smb_vwv5, 0); /* timeout */ WSET(buf, smb_vwv7, 1); /* send final result response */ DSET(buf, smb_vwv8, 0); /* reserved */ WSET(buf, smb_vwv10, 0); /* no data in this buf */ WSET(buf, smb_vwv11, 0); /* no data in this buf */ result = smb_request_ok(server, SMBwritebraw, 1, 0); DPRINTK("smb_proc_write_raw: first request returned %d\n", result); if (result < 0) { smb_unlock_server(server); return result; } result = smb_request_write_raw(server, data, count); DPRINTK("smb_proc_write_raw: raw request returned %d\n", result); if (result > 0) { /* We have to do the checks of smb_request_ok here as well */ if (smb_valid_packet(server->packet) != 0) { DPRINTK("not a valid packet!\n"); result = -EIO; } else if (server->rcls != 0) { result = -smb_errno(server->rcls, server->err); } else if (smb_verify(server->packet, SMBwritec,1,0) != 0) { DPRINTK("smb_verify failed\n"); result = -EIO; } } smb_unlock_server(server); return result; } /* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */ static int smb_proc_do_create(struct smb_server *server, const char *path, int len, struct smb_dirent *entry, word command) { int error; char *p; char *buf = server->packet; smb_lock_server(server); retry: p = smb_setup_header(server, command, 3, len + 2); WSET(buf, smb_vwv0, entry->attr); DSET(buf, smb_vwv1, utc2local(entry->ctime)); smb_encode_ascii(p, path, len); if ((error = smb_request_ok(server, command, 1, 0)) < 0) { if (smb_retry(server)) { goto retry; } smb_unlock_server(server); return error; } entry->opened = 1; entry->fileid = WVAL(buf, smb_vwv0); smb_unlock_server(server); smb_proc_close(server, entry->fileid, entry->mtime); return 0; } int smb_proc_create(struct smb_server *server, const char *path, int len, struct smb_dirent *entry) { return smb_proc_do_create(server, path, len, entry, SMBcreate); } int smb_proc_mknew(struct smb_server *server, const char *path, int len, struct smb_dirent *entry) { return smb_proc_do_create(server, path, len, entry, SMBmknew); } int smb_proc_mv(struct smb_server *server, const char *opath, const int olen, const char *npath, const int nlen) { char *p; char *buf = server->packet; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBmv, 1, olen + nlen + 4); WSET(buf, smb_vwv0, 0); p = smb_encode_ascii(p, opath, olen); smb_encode_ascii(p, npath, olen); if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) { if (smb_retry(server)) { goto retry; } } smb_unlock_server(server); return result; } int smb_proc_mkdir(struct smb_server *server, const char *path, const int len) { char *p; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBmkdir, 0, 2 + len); smb_encode_ascii(p, path, len); if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0) { if (smb_retry(server)) { goto retry; } } smb_unlock_server(server); return result; } int smb_proc_rmdir(struct smb_server *server, const char *path, const int len) { char *p; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBrmdir, 0, 2 + len); smb_encode_ascii(p, path, len); if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0) { if (smb_retry(server)) { goto retry; } } smb_unlock_server(server); return result; } int smb_proc_unlink(struct smb_server *server, const char *path, const int len) { char *p; char *buf = server->packet; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBunlink, 1, 2 + len); WSET(buf, smb_vwv0, 0); smb_encode_ascii(p, path, len); if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) { if (smb_retry(server)) { goto retry; } } smb_unlock_server(server); return result; } int smb_proc_trunc(struct smb_server *server, word fid, dword length) { char *p; char *buf = server->packet; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBwrite, 5, 3); WSET(buf, smb_vwv0, fid); WSET(buf, smb_vwv1, 0); DSET(buf, smb_vwv2, length); WSET(buf, smb_vwv4, 0); smb_encode_ascii(p, "", 0); if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) { if (smb_retry(server)) { goto retry; } } smb_unlock_server(server); return result; } static char * smb_decode_dirent(char *p, struct smb_dirent *entry) { p += SMB_STATUS_SIZE; /* reserved (search_status) */ entry->attr = BVAL(p, 0); entry->mtime = entry->atime = entry->ctime = date_dos2unix(WVAL(p, 1), WVAL(p, 3)); entry->size = DVAL(p, 5); memcpy(entry->path, p+9, 13); DDPRINTK("smb_decode_dirent: path = %s\n", entry->path); return p + 22; } /* This routine is used to read in directory entries from the network. Note that it is for short directory name seeks, i.e.: protocol < PROTOCOL_LANMAN2 */ static int smb_proc_readdir_short(struct smb_server *server, struct inode *dir, int fpos, int cache_size, struct smb_dirent *entry) { char *p; char *buf; int error; int result; int i; int first, total_count; struct smb_dirent *current_entry; word bcc; word count; char status[SMB_STATUS_SIZE]; int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE; int dirlen = strlen(SMB_FINFO(dir)->path); char mask[dirlen + 5]; strcpy(mask, SMB_FINFO(dir)->path); strcat(mask, "\\*.*"); DPRINTK("SMB call readdir %d @ %d\n", cache_size, fpos); DPRINTK(" mask = %s\n", mask); buf = server->packet; smb_lock_server(server); retry: first = 1; total_count = 0; current_entry = entry; while (1) { if (first == 1) { p = smb_setup_header(server, SMBsearch, 2, 5 + strlen(mask)); WSET(buf, smb_vwv0, entries_asked); WSET(buf, smb_vwv1, aDIR); p = smb_encode_ascii(p, mask, strlen(mask)); *p ++ = 5; p = smb_encode_word(p, 0); } else { p = smb_setup_header(server, SMBsearch, 2, 5 + SMB_STATUS_SIZE); WSET(buf, smb_vwv0, entries_asked); WSET(buf, smb_vwv1, aDIR); p = smb_encode_ascii(p, "", 0); p = smb_encode_vblock(p, status, SMB_STATUS_SIZE, 0); } if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0) { if ( (server->rcls == ERRDOS) && (server->err == ERRnofiles)) { result = total_count - fpos; goto unlock_return; } else { if (smb_retry(server)) { goto retry; } result = error; goto unlock_return; } } p = SMB_VWV(server->packet); p = smb_decode_word(p, &count); /* vwv[0] = count-returned */ p = smb_decode_word(p, &bcc); first = 0; if (count <= 0) { result = total_count - fpos; goto unlock_return; } if (bcc != count * SMB_DIRINFO_SIZE + 3) { result = -EIO; goto unlock_return; } p += 3; /* Skipping VBLOCK header (5, length lo, length hi). */ /* Read the last entry into the status field. */ memcpy(status, SMB_BUF(server->packet) + 3 + (count - 1) * SMB_DIRINFO_SIZE, SMB_STATUS_SIZE); /* Now we are ready to parse smb directory entries. */ for (i = 0; i < count; i ++) { if (total_count < fpos) { p += SMB_DIRINFO_SIZE; DDPRINTK("smb_proc_readdir: skipped entry.\n"); DDPRINTK(" total_count = %d\n" " i = %d, fpos = %d\n", total_count, i, fpos); } else if (total_count >= fpos + cache_size) { result = total_count - fpos; goto unlock_return; } else { p = smb_decode_dirent(p, current_entry); current_entry->f_pos = total_count; DDPRINTK("smb_proc_readdir: entry->f_pos = " "%d\n", current_entry->f_pos); current_entry += 1; } total_count += 1; } } unlock_return: smb_unlock_server(server); return result; } /* interpret a long filename structure - this is mostly guesses at the moment. The length of the structure is returned. The structure of a long filename depends on the info level. 260 is used by NT and 2 is used by OS/2. */ static char * smb_decode_long_dirent(char *p, struct smb_dirent *finfo, int level) { char *result; if (finfo) { /* I have to set times to 0 here, because I do not have specs about this for all info levels. */ finfo->ctime = finfo->mtime = finfo->atime = 0; } switch (level) { case 1: /* OS/2 understands this */ if (finfo) { DPRINTK("received entry\n"); strcpy(finfo->path,p+27); finfo->len = strlen(finfo->path); finfo->size = DVAL(p,16); finfo->attr = BVAL(p,24); finfo->ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4)); finfo->atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8)); finfo->mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12)); } result = p + 28 + BVAL(p,26); break; case 2: /* this is what OS/2 uses */ if (finfo) { strcpy(finfo->path,p+31); finfo->len = strlen(finfo->path); finfo->size = DVAL(p,16); finfo->attr = BVAL(p,24); #if 0 finfo->atime = make_unix_date2(p+8); finfo->mtime = make_unix_date2(p+12); #endif } result = p + 32 + BVAL(p,30); break; case 260: /* NT uses this, but also accepts 2 */ result = p + WVAL(p,0); if (finfo) { int namelen; p += 4; /* next entry offset */ p += 4; /* fileindex */ /* finfo->ctime = interpret_filetime(p);*/ p += 8; /* finfo->atime = interpret_filetime(p);*/ p += 8; p += 8; /* write time */ /* finfo->mtime = interpret_filetime(p);*/ p += 8; finfo->size = DVAL(p,0); p += 8; p += 8; /* alloc size */ finfo->attr = BVAL(p,0); p += 4; namelen = min(DVAL(p,0), SMB_MAXNAMELEN); p += 4; p += 4; /* EA size */ p += 2; /* short name len? */ p += 24; /* short name? */ strncpy(finfo->path,p,namelen); finfo->len = namelen; } break; default: DPRINTK("Unknown long filename format %d\n",level); result = p + WVAL(p,0); } return result; } int smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos, int cache_size, struct smb_dirent *entry) { int max_matches = 64; /* this should actually be based on the maxxmit */ /* NT uses 260, OS/2 uses 2. Both accept 1. */ int info_level = 1; char *p; char *lastname; int i; int first, total_count; struct smb_dirent *current_entry; char *resp_data; char *resp_param; int resp_data_len = 0; int resp_param_len=0; int attribute = aSYSTEM | aHIDDEN | aDIR; int result; int ff_resume_key = 0; int ff_searchcount=0; int ff_eos=0; int ff_lastname=0; int ff_dir_handle=0; int loop_count = 0; int dirlen = strlen(SMB_FINFO(dir)->path) + 3; char *mask; mask = smb_kmalloc(dirlen, GFP_KERNEL); if (mask == NULL) { printk("smb_proc_readdir_long: Memory allocation failed\n"); return -ENOMEM; } strcpy(mask, SMB_FINFO(dir)->path); strcat(mask, "\\*"); DPRINTK("SMB call lreaddir %d @ %d\n", cache_size, fpos); DPRINTK(" mask = %s\n", mask); resp_param = NULL; resp_data = NULL; smb_lock_server(server); retry: first = 1; total_count = 0; current_entry = entry; while (ff_eos == 0) { int masklen = strlen(mask); unsigned char *outbuf = server->packet; loop_count += 1; if (loop_count > 200) { printk("smb_proc_readdir_long: " "Looping in FIND_NEXT??\n"); break; } smb_setup_header(server, SMBtrans2, 15, 5 + 12 + masklen + 1); WSET(outbuf,smb_tpscnt,12 + masklen +1); WSET(outbuf,smb_tdscnt,0); WSET(outbuf,smb_mprcnt,10); WSET(outbuf,smb_mdrcnt,TRANS2_MAX_TRANSFER); WSET(outbuf,smb_msrcnt,0); WSET(outbuf,smb_flags,0); DSET(outbuf,smb_timeout,0); WSET(outbuf,smb_pscnt,WVAL(outbuf,smb_tpscnt)); WSET(outbuf,smb_psoff,((SMB_BUF(outbuf)+3) - outbuf)-4); WSET(outbuf,smb_dscnt,0); WSET(outbuf,smb_dsoff,0); WSET(outbuf,smb_suwcnt,1); WSET(outbuf,smb_setup0, first == 1 ? TRANSACT2_FINDFIRST : TRANSACT2_FINDNEXT); p = SMB_BUF(outbuf); *p++=0; /* put in a null smb_name */ *p++='D'; *p++ = ' '; /* this was added because OS/2 does it */ if (first != 0) { WSET(p,0,attribute); /* attribute */ WSET(p,2,max_matches); /* max count */ WSET(p,4,8+4+2); /* resume required + close on end + continue */ WSET(p,6,info_level); DSET(p,8,0); p += 12; strncpy(p, mask, masklen); p += masklen; *p++ = 0; *p++ = 0; } else { DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n", ff_dir_handle,ff_resume_key,ff_lastname,mask); WSET(p,0,ff_dir_handle); WSET(p,2,max_matches); /* max count */ WSET(p,4,info_level); DSET(p,6,ff_resume_key); /* ff_resume_key */ WSET(p,10,8+4+2); /* resume required + close on end + continue */ p += 12; strncpy(p, mask, masklen); p += masklen; *p++ = 0; *p++ = 0; } result = smb_trans2_request(server, &resp_data_len,&resp_param_len, &resp_data,&resp_param); if (result < 0) { if (smb_retry(server)) { goto retry; } DPRINTK("smb_proc_readdir_long: " "got error from trans2_request\n"); break; } if (server->rcls != 0) { result = -EIO; break; } /* parse out some important return info */ p = resp_param; if (first != 0) { ff_dir_handle = WVAL(p,0); ff_searchcount = WVAL(p,2); ff_eos = WVAL(p,4); ff_lastname = WVAL(p,8); } else { ff_searchcount = WVAL(p,0); ff_eos = WVAL(p,2); ff_lastname = WVAL(p,6); } if (ff_searchcount == 0) break; /* point to the data bytes */ p = resp_data; /* we might need the lastname for continuations */ lastname = ""; if (ff_lastname > 0) { switch(info_level) { case 260: lastname = p + ff_lastname + 94; ff_resume_key = 0; break; case 1: lastname = p + ff_lastname + 1; ff_resume_key = 0; break; } } /* Increase size of mask, if it is too small */ i = strlen(lastname) + 1; if (i > dirlen) { smb_kfree_s(mask, 0); dirlen = i; mask = smb_kmalloc(dirlen, GFP_KERNEL); if (mask == NULL) { printk("smb_proc_readdir_long: Memory allocation failed\n"); result = -ENOMEM; break; } strcpy(mask, lastname); } /* Now we are ready to parse smb directory entries. */ for (i = 0; i < ff_searchcount; i ++) { if (total_count < fpos) { p = smb_decode_long_dirent(p, NULL, info_level); DPRINTK("smb_proc_readdir: skipped entry.\n"); DDPRINTK(" total_count = %d\n" " i = %d, fpos = %d\n", total_count, i, fpos); } else if (total_count >= fpos + cache_size) { goto finished; } else { p = smb_decode_long_dirent(p, current_entry, info_level); current_entry->f_pos = total_count; DDPRINTK("smb_proc_readdir: entry->f_pos = " "%lu\n", current_entry->f_pos); current_entry += 1; } total_count += 1; } if (resp_data != NULL) { smb_kfree_s(resp_data, 0); resp_data = NULL; } if (resp_param != NULL) { smb_kfree_s(resp_param, 0); resp_param = NULL; } DPRINTK("received %d entries (eos=%d resume=%d)\n", ff_searchcount,ff_eos,ff_resume_key); first = 0; } finished: if (mask != NULL) smb_kfree_s(mask, 0); if (resp_data != NULL) { smb_kfree_s(resp_data, 0); resp_data = NULL; } if (resp_param != NULL) { smb_kfree_s(resp_param, 0); resp_param = NULL; } smb_unlock_server(server); return total_count - fpos; } int smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos, int cache_size, struct smb_dirent *entry) { if (server->protocol >= PROTOCOL_LANMAN2) return smb_proc_readdir_long(server, dir, fpos, cache_size, entry); else return smb_proc_readdir_short(server, dir, fpos, cache_size, entry); } int smb_proc_getattr_core(struct smb_server *server, const char *path, int len, struct smb_dirent *entry) { int result; char *p; char *buf = server->packet; smb_lock_server(server); DDPRINTK("smb_proc_getattr: %s\n", path); retry: p = smb_setup_header(server, SMBgetatr, 0, 2 + len); smb_encode_ascii(p, path, len); if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) { if (smb_retry(server)) { goto retry; } smb_unlock_server(server); return result; } entry->attr = WVAL(buf, smb_vwv0); entry->ctime = entry->atime = /* The server only tells us 1 time */ entry->mtime = local2utc(DVAL(buf, smb_vwv1)); entry->size = DVAL(buf, smb_vwv3); smb_unlock_server(server); return 0; } /* smb_proc_getattrE: entry->fid must be valid */ int smb_proc_getattrE(struct smb_server *server, struct smb_dirent *entry) { char* buf = server->packet; int result; smb_setup_header_exclusive(server, SMBgetattrE, 1, 0); WSET(buf, smb_vwv0, entry->fileid); if ((result = smb_request_ok(server, SMBgetattrE, 11, 0)) != 0) { smb_unlock_server(server); return result; } entry->ctime = date_dos2unix(WVAL(buf, smb_vwv1), WVAL(buf, smb_vwv0)); entry->atime = date_dos2unix(WVAL(buf, smb_vwv3), WVAL(buf, smb_vwv2)); entry->mtime = date_dos2unix(WVAL(buf, smb_vwv5), WVAL(buf, smb_vwv4)); entry->size = DVAL(buf, smb_vwv6); entry->attr = WVAL(buf, smb_vwv10); smb_unlock_server(server); return 0; } int smb_proc_getattr(struct smb_server *server, const char *path, int len, struct smb_dirent *entry) { if (server->protocol >= PROTOCOL_LANMAN1) { int result = 0; struct smb_dirent temp_entry; memset(&temp_entry, 0, sizeof(temp_entry)); if ((result=smb_proc_open(server,path,len, &temp_entry)) < 0) { /* We cannot open directories, so we try to use the core variant */ return smb_proc_getattr_core(server,path,len,entry); } if ((result=smb_proc_getattrE(server, &temp_entry)) >= 0) { entry->attr = temp_entry.attr; entry->atime = temp_entry.atime; entry->mtime = temp_entry.mtime; entry->ctime = temp_entry.ctime; entry->size = temp_entry.size; } smb_proc_close(server, temp_entry.fileid, temp_entry.mtime); return result; } else { return smb_proc_getattr_core(server, path, len, entry); } } /* In core protocol, there is only 1 time to be set, we use entry->mtime, to make touch work. */ int smb_proc_setattr_core(struct smb_server *server, const char *path, int len, struct smb_dirent *new_finfo) { char *p; char *buf = server->packet; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBsetatr, 8, 4 + len); WSET(buf, smb_vwv0, new_finfo->attr); DSET(buf, smb_vwv1, utc2local(new_finfo->mtime)); p = smb_encode_ascii(p, path, len); p = smb_encode_ascii(p, "", 0); if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0) { if (smb_retry(server)) { goto retry; } } smb_unlock_server(server); return result; } /* smb_proc_setattrE: we do not retry here, because we rely on fid, which would not be valid after a retry. */ int smb_proc_setattrE(struct smb_server *server, word fid, struct smb_dirent *new_entry) { char *buf = server->packet; word date, time; smb_setup_header_exclusive(server, SMBsetattrE, 7, 0); WSET(buf, smb_vwv0, fid); date_unix2dos(new_entry->ctime, &time, &date); WSET(buf, smb_vwv1, date); WSET(buf, smb_vwv2, time); date_unix2dos(new_entry->atime, &time, &date); WSET(buf, smb_vwv3, date); WSET(buf, smb_vwv4, time); date_unix2dos(new_entry->mtime, &time, &date); WSET(buf, smb_vwv5, date); WSET(buf, smb_vwv6, time); return smb_request_ok_unlock(server, SMBsetattrE, 0, 0); } /* smb_proc_setattr: for protocol >= LANMAN1 we expect the file to be opened for writing. */ int smb_proc_setattr(struct smb_server *server, struct inode *inode, struct smb_dirent *new_finfo) { struct smb_dirent *finfo = SMB_FINFO(inode); int result; if (server->protocol >= PROTOCOL_LANMAN1) { if ((result = smb_make_open(inode, O_RDWR)) < 0) return result; return smb_proc_setattrE(server, finfo->fileid, new_finfo); } else { return smb_proc_setattr_core(server, finfo->path, finfo->len, new_finfo); } } int smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr) { int error; char *p; struct smb_server *server = &(SMB_SBP(super)->s_server); smb_lock_server(server); retry: smb_setup_header(server, SMBdskattr, 0, 0); if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) { if (smb_retry(server)) { goto retry; } smb_unlock_server(server); return error; } p = SMB_VWV(server->packet); p = smb_decode_word(p, &attr->total); p = smb_decode_word(p, &attr->allocblocks); p = smb_decode_word(p, &attr->blocksize); p = smb_decode_word(p, &attr->free); smb_unlock_server(server); return 0; } /*****************************************************************************/ /* */ /* Mount/umount operations. */ /* */ /*****************************************************************************/ struct smb_prots { enum smb_protocol prot; const char *name; }; /* smb_proc_reconnect: We expect the server to be locked, so that you can call the routine from within smb_retry. The socket must be created, like after a user-level socket()-call. It may not be connected. */ int smb_proc_reconnect(struct smb_server *server) { struct smb_prots prots[] = { { PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"}, { PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"}, #ifdef LANMAN1 { PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"}, { PROTOCOL_LANMAN1,"LANMAN1.0"}, #endif #ifdef LANMAN2 { PROTOCOL_LANMAN2,"LM1.2X002"}, #endif #ifdef NT1 { PROTOCOL_NT1,"NT LM 0.12"}, { PROTOCOL_NT1,"NT LANMAN 1.0"}, #endif {-1, NULL} }; char dev[] = "A:"; int i, plength; int max_xmit = 1024; /* Space needed for first request. */ int given_max_xmit = server->m.max_xmit; int result; word any_word; byte *p; if(server->max_recv <= 0){ server->max_recv = given_max_xmit > 8000 ? given_max_xmit : 8000; } if ((result = smb_connect(server)) < 0) { DPRINTK("smb_proc_reconnect: could not smb_connect\n"); goto fail; } /* Here we assume that the connection is valid */ server->state = CONN_VALID; if (server->packet != NULL) { smb_kfree_s(server->packet, server->max_recv); } server->packet = smb_kmalloc(server->max_recv, GFP_KERNEL); if (server->packet == NULL) { printk("smb_proc_connect: No memory! Bailing out.\n"); result = -ENOMEM; goto fail; } server->max_xmit = max_xmit; /* * Start with an RFC1002 session request packet. */ p = server->packet + 4; p = smb_name_mangle(p, server->m.server_name); p = smb_name_mangle(p, server->m.client_name); smb_encode_smb_length(server->packet, (void *)p - (void *)(server->packet)); server->packet[0] = 0x81; /* SESSION REQUEST */ if (smb_catch_keepalive(server) < 0) { printk("smb_proc_connect: could not catch_keepalives\n"); } if ((result = smb_request(server)) < 0) { printk("smb_proc_connect: Failed to send SESSION REQUEST.\n"); smb_dont_catch_keepalive(server); goto fail; } if (server->packet[0] != 0x82) { printk("smb_proc_connect: Did not receive positive response " "(err = %x)\n", server->packet[0]); smb_dont_catch_keepalive(server); if(debug_mode & DEBUG_PROC_NOISY){ smb_dump_packet(server->packet); } result = -EIO; goto fail; } DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n"); /* Now we are ready to send a SMB Negotiate Protocol packet. */ memset(server->packet, 0, SMB_HEADER_LEN); plength = 0; for (i = 0; prots[i].name != NULL; i++) { plength += strlen(prots[i].name) + 2; } smb_setup_header(server, SMBnegprot, 0, plength); p = SMB_BUF(server->packet); for (i = 0; prots[i].name != NULL; i++) { p = smb_encode_dialect(p,prots[i].name, strlen(prots[i].name)); } if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0) { printk("smb_proc_connect: Failure requesting SMBnegprot\n"); smb_dont_catch_keepalive(server); goto fail; } else { DDPRINTK("smb_proc_connect: Request SMBnegprot.."); } DDPRINTK("Verified!\n"); p = SMB_VWV(server->packet); p = smb_decode_word(p, &any_word); i = any_word; server->protocol = prots[i].prot; DPRINTK("smb_proc_connect: Server wants %s protocol.\n", prots[i].name); if (server->protocol > PROTOCOL_LANMAN1) { word passlen = strlen(server->m.password); word userlen = strlen(server->m.username); DPRINTK("smb_proc_connect: password = %s\n", server->m.password); DPRINTK("smb_proc_connect: usernam = %s\n", server->m.username); DPRINTK("smb_proc_connect: blkmode = %d\n", WVAL(server->packet, smb_vwv5)); if (server->protocol >= PROTOCOL_NT1) { server->maxxmt = DVAL(server->packet,smb_vwv3+1); server->maxmux = WVAL(server->packet, smb_vwv1+1); server->maxvcs = WVAL(server->packet, smb_vwv2+1); server->blkmode= DVAL(server->packet, smb_vwv9+1); server->sesskey= DVAL(server->packet, smb_vwv7+1); } else { server->maxxmt = WVAL(server->packet, smb_vwv2); server->maxmux = WVAL(server->packet, smb_vwv3); server->maxvcs = WVAL(server->packet, smb_vwv4); server->blkmode= WVAL(server->packet, smb_vwv5); server->sesskey= DVAL(server->packet, smb_vwv6); } if (server->protocol >= PROTOCOL_NT1) { char *workgroup = "WORKGROUP"; char *OS_id = "Unix"; char *client_id = "ksmbfs"; smb_setup_header(server, SMBsesssetupX, 13, 5 + userlen + passlen + strlen(workgroup) + strlen(OS_id) + strlen(client_id)); WSET(server->packet, smb_vwv0, 0x00ff); WSET(server->packet, smb_vwv1, 0); WSET(server->packet, smb_vwv2, given_max_xmit); WSET(server->packet, smb_vwv3, 2); WSET(server->packet, smb_vwv4, server->pid); DSET(server->packet, smb_vwv5, server->sesskey); WSET(server->packet, smb_vwv7, passlen + 1); WSET(server->packet, smb_vwv8, 0); WSET(server->packet, smb_vwv9, 0); p = SMB_BUF(server->packet); strcpy(p, server->m.password); p += passlen + 1; strcpy(p, server->m.username); p += userlen + 1; strcpy(p, workgroup); p += strlen(p) + 1; strcpy(p, OS_id); p += strlen(p) + 1; strcpy(p, client_id); } else { smb_setup_header(server, SMBsesssetupX, 10, 2 + userlen + passlen); WSET(server->packet, smb_vwv0, 0x00ff); WSET(server->packet, smb_vwv1, 0); WSET(server->packet, smb_vwv2, given_max_xmit); WSET(server->packet, smb_vwv3, 2); WSET(server->packet, smb_vwv4, server->pid); DSET(server->packet, smb_vwv5, server->sesskey); WSET(server->packet, smb_vwv7, passlen + 1); WSET(server->packet, smb_vwv8, 0); WSET(server->packet, smb_vwv9, 0); p = SMB_BUF(server->packet); strcpy(p, server->m.password); p += passlen + 1; strcpy(p, server->m.username); } if ((result = smb_request_ok(server,SMBsesssetupX,3,0)) < 0) { DPRINTK("smb_proc_connect: SMBsessetupX failed\n"); smb_dont_catch_keepalive(server); goto fail; } smb_decode_word(server->packet+32, &(server->server_uid)); } else { server->maxxmt = 0; server->maxmux = 0; server->maxvcs = 0; server->blkmode = 0; server->sesskey = 0; } /* Fine! We have a connection, send a tcon message. */ smb_setup_header(server, SMBtcon, 0, 6 + strlen(server->m.service) + strlen(server->m.password) + strlen(dev)); p = SMB_BUF(server->packet); p = smb_encode_ascii(p, server->m.service, strlen(server->m.service)); p = smb_encode_ascii(p,server->m.password, strlen(server->m.password)); p = smb_encode_ascii(p, dev, strlen(dev)); if ((result = smb_request_ok(server, SMBtcon, 2, 0)) < 0) { DPRINTK("smb_proc_connect: SMBtcon not verified.\n"); smb_dont_catch_keepalive(server); goto fail; } DDPRINTK("OK! Managed to set up SMBtcon!\n"); p = SMB_VWV(server->packet); p = smb_decode_word(p, &server->max_xmit); if (server->max_xmit > given_max_xmit) server->max_xmit = given_max_xmit; p = smb_decode_word(p, &server->tid); /* Ok, everything is fine. max_xmit does not include */ /* the TCP-SMB header of 4 bytes. */ server->max_xmit += 4; DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid); # if 0 /* CS: don't resize buffer to max_xmit, leave it at max_recv */ /* Now make a new packet with the correct size. */ smb_kfree_s(server->packet, max_xmit); server->packet = smb_kmalloc(server->max_xmit, GFP_KERNEL); if (server->packet == NULL) { printk("smb_proc_connect: No memory left in end of " "connection phase :-(\n"); smb_dont_catch_keepalive(server); goto fail; } #endif DPRINTK("smb_proc_connect: Normal exit\n"); return 0; fail: server->state = CONN_INVALID; return result; } /* smb_proc_reconnect: server->packet is allocated with server->max_xmit bytes if and only if we return >= 0 */ int smb_proc_connect(struct smb_server *server) { int result; smb_lock_server(server); result = smb_proc_reconnect(server); if ((result < 0) && (server->packet != NULL)) { smb_kfree_s(server->packet, server->max_recv); server->packet = NULL; } smb_unlock_server(server); return result; } int smb_proc_disconnect(struct smb_server *server) { smb_setup_header_exclusive(server, SMBtdis, 0, 0); return smb_request_ok_unlock(server, SMBtdis, 0, 0); } /* error code stuff - put together by Merik Karman merik@blackadder.dsh.oz.au */ typedef struct { char *name; int code; char *message; } err_code_struct; /* Dos Error Messages */ err_code_struct dos_msgs[] = { { "ERRbadfunc",1,"Invalid function."}, { "ERRbadfile",2,"File not found."}, { "ERRbadpath",3,"Directory invalid."}, { "ERRnofids",4,"No file descriptors available"}, { "ERRnoaccess",5,"Access denied."}, { "ERRbadfid",6,"Invalid file handle."}, { "ERRbadmcb",7,"Memory control blocks destroyed."}, { "ERRnomem",8,"Insufficient server memory to perform the requested function."}, { "ERRbadmem",9,"Invalid memory block address."}, { "ERRbadenv",10,"Invalid environment."}, { "ERRbadformat",11,"Invalid format."}, { "ERRbadaccess",12,"Invalid open mode."}, { "ERRbaddata",13,"Invalid data."}, { "ERR",14,"reserved."}, { "ERRbaddrive",15,"Invalid drive specified."}, { "ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."}, { "ERRdiffdevice",17,"Not same device."}, { "ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."}, { "ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."}, { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, { "ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."}, { "ERRbadpipe",230,"Pipe invalid."}, { "ERRpipebusy",231,"All instances of the requested pipe are busy."}, { "ERRpipeclosing",232,"Pipe close in progress."}, { "ERRnotconnected",233,"No process on other end of pipe."}, { "ERRmoredata",234,"There is more data to be returned."}, { NULL,-1,NULL}}; /* Server Error Messages */ err_code_struct server_msgs[] = { { "ERRerror",1,"Non-specific error code."}, { "ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, { "ERRbadtype",3,"reserved."}, { "ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, { "ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."}, { "ERRinvnetname",6,"Invalid network name in tree connect."}, { "ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, { "ERRqfull",49,"Print queue full (files) -- returned by open print file."}, { "ERRqtoobig",50,"Print queue full -- no space."}, { "ERRqeof",51,"EOF on print queue dump."}, { "ERRinvpfid",52,"Invalid print file FID."}, { "ERRsmbcmd",64,"The server did not recognize the command received."}, { "ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."}, { "ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."}, { "ERRreserved",68,"reserved."}, { "ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, { "ERRreserved",70,"reserved."}, { "ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."}, { "ERRpaused",81,"Server is paused."}, { "ERRmsgoff",82,"Not receiving messages."}, { "ERRnoroom",83,"No room to buffer message."}, { "ERRrmuns",87,"Too many remote user names."}, { "ERRtimeout",88,"Operation timed out."}, { "ERRnoresource",89,"No resources currently available for request."}, { "ERRtoomanyuids",90,"Too many UIDs active on this session."}, { "ERRbaduid",91,"The UID is not known as a valid ID on this session."}, { "ERRusempx",250,"Temp unable to support Raw, use MPX mode."}, { "ERRusestd",251,"Temp unable to support Raw, use standard read/write."}, { "ERRcontmpx",252,"Continue in MPX mode."}, { "ERRreserved",253,"reserved."}, { "ERRreserved",254,"reserved."}, { "ERRnosupport",0xFFFF,"Function not supported."}, { NULL,-1,NULL}}; /* Hard Error Messages */ err_code_struct hard_msgs[] = { { "ERRnowrite",19,"Attempt to write on write-protected diskette."}, { "ERRbadunit",20,"Unknown unit."}, { "ERRnotready",21,"Drive not ready."}, { "ERRbadcmd",22,"Unknown command."}, { "ERRdata",23,"Data error (CRC)."}, { "ERRbadreq",24,"Bad request structure length."}, { "ERRseek",25 ,"Seek error."}, { "ERRbadmedia",26,"Unknown media type."}, { "ERRbadsector",27,"Sector not found."}, { "ERRnopaper",28,"Printer out of paper."}, { "ERRwrite",29,"Write fault."}, { "ERRread",30,"Read fault."}, { "ERRgeneral",31,"General failure."}, { "ERRbadshare",32,"A open conflicts with an existing open."}, { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, { "ERRwrongdisk",34,"The wrong disk was found in a drive."}, { "ERRFCBUnavail",35,"No FCBs are available to process request."}, { "ERRsharebufexc",36,"A sharing buffer has been exceeded."}, { NULL,-1,NULL} }; struct { int code; char *class; err_code_struct *err_msgs; } err_classes[] = { { 0,"SUCCESS",NULL}, { 0x01,"ERRDOS",dos_msgs}, { 0x02,"ERRSRV",server_msgs}, { 0x03,"ERRHRD",hard_msgs}, { 0x04,"ERRXOS",NULL}, { 0xE1,"ERRRMX1",NULL}, { 0xE2,"ERRRMX2",NULL}, { 0xE3,"ERRRMX3",NULL}, { 0xFF,"ERRCMD",NULL}, { -1,NULL,NULL} }; void smb_printerr(int class, int num) { int i,j; err_code_struct *err; for (i=0; err_classes[i].class; i++) { if (err_classes[i].code != class) continue; if (!err_classes[i].err_msgs) { printk("%s - %d", err_classes[i].class, num); return; } err = err_classes[i].err_msgs; for (j=0; err[j].name; j++) { if (num != err[j].code) continue; printk("%s - %s (%s)", err_classes[i].class, err[j].name, err[j].message); return; } } printk("Unknown error - (%d,%d)", class, num); return; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.