diff --git a/documentation/history.doc b/documentation/history.doc index d046abc..d8851b1 100644 --- a/documentation/history.doc +++ b/documentation/history.doc @@ -1590,7 +1590,7 @@ smbfs 1.133 (20.5.2018) server would be reported as being both protected from writing and from deletion. On the Amiga side, protecting a file from deletion only changed the file on the server to "read only" - if the protection fron writing was in effect, too. Now we have + if the protection from writing was in effect, too. Now we have a functionally identical mapping which hinges only on the delete protection. @@ -1601,3 +1601,51 @@ smbfs 1.134 (20.5.2018) parameter or data response information, but the code still updated the respective pointer and length information passed as pointers, even if these pointers were NULL... + + +smbfs 1.135 (21.5.2018) + +- Creating a new file failed to close it after having just created it. + Because file IDs are 16 bit integers, at some point the SMB server + would have run out of IDs. It was reported to me that one SMB server + may have refused to assign any further file IDs after 500 files were + created. + +- When creating a file using SMB_COM_CREATE, the read-only, archived and + system attributes are no longer set. We just create a "normal" file. + +- If the connection to the server is no longer reliable, it will + actually get closed now, to be reopened later (maybe). + +- Added a check to verify that prior to deleting a file or directory, + all currently active file handles referring to the same file can + be closed. This also goes for renaming files. + +- Added a safety check to make sure that a file/directory which has + already been opened is not opened again. Note that this should not + strictly be necessary, but the current smbfs "architecture" identifies + files and directories internally through their fully qualified + path names rather than their file IDs. + +- During session setup smbfs now properly reports that it supports + raw read/write mode, large readx/writex mode, the TRANS2_FIND_FIRST2 + and TRANS2_FIND_NEXT2 commands and 64 bit file offsets (sort of). + +- The length limits of the server and client names (16 characters) are + now only enforced if NetBIOS session setup is used (which is disabled + by default). The length of the workgroup/domain name is not checked + any more (maximum length was 15 characters). Note that length limits + may still exist which the server enforces and complains about. + +- When creating new files the sharing permissions now include deletion, + too, just in case you need to remove debris after smbfs had to be + shut down, or your Amiga needed to be restarted. + +- The "pure" file protection bit is no longer associated with the + "system" attribute of a file or directory. This leaves only the + "read-only" and "archived" attributes for manipulation. + +- Connecting and reconnecting to the server now obeys the same timeout + restrictions as the read and write operations. Should the server + communication fail because of a timeout, reestablishing a connection + to the server should no longer hang indefinitely. diff --git a/source_code/include/smb/smb_fs_sb.h b/source_code/include/smb/smb_fs_sb.h index d1ed00e..d38c924 100644 --- a/source_code/include/smb/smb_fs_sb.h +++ b/source_code/include/smb/smb_fs_sb.h @@ -73,26 +73,4 @@ struct smb_server char * native_os; }; -#define NEGOTIATE_USER_SECURITY 0x01 /* If set, the server supports - only user level access control. - If clear, the server supports - only share level access - control. */ - -#define NEGOTIATE_ENCRYPT_PASSWORDS 0x02 /* If set, the server supports - challenge/response - authentication. If clear, - the server supports only - plaintext password - authentication. */ - -#define CAP_RAW_MODE 0x00000001 /* The server supports SMB_COM_WRITE_RAW - and SMB_COM_READ_RAW requests. */ - -#define CAP_LARGE_READX 0x00004000 /* The server permits SMB_COM_READ_ANDX - to read up to 65535 bytes. */ - -#define CAP_LARGE_WRITEX 0x00008000 /* The server permits SMB_COM_WRITE_ANDX - to write up to 65535 bytes. */ - #endif diff --git a/source_code/include/smb/smbno.h b/source_code/include/smb/smbno.h index 47eb323..a8e390e 100644 --- a/source_code/include/smb/smbno.h +++ b/source_code/include/smb/smbno.h @@ -306,6 +306,37 @@ #define ATTR_NO_BUFFERING 0x20000000 #define ATTR_WRITE_THROUGH 0x80000000 +/* These are used by SMBsesssetupX */ +#define NEGOTIATE_USER_SECURITY 0x01 /* If set, the server supports + only user level access control. + If clear, the server supports + only share level access + control. */ + +#define NEGOTIATE_ENCRYPT_PASSWORDS 0x02 /* If set, the server supports + challenge/response + authentication. If clear, + the server supports only + plaintext password + authentication. */ + + +#define CAP_RAW_MODE 0x00000001 /* The server supports SMB_COM_WRITE_RAW + * and SMB_COM_READ_RAW requests. + */ + +#define CAP_LARGE_READX 0x00004000 /* The server permits SMB_COM_READ_ANDX + * to read up to 65535 bytes. + */ + +#define CAP_LARGE_WRITEX 0x00008000 /* The server permits SMB_COM_WRITE_ANDX + * to write up to 65535 bytes. + */ + +#define CAP_LARGE_FILES 0x00000008 +#define CAP_NT_FIND 0x00000200 +#define CAP_UNIX 0x00800000 + /* These are used by SMBntcreateX */ #define FILE_READ_DATA 0x00000001 #define FILE_WRITE_DATA 0x00000002 @@ -317,7 +348,7 @@ #define FILE_SHARE_READ 0x00000001 #define FILE_SHARE_WRITE 0x00000002 - +#define FILE_SHARE_DELETE 0x00000004 #define FILE_NON_DIRECTORY_FILE 0x00000040 #define FILE_RANDOM_ACCESS 0x00000800 diff --git a/source_code/main.c b/source_code/main.c index f629eee..7caf40e 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -26,8 +26,8 @@ * copy "amiga:Public/Documents/Amiga Files/Shared/dir/Windows-Export/LP2NRFP.h" ram: * smbfs.debug user=guest volume=sicherung //192.168.1.76/sicherung-smb * smbfs maxtransmit=16600 debuglevel=2 dumpsmb dumpsmblevel=2 domain=workgroup user=olsen password=... volume=olsen //felix/olsen - * Samba 4.6.7: smbfs debuglevel=2 dumpsmb dumpsmblevel=2 volume=ubuntu-test //ubuntu-17-olaf/test - * Samba 4.7.6: smbfs debuglevel=2 dumpsmb dumpsmblevel=2 volume=ubuntu-test //ubuntu-18-olaf/test + * Samba 4.6.7: smbfs debuglevel=2 dumpsmb dumpsmblevel=1 volume=ubuntu-test //ubuntu-17-olaf/test + * Samba 4.7.6: smbfs debuglevel=2 dumpsmb dumpsmblevel=1 volume=ubuntu-test //ubuntu-18-olaf/test * Samba 3.0.25: smbfs debuglevel=2 dumpsmb dumpsmblevel=1 user=olsen password=... volume=olsen //192.168.1.118/olsen */ @@ -4086,21 +4086,23 @@ Action_SetProtect( if((mask & FIBF_DELETE) != 0) { - SHOWMSG("write protection enabled"); - st.is_wp = TRUE; + SHOWMSG("write/delete protection enabled"); + st.is_read_only = TRUE; } else { - SHOWMSG("write protection disabled"); + SHOWMSG("write/delete protection disabled"); } /* Careful: the 'archive' attribute has exactly the opposite * meaning in the Amiga and the SMB worlds. */ - st.is_archive = ((mask & FIBF_ARCHIVE) == 0); + st.is_changed_since_last_archive = ((mask & FIBF_ARCHIVE) == 0); /* The 'system' attribute is associated with the 'pure' bit for now. */ + /* st.is_system = ((mask & FIBF_PURE) != 0); + */ if(smba_setattr(file,&st,NULL,&error) < 0) { @@ -4564,17 +4566,19 @@ Action_ExamineObject( fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE| FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE; - if(st.is_wp) + if(st.is_read_only) fib->fib_Protection ^= (FIBF_OTR_DELETE|FIBF_GRP_DELETE|FIBF_DELETE); /* Careful: the 'archive' attribute has exactly the opposite * meaning in the Amiga and the SMB worlds. */ - if(NOT st.is_archive) + if(NOT st.is_changed_since_last_archive) fib->fib_Protection |= FIBF_ARCHIVE; + /* if(st.is_system) fib->fib_Protection |= FIBF_PURE; + */ if(NOT st.is_dir) fib->fib_DiskKey = -1; @@ -4647,8 +4651,8 @@ dir_scan_callback_func_exnext( ENTER(); D((" '%s'",name)); - D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld", - st->is_dir,st->is_wp,st->is_hidden,st->size)); + D((" is_dir=%ld is_read_only=%ld is_hidden=%ld size=%ld", + st->is_dir,st->is_read_only,st->is_hidden,st->size)); D((" nextpos=%ld eof=%ld",nextpos,eof)); /* Skip file and drawer names that we wouldn't be @@ -4697,17 +4701,19 @@ dir_scan_callback_func_exnext( fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE| FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE; - if(st->is_wp) - fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE); + if(st->is_read_only) + fib->fib_Protection ^= (FIBF_OTR_DELETE|FIBF_GRP_DELETE|FIBF_DELETE); /* Careful: the 'archive' attribute has exactly the opposite * meaning in the Amiga and the SMB worlds. */ - if(NOT st->is_archive) + if(NOT st->is_changed_since_last_archive) fib->fib_Protection |= FIBF_ARCHIVE; + /* if(st->is_system) fib->fib_Protection |= FIBF_PURE; + */ /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */ seconds = (st->mtime == 0 ? st->ctime : st->mtime) - UNIX_TIME_OFFSET - GetTimeZoneDelta(); @@ -4840,8 +4846,8 @@ dir_scan_callback_func_exall( ENTER(); D((" '%s'",name)); - D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld", - st->is_dir,st->is_wp,st->is_hidden,st->size)); + D((" is_dir=%ld is_read_only=%ld is_hidden=%ld size=%ld", + st->is_dir,st->is_read_only,st->is_hidden,st->size)); D((" nextpos=%ld eof=%ld",nextpos,eof)); /* If necessary, translate the name of the file first, so that we @@ -4928,17 +4934,19 @@ dir_scan_callback_func_exall( ed->ed_Prot = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE| FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE; - if(st->is_wp) - ed->ed_Prot ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE); + if(st->is_read_only) + ed->ed_Prot ^= (FIBF_OTR_DELETE|FIBF_GRP_DELETE|FIBF_DELETE); /* Careful: the 'archive' attribute has exactly the opposite * meaning in the Amiga and the SMB worlds. */ - if(NOT st->is_archive) + if(NOT st->is_changed_since_last_archive) ed->ed_Prot |= FIBF_ARCHIVE; + /* if(st->is_system) ed->ed_Prot |= FIBF_PURE; + */ } if(type >= ED_DATE) @@ -5937,17 +5945,19 @@ Action_ExamineFH( fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE| FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE; - if(st.is_wp) - fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE); + if(st.is_read_only) + fib->fib_Protection ^= (FIBF_OTR_DELETE|FIBF_GRP_DELETE|FIBF_DELETE); /* Careful: the 'archive' attribute has exactly the opposite * meaning in the Amiga and the SMB worlds. */ - if(NOT st.is_archive) + if(NOT st.is_changed_since_last_archive) fib->fib_Protection |= FIBF_ARCHIVE; + /* if(st.is_system) fib->fib_Protection |= FIBF_PURE; + */ /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */ seconds = (st.mtime == 0 ? st.ctime : st.mtime) - UNIX_TIME_OFFSET - GetTimeZoneDelta(); diff --git a/source_code/proc.c b/source_code/proc.c index 7d3ff42..4515126 100644 --- a/source_code/proc.c +++ b/source_code/proc.c @@ -841,15 +841,16 @@ smb_request_ok (struct smb_server *s, int command, int wct, int bcc, int * error } /* 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. */ + * indicated an error. If the error was indicated because the + * connection was killed, we try to reconnect. If smb_retry returns FALSE, + * the error was indicated for another reason, so a retry would not be + * of any use. + */ static int smb_retry (struct smb_server *server) { + int success = FALSE; int ignored_error; - int result = 0; if (server->state == CONN_VALID) goto out; @@ -868,11 +869,11 @@ smb_retry (struct smb_server *server) } server->state = CONN_VALID; - result = 1; + success = TRUE; out: - return result; + return success; } /* smb_setup_header: We completely set up the packet. You only have to @@ -990,12 +991,6 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri SHOWMSG("we'll try SMB_COM_NT_CREATE_ANDX"); - if((*pathname) == '\\') - { - pathname++; - len--; - } - ASSERT( smb_payload_size(server, 24, len+1) >= 0 ); if(writable) @@ -1013,7 +1008,12 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri // desired_access |= FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES; - share_access = FILE_SHARE_READ|FILE_SHARE_WRITE; + /* Allows others to read, write and delete the file just created. + * This may be useful if smbfs hangs or you need to restart your + * System and you need to clean up after the file you just + * created. + */ + share_access = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE; if(writable && truncate_file) { @@ -1091,7 +1091,7 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri entry->size = end_of_file_low; - entry->opened = 1; + entry->opened = TRUE; goto out; } @@ -1148,7 +1148,7 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri entry->attr = WVAL (buf, smb_vwv1); entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc (DVAL (buf, smb_vwv2)); entry->size = DVAL (buf, smb_vwv4); - entry->opened = 1; + entry->opened = TRUE; out: @@ -1659,7 +1659,7 @@ smb_proc_create (struct smb_server *server, const char *path, int len, struct sm goto out; } - entry->opened = 1; + entry->opened = TRUE; entry->fileid = WVAL (buf, smb_vwv0); smb_proc_close (server, entry->fileid, entry->mtime, error_ptr); @@ -1945,13 +1945,13 @@ smb_proc_readdir_short (struct smb_server *server, char *path, int fpos, int cac retry: - first = 1; + first = TRUE; total_count = 0; current_entry = entry; - while (1) + while (TRUE) { - if (first == 1) + if (first) { ASSERT( smb_payload_size(server, 2, 5 + strlen (mask)) >= 0 ); @@ -1994,7 +1994,7 @@ smb_proc_readdir_short (struct smb_server *server, char *path, int fpos, int cac p = smb_decode_word (p, &count); /* vwv[0] = count-returned */ p = smb_decode_word (p, &bcc); - first = 0; + first = FALSE; if (count <= 0) { @@ -2826,7 +2826,7 @@ smb_query_path_information(struct smb_server *server, const char *path, int len, p += 2 * sizeof(dword); /* LastChangeTime */ p = smb_decode_dword(p, &ext_file_attributes); - entry->attr = ext_file_attributes & 0xffff; + entry->attr = ext_file_attributes; p += sizeof(dword); /* Reserved */ @@ -3571,6 +3571,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) { const char *native_os = server->native_os != NULL ? server->native_os : "AmigaOS"; const char *native_lanman = VERS; + dword capabilities; SHOWMSG("server->protocol >= PROTOCOL_NT1"); @@ -3578,15 +3579,18 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) smb_setup_header (server, SMBsesssetupX, 13, user_len + password_len + nt_password_len + strlen (server->mount_data.workgroup_name)+1 + strlen (native_os)+1 + strlen (native_lanman)+1); - WSET (packet, smb_vwv0, 0xff); - WSET (packet, smb_vwv2, given_max_xmit); - WSET (packet, smb_vwv3, 2); - WSET (packet, smb_vwv4, 0); /* server->pid */ - DSET (packet, smb_vwv5, server_sesskey); - WSET (packet, smb_vwv7, password_len); - WSET (packet, smb_vwv8, nt_password_len); - DSET (packet, smb_vwv9, 0); /* reserved */ - DSET (packet, smb_vwv11, server->capabilities & 0x00800000); /* capabilities: Unix support. */ + capabilities = CAP_RAW_MODE|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_NT_FIND|CAP_LARGE_FILES; + + WSET (packet, smb_vwv0, 0xff); /* AndXCommand+AndXReserved */ + WSET (packet, smb_vwv1, 0); /* AndXOffset */ + WSET (packet, smb_vwv2, given_max_xmit); /* MaxBufferSize */ + WSET (packet, smb_vwv3, 2); /* MaxMpxCount */ + WSET (packet, smb_vwv4, 0); /* VcNumber */ + DSET (packet, smb_vwv5, server_sesskey); /* SessionKey */ + WSET (packet, smb_vwv7, password_len); /* OEMPasswordLen */ + WSET (packet, smb_vwv8, nt_password_len); /* UnicodePasswordLen */ + DSET (packet, smb_vwv9, 0); /* Reserved */ + DSET (packet, smb_vwv11, capabilities); /* Capabilities */ p = SMB_BUF (packet); diff --git a/source_code/smb_abstraction.c b/source_code/smb_abstraction.c index c3302f2..78a4562 100644 --- a/source_code/smb_abstraction.c +++ b/source_code/smb_abstraction.c @@ -114,27 +114,27 @@ smba_connect ( /* Olaf (2012-12-10): force raw SMB over TCP rather than NetBIOS. */ if(opt_raw_smb) - res->server.raw_smb = 1; + res->server.raw_smb = TRUE; /* olsen (2016-04-20): Use write-behind with SMB_COM_WRITE_RAW. */ if(opt_write_behind) - res->server.write_behind = 1; + res->server.write_behind = TRUE; /* olsen (2018-05-08): Always use SMB_COM_WRITE, even if SMB_COM_WRITE_RAW were possible. */ if(opt_disable_write_raw) { - res->server.disable_write_raw = 1; + res->server.disable_write_raw = TRUE; } else { /* olsen (2016-04-20): Prefer the use of SMB_COM_WRITE_RAW over SMB_COM_WRITE. */ if(opt_prefer_write_raw) - res->server.prefer_write_raw = 1; + res->server.prefer_write_raw = TRUE; } /* olsen (2018-05-08): Always use SMB_COM_READ, even if SMB_COM_READ_RAW were possible. */ if(opt_disable_read_raw) - res->server.disable_read_raw = 1; + res->server.disable_read_raw = TRUE; /* olsen (2018-05-09): Timeout for send/receive operations in seconds. */ res->server.timeout = timeout; @@ -198,10 +198,10 @@ smba_connect ( if (data.server_name[0] == '\0') { - if (strlen (p->server_ipname) > 16) + if (!res->server.raw_smb && strlen (p->server_ipname) > 16) { ReportError("Server name '%s' is too long for NetBIOS (max %ld characters).",p->server_ipname,16); - + (*error_ptr) = ENAMETOOLONG; goto error_occured; } @@ -213,7 +213,7 @@ smba_connect ( if (data.client_name[0] == '\0') { - if (strlen (hostname) > 16) + if (!res->server.raw_smb && strlen (hostname) > 16) { ReportError("Local host name '%s' is too long for NetBIOS (max %ld characters).", hostname, 16); @@ -233,7 +233,7 @@ smba_connect ( goto error_occured; if (!use_E) - res->supports_E_known = 1; + res->supports_E_known = TRUE; (*smba_server_ptr) = res; res = NULL; @@ -246,7 +246,7 @@ smba_connect ( { (*smb_error_class_ptr) = res->server.rcls; (*smb_error_ptr) = res->server.err; - + smba_cleanup_dircache (res); free (res); } @@ -297,6 +297,24 @@ make_open (smba_file_t * f, int need_fid, int writable, int truncate, int * erro if (f->server->server.protocol >= PROTOCOL_LANMAN2) { if(need_fid) + { + if(!f->dirent.opened) + { + LOG (("opening file %s\n", f->dirent.complete_path)); + + result = smb_proc_open (&s->server, f->dirent.complete_path, f->dirent.len, writable, truncate, &f->dirent, error_ptr); + if (result < 0) + goto out; + } + else + { + LOG (("file %s is already open\n", f->dirent.complete_path)); + } + } + } + else if (need_fid || !s->supports_E_known || s->supports_E) + { + if(!f->dirent.opened) { LOG (("opening file %s\n", f->dirent.complete_path)); @@ -304,13 +322,10 @@ make_open (smba_file_t * f, int need_fid, int writable, int truncate, int * erro if (result < 0) goto out; } - } - else if (need_fid || !s->supports_E_known || s->supports_E) - { - LOG (("opening file %s\n", f->dirent.complete_path)); - result = smb_proc_open (&s->server, f->dirent.complete_path, f->dirent.len, writable, truncate, &f->dirent, error_ptr); - if (result < 0) - goto out; + else + { + LOG (("file %s is already open\n", f->dirent.complete_path)); + } if (s->supports_E || !s->supports_E_known) { @@ -318,14 +333,14 @@ make_open (smba_file_t * f, int need_fid, int writable, int truncate, int * erro { if (!s->supports_E_known) { - s->supports_E_known = 1; - s->supports_E = 0; + s->supports_E_known = TRUE; + s->supports_E = FALSE; } /* ignore errors here */ } else { - s->supports_E_known = 1; - s->supports_E = 1; + s->supports_E_known = TRUE; + s->supports_E = TRUE; } } } @@ -342,7 +357,7 @@ make_open (smba_file_t * f, int need_fid, int writable, int truncate, int * erro } f->attr_time = GetCurrentTime(); - f->is_valid = 1; + f->is_valid = TRUE; } result = 0; @@ -366,7 +381,7 @@ smba_open (smba_server_t * s, char *name, size_t name_size, int writable, int tr if(f == NULL) { (*error_ptr) = ENOMEM; - + result = -1; goto out; } @@ -887,7 +902,7 @@ smba_lockrec (smba_file_t *f, long offset, long len, long mode, int unlocked, lo if (rec_lock == NULL) { (*error_ptr) = ENOMEM; - + result = -1; goto out; } @@ -945,10 +960,10 @@ smba_getattr (smba_file_t * f, smba_stat_t * data, int * error_ptr) } data->is_dir = (f->dirent.attr & aDIR) != 0; - data->is_wp = (f->dirent.attr & aRONLY) != 0; + data->is_read_only = (f->dirent.attr & aRONLY) != 0; data->is_hidden = (f->dirent.attr & aHIDDEN) != 0; data->is_system = (f->dirent.attr & aSYSTEM) != 0; - data->is_archive = (f->dirent.attr & aARCH) != 0; + data->is_changed_since_last_archive = (f->dirent.attr & aARCH) != 0; data->size = f->dirent.size; data->atime = f->dirent.atime; @@ -991,20 +1006,22 @@ smba_setattr (smba_file_t * f, const smba_stat_t * data, const dword * size_ptr, attrs = f->dirent.attr; - if (data->is_wp) + if (data->is_read_only) attrs |= aRONLY; else attrs &= ~aRONLY; - if (data->is_archive) + if (data->is_changed_since_last_archive) attrs |= aARCH; else attrs &= ~aARCH; + /* if (data->is_system) attrs |= aSYSTEM; else attrs &= ~aSYSTEM; + */ if(f->dirent.attr != attrs) { @@ -1112,7 +1129,7 @@ smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback, int if (f->dircache == NULL) { LOG (("lost dircache due to an error, bailing out!\n")); - + (*error_ptr) = ENOMEM; result = -1; @@ -1132,15 +1149,15 @@ smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback, int LOG (("delivering '%s', cache_index=%ld, eof=%ld\n", f->dircache->cache[o].complete_path, cache_index, eof)); - data.is_dir = (f->dircache->cache[o].attr & aDIR) != 0; - data.is_wp = (f->dircache->cache[o].attr & aRONLY) != 0; - data.is_hidden = (f->dircache->cache[o].attr & aHIDDEN) != 0; - data.is_system = (f->dircache->cache[o].attr & aSYSTEM) != 0; - data.is_archive = (f->dircache->cache[o].attr & aARCH) != 0; - data.size = f->dircache->cache[o].size; - data.atime = f->dircache->cache[o].atime; - data.ctime = f->dircache->cache[o].ctime; - data.mtime = f->dircache->cache[o].mtime; + data.is_dir = (f->dircache->cache[o].attr & aDIR) != 0; + data.is_read_only = (f->dircache->cache[o].attr & aRONLY) != 0; + data.is_hidden = (f->dircache->cache[o].attr & aHIDDEN) != 0; + data.is_system = (f->dircache->cache[o].attr & aSYSTEM) != 0; + data.is_changed_since_last_archive = (f->dircache->cache[o].attr & aARCH) != 0; + data.size = f->dircache->cache[o].size; + data.atime = f->dircache->cache[o].atime; + data.ctime = f->dircache->cache[o].ctime; + data.mtime = f->dircache->cache[o].mtime; if ((*callback) (d, cache_index, cache_index + 1, f->dircache->cache[o].complete_path, eof, &data)) break; @@ -1218,6 +1235,7 @@ smba_create (smba_file_t * dir, const char *name, smba_stat_t * attr, int * erro { struct smb_dirent entry; char *path = NULL; + size_t len; int result; result = make_open (dir, open_dont_need_fid, open_read_only, open_dont_truncate, error_ptr); @@ -1226,37 +1244,40 @@ smba_create (smba_file_t * dir, const char *name, smba_stat_t * attr, int * erro memset (&entry, 0, sizeof (entry)); - if (attr->is_wp) - entry.attr |= aRONLY; - - if (attr->is_archive) - entry.attr |= aARCH; - - if (attr->is_system) - entry.attr |= aSYSTEM; - entry.atime = entry.mtime = entry.ctime = GetCurrentTime(); - path = malloc (strlen (name) + dir->dirent.len + 2); + len = strlen(name); + + path = malloc (len + 1 + dir->dirent.len + 1); if(path == NULL) { (*error_ptr) = ENOMEM; - + result = -1; goto out; } memcpy (path, dir->dirent.complete_path, dir->dirent.len); path[dir->dirent.len] = DOS_PATHSEP; - strcpy (&path[dir->dirent.len + 1], name); + memcpy(&path[dir->dirent.len+1], name, len+1); if (dir->server->server.protocol >= PROTOCOL_LANMAN2) - result = smb_proc_open (&dir->server->server, path, strlen(path), open_writable, open_truncate, &entry, error_ptr); - else - result = smb_proc_create (&dir->server->server, path, strlen (path), &entry, error_ptr); + { + int ignored_error; - if(result < 0) - goto out; + result = smb_proc_open (&dir->server->server, path, strlen(path), open_writable, open_truncate, &entry, error_ptr); + if(result < 0) + goto out; + + /* Close the file again, we don't really need it right now. */ + smb_proc_close(&dir->server->server,entry.fileid,entry.mtime,&ignored_error); + } + else + { + result = smb_proc_create (&dir->server->server, path, strlen (path), &entry, error_ptr); + if(result < 0) + goto out; + } invalidate_dircache (dir->server, path); @@ -1309,9 +1330,10 @@ smba_mkdir (smba_file_t * dir, const char *name, int * error_ptr) /*****************************************************************************/ -static void +static int close_path (smba_server_t * s, char *path, int * error_ptr) { + int result = 0; smba_file_t *p; for (p = (smba_file_t *)s->open_files.mlh_Head; @@ -1322,13 +1344,21 @@ close_path (smba_server_t * s, char *path, int * error_ptr) { if (p->dirent.opened) { - smb_proc_close (&s->server, p->dirent.fileid, p->dirent.mtime, error_ptr); + result = smb_proc_close (&s->server, p->dirent.fileid, p->dirent.mtime, error_ptr); + if(result < 0) + { + LOG(("closing %s with file id %ld failed\n", path, p->dirent.fileid)); + break; + } + p->dirent.opened = FALSE; } - + p->is_valid = FALSE; } } + + return(result); } /*****************************************************************************/ @@ -1338,7 +1368,9 @@ smba_remove (smba_server_t * s, char *path, int * error_ptr) { int result; - close_path (s, path, error_ptr); + result = close_path (s, path, error_ptr); + if(result < 0) + goto out; result = smb_proc_unlink (&s->server, path, strlen (path), error_ptr); if(result < 0) @@ -1358,7 +1390,9 @@ smba_rmdir (smba_server_t * s, char *path, int * error_ptr) { int result; - close_path (s, path, error_ptr); + result = close_path (s, path, error_ptr); + if(result < 0) + goto out; result = smb_proc_rmdir (&s->server, path, strlen (path), error_ptr); if(result < 0) @@ -1378,7 +1412,9 @@ smba_rename (smba_server_t * s, char *from, char *to, int * error_ptr) { int result; - close_path (s, from, error_ptr); + result = close_path (s, from, error_ptr); + if(result < 0) + goto out; result = smb_proc_mv (&s->server, from, strlen (from), to, strlen (to), error_ptr); if(result < 0) @@ -1425,8 +1461,8 @@ smb_invalidate_all_inodes (struct smb_server *server) f->node.mln_Succ != NULL; f = (smba_file_t *)f->node.mln_Succ) { - f->dirent.opened = 0; - f->is_valid = 0; + f->dirent.opened = FALSE; + f->is_valid = FALSE; } } @@ -1516,9 +1552,9 @@ extract_service (char *service, char *server, size_t server_size, char *share, s if(service_copy == NULL) { ReportError("Not enough memory."); - + (*error_ptr) = ENOMEM; - + goto out; } @@ -1602,9 +1638,9 @@ smba_start( int i; struct hostent *h; int use_extended = 0; - char server_name[17], client_name[17]; + char server_name[17], client_name[17]; /* Maximum length appears to be 16 characters for NetBIOS */ char username[64], password[64]; - char workgroup[20]; + char workgroup[64]; /* Maximum length appears to be 15 characters */ char server[64], share[64]; in_addr_t ipAddr; int result = -1; @@ -1635,7 +1671,7 @@ smba_start( else if (BroadcastNameQuery(server,"",(UBYTE *)&ipAddr) != 0) { ReportError("Unknown host '%s' (%ld, %s).",server,lookup_error,host_strerror(lookup_error)); - + (*error_ptr) = ENOENT; goto out; } @@ -1665,8 +1701,8 @@ smba_start( hostName[i] = '\0'; - /* Make sure the hostname is 16 characters or less (for Netbios) */ - if (strlen (hostName) > 16) + /* Make sure the hostname is 16 characters or less (for NetBIOS) */ + if (!opt_raw_smb && strlen (hostName) > 16) { ReportError("Server host name '%s' is too long (max %ld characters).", hostName, 16); @@ -1701,6 +1737,7 @@ smba_start( strlcpy(username,opt_username,sizeof(username)); StringToUpper(username); + /* if (strlen(opt_workgroup) > 15) { ReportError("Workgroup/domain name '%s' is too long (max %ld characters).", opt_workgroup,15); @@ -1708,13 +1745,14 @@ smba_start( (*error_ptr) = ENAMETOOLONG; goto out; } + */ strlcpy (workgroup, opt_workgroup, sizeof(workgroup)); StringToUpper (workgroup); if(opt_servername != NULL) { - if (strlen (opt_servername) > 16) + if (!opt_raw_smb && strlen (opt_servername) > 16) { ReportError("Server name '%s' is too long (max %ld characters).", opt_servername,16); @@ -1727,7 +1765,7 @@ smba_start( if(opt_clientname != NULL) { - if (strlen (opt_clientname) > 16) + if (!opt_raw_smb && strlen (opt_clientname) > 16) { ReportError("Client name '%s' is too long (max %ld characters).", opt_clientname,16); diff --git a/source_code/smb_abstraction.h b/source_code/smb_abstraction.h index 764ab28..9e853d6 100644 --- a/source_code/smb_abstraction.h +++ b/source_code/smb_abstraction.h @@ -51,10 +51,10 @@ typedef struct smba_connect_parameters typedef struct smba_stat { unsigned is_dir:1; - unsigned is_wp:1; + unsigned is_read_only:1; unsigned is_hidden:1; unsigned is_system:1; - unsigned is_archive:1; + unsigned is_changed_since_last_archive:1; int size; long atime; long ctime; diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h index 308f3c9..1d409ef 100644 --- a/source_code/smbfs_rev.h +++ b/source_code/smbfs_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 134 -#define DATE "20.5.2018" -#define VERS "smbfs 1.134" -#define VSTRING "smbfs 1.134 (20.5.2018)\r\n" -#define VERSTAG "\0$VER: smbfs 1.134 (20.5.2018)" +#define REVISION 135 +#define DATE "21.5.2018" +#define VERS "smbfs 1.135" +#define VSTRING "smbfs 1.135 (21.5.2018)\r\n" +#define VERSTAG "\0$VER: smbfs 1.135 (21.5.2018)" diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev index 405e2af..c8b255f 100644 --- a/source_code/smbfs_rev.rev +++ b/source_code/smbfs_rev.rev @@ -1 +1 @@ -134 +135 diff --git a/source_code/sock.c b/source_code/sock.c index feb3dac..8039acc 100644 --- a/source_code/sock.c +++ b/source_code/sock.c @@ -827,6 +827,8 @@ smb_release (struct smb_server *server) CloseSocket (server->mount_data.fd); server->mount_data.fd = -1; } + + server->state = CONN_INVALID; } int @@ -842,6 +844,8 @@ smb_connect (struct smb_server *server, int * error_ptr) result = socket (AF_INET, SOCK_STREAM, 0); if (result < 0) { + server->state = CONN_INVALID; + (*error_ptr) = errno; goto out; @@ -852,12 +856,117 @@ smb_connect (struct smb_server *server, int * error_ptr) LOG(("connecting to server %s\n", Inet_NtoA(server->mount_data.addr.sin_addr.s_addr))); - result = connect (server->mount_data.fd, (struct sockaddr *)&server->mount_data.addr, sizeof(struct sockaddr_in)); - if(result < 0) + /* Wait a certain time period for the connection attempt to succeed? */ + if(server->timeout > 0) { - (*error_ptr) = errno; + int non_blocking_io; + struct timeval tv; + fd_set write_fds; - goto out; + /* Switch the socket into non-blocking mode, so that we + * may start the connection attempt and wait for it to + * either succeed or fail. + */ + non_blocking_io = TRUE; + + result = IoctlSocket(server->mount_data.fd, FIONBIO, &non_blocking_io); + if(result < 0) + { + server->state = CONN_INVALID; + + (*error_ptr) = errno; + + goto out; + } + + FD_ZERO(&write_fds); + FD_SET(server->mount_data.fd,&write_fds); + + memset(&tv,0,sizeof(tv)); + + tv.tv_secs = server->timeout; + + /* Try to establish the connection and don't hang around until + * it either succeeds or fails. + */ + connect (server->mount_data.fd, (struct sockaddr *)&server->mount_data.addr, sizeof(struct sockaddr_in)); + + LOG(("will wait for up to %ld seconds for connection attempt to succeed\n",server->timeout)); + + /* Wait for the connection status to change (success/failure), or until + * the timeout has elapsed. + */ + result = WaitSelect(server->mount_data.fd+1, NULL, &write_fds, NULL, &tv, NULL); + + /* Connection status is known? */ + if (result == 1) + { + socklen_t len; + int error; + + error = 0; + len = sizeof(error); + + /* Check if it failed or succeeded. */ + if(getsockopt(server->mount_data.fd,SOL_SOCKET,SO_ERROR,&error,&len) == 0) + { + /* Connection established? */ + if(error == 0) + { + result = 0; + } + /* Connection could not be made. */ + else + { + (*error_ptr) = errno; + + result = -1; + } + } + /* Well, that could happen, too. */ + else + { + (*error_ptr) = errno; + result = -1; + } + } + /* Connection attempt timed out? */ + else if (result == 0) + { + (*error_ptr) = EWOULDBLOCK; + result = -1; + } + /* Well, that could happen, too. */ + else /* if (result < 0) */ + { + (*error_ptr) = errno; + } + + /* Switch the socket back into blocking mode. */ + non_blocking_io = FALSE; + IoctlSocket(server->mount_data.fd, FIONBIO, &non_blocking_io); + + if(result < 0) + { + server->state = CONN_INVALID; + + goto out; + } + } + /* Wait almost indefinitely for the connection to + * be made. + */ + else + { + result = connect (server->mount_data.fd, (struct sockaddr *)&server->mount_data.addr, sizeof(struct sockaddr_in)); + if(result < 0) + { + server->state = CONN_INVALID; + + (*error_ptr) = errno; + + goto out; + } } /* Configure the send/receive timeout (in seconds)? */ @@ -920,8 +1029,10 @@ smb_check_server_connection(struct smb_server *server, int error) if(error == EINTR) server->dont_retry = TRUE; - server->state = CONN_INVALID; smb_invalidate_all_inodes (server); + + SHOWMSG("closing the server connection."); + smb_release(server); } } } diff --git a/source_code/system_headers.h b/source_code/system_headers.h index 7fc995f..b165817 100644 --- a/source_code/system_headers.h +++ b/source_code/system_headers.h @@ -127,7 +127,7 @@ #include #include /*#include */ -/*#include */ +#include #include #include