diff --git a/documentation/history.doc b/documentation/history.doc index 598fc0d..de6a7b9 100644 --- a/documentation/history.doc +++ b/documentation/history.doc @@ -2124,3 +2124,54 @@ smbfs 1.155 (24.6.2018) conversion. Fixed. Now I'm curious if this actually manages to make things worse because the SMB server may have reported its "local time" as UTC :-/ + + +smbfs 1.156 (24.6.2018) + +- When processing the entries returned by directory scanning + the names of entries would not be processed correctly if + these were neither NUL-terminated nor NUL-padded. Thanks go + to Tony Wyatt for reporting the problem. + +- When preparing for reading from a file which was not yet + ready to be accessed, accessing it could return an error + code indicating that the access mode was not correct. + Instead of retrying to access the file in read-only mode, + the relevant function aborted the access attempt. This has + been replaced by asking for read-only access and retrying. + Thanks go to Tony Wyatt for reporting the problem. + +- Slightly more robust handling of ExAll() due to the correct + size of the the entry being known more early on. + +- Printing the list of ExAll() entries to be returned crashed + "reliably" if the number of entries was zero. Thanks go to + Hubert Maier for reporting the problem. + + +smbfs 1.157 (26.6.2018) + +- The ACTION_SETDATE implementation now shows the date/time + to be used before it is handed over to the respective SMB + commands which change it for a file/directory. Because the + different SMB commands (three of them) cannot but change + three times (creation, modification, access) we now make + sure that all three are initialized by reusing the current + state of affairs. + + +smbfs 1.158 (27.6.2018) + +- Changing the attributes of a file/directory, as in "archived" + or "deletable" did not work at all in protocol=core because + the original code which handled this used the command + SMB_COM_SET_INFORMATION2 in place of SMB_COM_SET_INFORMATION. + The command SMB_COM_SET_INFORMATION2 can only change time + information but not the attributes. I changed this to use + SMB_COM_SET_INFORMATION when necessary. + +- Changing the attributes and/or times of files/directories + would have no effect if the server dropped out, the connection + had to be reestablished and the file/directory in question had + to be reopened because all the attribute and file information + was overwritten. Fixed. diff --git a/source_code/include/smb/smb_fs.h b/source_code/include/smb/smb_fs.h index db272fb..181f705 100644 --- a/source_code/include/smb/smb_fs.h +++ b/source_code/include/smb/smb_fs.h @@ -69,7 +69,7 @@ int smb_proc_mv(struct smb_server *server, const char *opath, const int olen, co int smb_proc_mkdir(struct smb_server *server, const char *path, const int len, int * error_ptr); int smb_proc_rmdir(struct smb_server *server, const char *path, const int len, int * error_ptr); int smb_proc_unlink(struct smb_server *server, const char *path, const int len, int * error_ptr); -int smb_proc_trunc(struct smb_server *server, word fid, dword length, int * error_ptr); +int smb_proc_trunc(struct smb_server *server, struct smb_dirent *entry, dword length, int * error_ptr); int smb_proc_readdir(struct smb_server *server, const char *path, int fpos, int cache_size, struct smb_dirent *entry, int * error_ptr); int smb_proc_getattr_core(struct smb_server *server, const char *path, int len, struct smb_dirent *entry, int * error_ptr); int smb_proc_getattrE(struct smb_server *server, struct smb_dirent *entry, int * error_ptr); diff --git a/source_code/main.c b/source_code/main.c index a2d5790..4c8cacb 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -4836,10 +4836,6 @@ Action_SetProtect( memset(&st,0,sizeof(st)); - st.atime = -1; - st.ctime = -1; - st.mtime = -1; - if((mask & FIBF_DELETE) != 0) { SHOWMSG("write/delete protection enabled"); @@ -5378,11 +5374,34 @@ Action_ExamineObject( SHOWVALUE(fib->fib_DirEntryType); SHOWVALUE(fib->fib_NumBlocks); SHOWVALUE(fib->fib_Size); - SHOWVALUE(fib->fib_Date.ds_Days); - SHOWVALUE(fib->fib_Date.ds_Minute); - SHOWVALUE(fib->fib_Date.ds_Tick); SHOWVALUE(fib->fib_DiskKey); + #if DEBUG + { + struct DateTime dat; + TEXT date[LEN_DATSTRING],time[LEN_DATSTRING]; + + memset(&dat,0,sizeof(dat)); + + memset(date,0,sizeof(date)); + memset(time,0,sizeof(time)); + + dat.dat_Stamp = fib->fib_Date; + dat.dat_Format = FORMAT_DEF; + dat.dat_StrDate = date; + dat.dat_StrTime = time; + + if(DateToStr(&dat)) + { + D(("days=%ld/minutes=%ld/ticks=%ld: %s %s", fib->fib_Date.ds_Days, fib->fib_Date.ds_Minute, fib->fib_Date.ds_Tick, date, time)); + } + else + { + D(("could not convert days=%ld/minutes=%ld/ticks=%ld", fib->fib_Date.ds_Days, fib->fib_Date.ds_Minute, fib->fib_Date.ds_Tick)); + } + } + #endif /* DEBUG */ + out: (*error_ptr) = error; @@ -5554,6 +5573,32 @@ dir_scan_callback_func_exnext( fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60; fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND; + #if DEBUG + { + struct DateTime dat; + TEXT date[LEN_DATSTRING],time[LEN_DATSTRING]; + + memset(&dat,0,sizeof(dat)); + + memset(date,0,sizeof(date)); + memset(time,0,sizeof(time)); + + dat.dat_Stamp = fib->fib_Date; + dat.dat_Format = FORMAT_DEF; + dat.dat_StrDate = date; + dat.dat_StrTime = time; + + if(DateToStr(&dat)) + { + D((" days=%ld/minutes=%ld/ticks=%ld: %s %s", fib->fib_Date.ds_Days, fib->fib_Date.ds_Minute, fib->fib_Date.ds_Tick, date, time)); + } + else + { + D((" could not convert days=%ld/minutes=%ld/ticks=%ld", fib->fib_Date.ds_Days, fib->fib_Date.ds_Minute, fib->fib_Date.ds_Tick)); + } + } + #endif /* DEBUG */ + result = 1; out: @@ -5781,9 +5826,16 @@ dir_scan_callback_func_exall( */ ed_size = ec->ec_MinSize + name_len+1; - if(ec->ec_Next == NULL || ed_size > ec->ec_BytesLeft) + /* All entries need to begin on a word-aligned address, + * which means that we need to pad the entry size to + * a multiple of 2. + */ + if((ed_size % 2) > 0) + ed_size++; + + if(ec->ec_Next == NULL || ec->ec_BytesLeft < ed_size) { - D(("Not enough room to return this entry: size %ld > ec->ec_BytesLeft %ld",ed_size,ec->ec_BytesLeft)); + D(("Not enough room to return this entry: ec->ec_BytesLeft %ld < size %ld",ec->ec_BytesLeft,ed_size)); /* If this is the first directory entry, * stop the entire process before it has @@ -5814,7 +5866,7 @@ dir_scan_callback_func_exall( ed->ed_Next = NULL; /* Copy the name, including the terminating NUL byte. */ - ed->ed_Name = (STRPTR)(((ULONG)ed) + ec->ec_MinSize); + ed->ed_Name = (STRPTR)(&((BYTE *)ed)[ec->ec_MinSize]); memcpy(ed->ed_Name,name,name_len+1); /* Fill in as many records as were requested. */ @@ -5908,19 +5960,9 @@ dir_scan_callback_func_exall( if(ec->ec_Last != NULL) ec->ec_Last->ed_Next = ed; - /* All entries need to begin on a word-aligned address, - * which means that we need to pad the entry size to - * a multiple of 2. - */ - if((ed_size % 2) > 0) - ed_size++; - - /* Note: due to the padding byte the number of bytes - * left may become negative. - */ ec->ec_BytesLeft -= ed_size; - ec->ec_Next = ec->ec_BytesLeft > 0 ? (struct ExAllData *)(((ULONG)ed) + ed_size) : NULL; + ec->ec_Next = ec->ec_BytesLeft > 0 ? (struct ExAllData *)(&((BYTE *)ed)[ed_size]) : NULL; ec->ec_Last = ed; ec->ec_Control->eac_Entries++; @@ -6138,14 +6180,23 @@ Action_ExamineAll( #if DEBUG { + int num_entries_found = 0; + SHOWVALUE(eac->eac_Entries); - while(ed != NULL) + if(eac->eac_Entries > 0) { - SHOWSTRING(ed->ed_Name); + do + { + SHOWSTRING(ed->ed_Name); + num_entries_found++; - ed = ed->ed_Next; + ed = ed->ed_Next; + } + while(ed != NULL); } + + ASSERT( eac->eac_Entries == num_entries_found ); } #endif /* DEBUG */ @@ -6817,14 +6868,40 @@ Action_SetDate( goto out; } + #if DEBUG + { + struct DateTime dat; + TEXT date[LEN_DATSTRING],time[LEN_DATSTRING]; + + memset(&dat,0,sizeof(dat)); + + memset(date,0,sizeof(date)); + memset(time,0,sizeof(time)); + + dat.dat_Stamp = (*ds); + dat.dat_Format = FORMAT_DEF; + dat.dat_StrDate = date; + dat.dat_StrTime = time; + + if(DateToStr(&dat)) + { + D(("days=%ld/minutes=%ld/ticks=%ld: %s %s", ds->ds_Days, ds->ds_Minute, ds->ds_Tick, date, time)); + } + else + { + D(("could not convert days=%ld/minutes=%ld/ticks=%ld", ds->ds_Days, ds->ds_Minute, ds->ds_Tick)); + } + } + #endif /* DEBUG */ + seconds = (ds->ds_Days * 24 * 60 + ds->ds_Minute) * 60 + (ds->ds_Tick / TICKS_PER_SECOND); - memset(&st,0,sizeof(st)); - - st.atime = -1; - st.ctime = -1; + st.ctime = 0; + st.atime = 0; st.mtime = seconds + UNIX_TIME_OFFSET + get_time_zone_delta(); + D(("mtime = %lu",st.mtime)); + if(smba_setattr(file,&st,NULL,&error) < 0) { error = map_errno_to_ioerr(error); diff --git a/source_code/proc.c b/source_code/proc.c index 2b1be97..3775a39 100644 --- a/source_code/proc.c +++ b/source_code/proc.c @@ -391,7 +391,7 @@ static size_t strnlen(const char * s,size_t max_size) if(max_size > 0) { - while((*s) != '\0' && --max_size > 0) + while((*s) != '\0' && max_size-- > 0) s++; } @@ -1368,10 +1368,16 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri result = smb_request_ok(server, SMBntcreateX, 34, 0, error_ptr); if (result < 0) { + int access_error; + SHOWMSG("that didn't work; retrying"); /* Try again in read-only mode? */ - if ((*error_ptr) == EACCES || ((*error_ptr) == error_check_smb_error && smb_errno(server->rcls,server->err) == EACCES)) + access_error = (*error_ptr); + if(access_error == error_check_smb_error) + access_error = smb_errno(server->rcls,server->err); + + if (access_error == EACCES || access_error == EPERM) { if(retry_read_only) { @@ -1466,8 +1472,16 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri result = smb_request_ok (server, SMBopen, 7, 0, error_ptr); if (result < 0) { + int access_error; + + SHOWMSG("that didn't work; retrying"); + /* Try again in read-only mode? */ - if ((*error_ptr) == EACCES || ((*error_ptr) == error_check_smb_error && smb_errno(server->rcls,server->err) == EACCES)) + access_error = (*error_ptr); + if(access_error == error_check_smb_error) + access_error = smb_errno(server->rcls,server->err); + + if (access_error == EACCES || access_error == EPERM) { if(retry_read_only) { @@ -1497,10 +1511,10 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri entry->attr = WVAL (buf, smb_vwv1); - /* This is actually just the mtime value, but we use it + /* This is actually just the wtime value, but we use it * in all other places as well. */ - entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc (DVAL (buf, smb_vwv2)); + entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc(DVAL (buf, smb_vwv2)); /* Note: this is UTIME, and should be the server's local time. */ #if DEBUG { @@ -1546,18 +1560,18 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri * the server */ int -smb_proc_close (struct smb_server *server, word fileid, dword mtime, int * error_ptr) +smb_proc_close (struct smb_server *server, word fileid, dword wtime, int * error_ptr) { char *buf = server->transmit_buffer; int result; - /* 0 and 0xffffffff mean: do not set mtime */ - if(mtime != 0 && mtime != (dword)0xffffffff) - mtime = utc2local (mtime); + /* Note: wtime is UTIME, and should be the server's local time. */ + if(wtime != 0 && wtime != (dword)-1) + wtime = utc2local(wtime); smb_setup_header (server, SMBclose, 3, 0); WSET (buf, smb_vwv0, fileid); - DSET (buf, smb_vwv1, mtime); + DSET (buf, smb_vwv1, wtime); result = smb_request_ok (server, SMBclose, 0, 0, error_ptr); @@ -2052,16 +2066,18 @@ smb_proc_lockingX (struct smb_server *server, struct smb_dirent *finfo, const st int smb_proc_create (struct smb_server *server, const char *path, int len, struct smb_dirent *entry, int * error_ptr) { - dword local_time = utc2local (entry->ctime); + dword local_time; int result; char *p; char *buf = server->transmit_buffer; int path_size; + local_time = utc2local(entry->ctime); /* Note: this is UTIME, and should be the server's local time. */ + #if DEBUG { - struct tm tm_utc; struct tm tm_local; + struct tm tm_utc; seconds_to_tm(entry->ctime,&tm_utc); @@ -2368,7 +2384,7 @@ smb_proc_unlink (struct smb_server *server, const char *path, const int len, int * writes "enough" data to the file. */ int -smb_proc_trunc (struct smb_server *server, word fid, dword length, int * error_ptr) +smb_proc_trunc (struct smb_server *server, struct smb_dirent *entry, dword length, int * error_ptr) { char *p; char *buf = server->transmit_buffer; @@ -2379,7 +2395,7 @@ smb_proc_trunc (struct smb_server *server, word fid, dword length, int * error_p retry: p = smb_setup_header (server, SMBwrite, 5, 3); - WSET (buf, smb_vwv0, fid); + WSET (buf, smb_vwv0, entry->fileid); WSET (buf, smb_vwv1, 0); DSET (buf, smb_vwv2, length); WSET (buf, smb_vwv4, 0); @@ -2390,7 +2406,10 @@ smb_proc_trunc (struct smb_server *server, word fid, dword length, int * error_p if(result < 0) { if ((*error_ptr) != error_check_smb_error && smb_retry (server)) - goto retry; + { + if(reopen_entry(server,entry,NULL) == 0) + goto retry; + } } else { @@ -2826,6 +2845,21 @@ smb_decode_long_dirent (const struct smb_server *server, const char *p, struct s finfo->len = name_len; D(("name = '%s', length=%ld, size=%ld",escape_name(finfo->complete_path),name_len,name_size)); + + #if DEBUG + { + struct tm tm; + + seconds_to_tm(finfo->mtime,&tm); + LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(finfo->ctime,&tm); + LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(finfo->atime,&tm); + LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(finfo->wtime,&tm); + LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + } + #endif /* DEBUG */ } break; @@ -2937,6 +2971,21 @@ smb_decode_long_dirent (const struct smb_server *server, const char *p, struct s finfo->len = name_len; D(("name = '%s', length=%ld, size=%ld",escape_name(finfo->complete_path),name_len,name_size)); + + #if DEBUG + { + struct tm tm; + + seconds_to_tm(finfo->mtime,&tm); + LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(finfo->ctime,&tm); + LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(finfo->atime,&tm); + LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(finfo->wtime,&tm); + LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + } + #endif /* DEBUG */ } break; @@ -3380,8 +3429,8 @@ smb_proc_getattr_core (struct smb_server *server, const char *path, int len, str entry->attr = WVAL (buf, smb_vwv0); - /* The server only tells us just the mtime */ - entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc (DVAL (buf, smb_vwv1)); + /* The server only tells us just the wtime */ + entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc(DVAL (buf, smb_vwv1)); /* Note: this is UTIME, and should be the server's local time. */ #if DEBUG { @@ -3505,7 +3554,19 @@ smb_query_path_information(struct smb_server *server, const char *path, int len, if (result < 0) { if ((*error_ptr) != error_check_smb_error && smb_retry (server)) - goto retry; + { + /* We don't need the file id? */ + if (len > 0) + { + goto retry; + } + /* We do need the file id. */ + else if (reopen_entry(server,entry,NULL) == 0) + { + fid = entry->fileid; + goto retry; + } + } goto out; } @@ -3528,6 +3589,7 @@ smb_query_path_information(struct smb_server *server, const char *path, int len, entry->atime = convert_long_date_to_time_t(p); p += 2 * sizeof(dword); /* LastAccessTime */ + entry->wtime = convert_long_date_to_time_t(p); p += 2 * sizeof(dword); /* LastWriteTime */ entry->mtime = convert_long_date_to_time_t(p); @@ -3577,8 +3639,13 @@ smb_query_path_information(struct smb_server *server, const char *path, int len, entry_size_quad.High = entry->size_high; seconds_to_tm(entry->mtime,&tm); - LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(entry->ctime,&tm); + LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(entry->atime,&tm); + LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); + seconds_to_tm(entry->wtime,&tm); + LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec)); LOG(("size = %s (0x%08lx%08lx)\n",convert_quad_to_string(&entry_size_quad),entry->size_high,entry->size_low)); LOG(("attr = 0x%08lx\n",entry->attr)); LOG(("name = '%s' (length in bytes = %ld)\n",escape_name(name),file_name_length)); @@ -3704,6 +3771,16 @@ smb_set_file_information(struct smb_server *server, struct smb_dirent *entry, co DSET(p, 8, 0); DSET(p, 12, 0); + /* Note that we update both mtime and wtime of the + * directory and not just mtime because some Samba + * versions will end up setting the mtime of the + * directory entry to the time given as the wtime + * value and ignore the mtime value. This happens + * even if the wtime value is given as zero and the + * mtime value is non-zero. + */ + LOG(("entry->mtime = %lu\n",entry->mtime)); + convert_time_t_to_long_date(entry->mtime,&change_time_quad); /* Last write time */ @@ -3758,16 +3835,36 @@ smb_set_file_information(struct smb_server *server, struct smb_dirent *entry, co int smb_proc_setattr_core (struct smb_server *server, const char *path, int len, const struct smb_dirent *new_finfo, int * error_ptr) { - dword local_time = utc2local (new_finfo->mtime); + dword local_time; char *p; char *buf = server->transmit_buffer; int result; int path_size; + dword attr; + + /* Don't do anything if mtime is unset. */ + if(new_finfo->mtime == 0 || new_finfo->mtime == (time_t)-1) + return(0); + + if(server->unicode_enabled) + path_size = 1 + 2 * (len + 1 + 1); + else + path_size = 1 + len + 1 + 1; + + ASSERT( smb_payload_size(server, 8, path_size) >= 0 ); + + /* We cache these because if the connection needs to be + * reestablished, the direntry values will all get + * overwritten. + */ + attr = new_finfo->attr; + + local_time = utc2local(new_finfo->mtime); /* Note: this is UTIME, and should be the server's local time. */ #if DEBUG { - struct tm tm_utc; struct tm tm_local; + struct tm tm_utc; seconds_to_tm(new_finfo->mtime,&tm_utc); @@ -3791,17 +3888,10 @@ smb_proc_setattr_core (struct smb_server *server, const char *path, int len, con } #endif /* DEBUG */ - if(server->unicode_enabled) - path_size = 1 + 2 * (len + 1 + 1); - else - path_size = 1 + len + 1 + 1; - - ASSERT( smb_payload_size(server, 8, path_size) >= 0 ); - retry: p = smb_setup_header (server, SMBsetatr, 8, path_size); - WSET (buf, smb_vwv0, new_finfo->attr); + WSET (buf, smb_vwv0, attr); DSET (buf, smb_vwv1, local_time); if(server->unicode_enabled) @@ -3826,44 +3916,91 @@ smb_proc_setattr_core (struct smb_server *server, const char *path, int len, con 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, int * error_ptr) { char *buf = server->transmit_buffer; word date, time_value; + time_t ctime, atime, mtime; + int num_changes; int result; + /* We cache these because if the connection needs to be + * reestablished, the direntry values will all get + * overwritten. + */ + ctime = new_entry->ctime; + atime = new_entry->atime; + mtime = new_entry->mtime; + retry: smb_setup_header (server, SMBsetattrE, 7, 0); WSET (buf, smb_vwv0, fid); - date_unix2dos (new_entry->ctime, &time_value, &date); + num_changes = 0; + + if(ctime != 0 && ctime != (time_t)-1) + { + date_unix2dos (ctime, &time_value, &date); + num_changes++; + } + else + { + date = time_value = 0; + } + WSET (buf, smb_vwv1, date); WSET (buf, smb_vwv2, time_value); - date_unix2dos (new_entry->atime, &time_value, &date); + if(atime != 0 && atime != (time_t)-1) + { + date_unix2dos (atime, &time_value, &date); + num_changes++; + } + else + { + date = time_value = 0; + } + WSET (buf, smb_vwv3, date); WSET (buf, smb_vwv4, time_value); - date_unix2dos (new_entry->mtime, &time_value, &date); + if(mtime != 0 && mtime != (time_t)-1) + { + date_unix2dos (mtime, &time_value, &date); + num_changes++; + } + else + { + date = time_value = 0; + } + WSET (buf, smb_vwv5, date); WSET (buf, smb_vwv6, time_value); - result = smb_request_ok (server, SMBsetattrE, 0, 0, error_ptr); - if (result < 0) + /* Do we actually have to change anything at all? */ + if(num_changes > 0) { - if ((*error_ptr) != error_check_smb_error && smb_retry (server)) + result = smb_request_ok (server, SMBsetattrE, 0, 0, error_ptr); + if (result < 0) { - if(reopen_entry(server,new_entry,NULL) == 0) - goto retry; - } + if ((*error_ptr) != error_check_smb_error && smb_retry (server)) + { + if(reopen_entry(server,new_entry,NULL) == 0) + { + fid = new_entry->fileid; + goto retry; + } + } - LOG(("that didn't work.\n")); + LOG(("that didn't work.\n")); + } + } + else + { + result = 0; } return result; diff --git a/source_code/smb_abstraction.c b/source_code/smb_abstraction.c index e502f0d..0cc6942 100644 --- a/source_code/smb_abstraction.c +++ b/source_code/smb_abstraction.c @@ -423,36 +423,84 @@ write_attr (smba_file_t * f, int * error_ptr) LOG (("file '%s'\n", escape_name(f->dirent.complete_path))); + LOG(("mtime = %lu\n",f->dirent.mtime)); + if(!f->server->server.prefer_core_protocol && f->server->server.protocol >= PROTOCOL_LANMAN2) { + /* Copy these, because make_open() may overwrite them. */ + time_t mtime = f->dirent.mtime; + dword attr = f->dirent.attr; + + LOG(("mtime = %lu\n",f->dirent.mtime)); + result = make_open (f, open_need_fid, open_writable, open_dont_truncate, error_ptr); if (result < 0) goto out; + LOG(("mtime = %lu\n",f->dirent.mtime)); + + f->dirent.mtime = mtime; + f->dirent.attr = attr; + result = smb_set_file_information (&f->server->server, &f->dirent, NULL, error_ptr); + if (result < 0) + goto out; + + f->attr_dirty = FALSE; } else { + /* Copy these, because make_open() may overwrite them. */ + time_t mtime = f->dirent.mtime; + dword attr = f->dirent.attr; + + LOG(("mtime = %lu\n",f->dirent.mtime)); + result = make_open (f, open_dont_need_fid, open_writable, open_dont_truncate, error_ptr); if (result < 0) goto out; - if (f->dirent.opened && f->server->supports_E) - result = smb_proc_setattrE (&f->server->server, f->dirent.fileid, &f->dirent, error_ptr); - else + LOG(("mtime = %lu\n",f->dirent.mtime)); + + f->dirent.mtime = mtime; + f->dirent.attr = attr; + + /* If the attributes need to be updated, we cannot used smb_proc_setattrE(), + * because that only updates the "time of last write access", but not the + * attributes. + */ + if(f->attr_dirty) + { + /* Update the attributes and the "time of last write access". */ result = smb_proc_setattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent, error_ptr); - } + if(result < 0) + goto out; - if (result < 0) - { - f->attr_time = 0; - goto out; - } + /* Now deal with the creation/access/modification times. */ + if (f->dirent.opened && f->server->supports_E) + { + result = smb_proc_setattrE (&f->server->server, f->dirent.fileid, &f->dirent, error_ptr); + if(result < 0) + goto out; + } - f->attr_dirty = FALSE; + f->attr_dirty = FALSE; + } + /* Update the times. */ + else + { + if (f->dirent.opened && f->server->supports_E) + result = smb_proc_setattrE (&f->server->server, f->dirent.fileid, &f->dirent, error_ptr); + else + result = smb_proc_setattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent, error_ptr); + } + } out: + if (result < 0) + f->attr_time = 0; + return result; } @@ -993,6 +1041,8 @@ smba_getattr (smba_file_t * f, smba_stat_t * data, int * error_ptr) if (!f->server->server.prefer_core_protocol && f->server->server.protocol >= PROTOCOL_LANMAN2) { + LOG(("using smb_query_path_information\n")); + if (f->dirent.opened) result = smb_query_path_information (&f->server->server, NULL, 0, f->dirent.fileid, &f->dirent, error_ptr); else @@ -1001,9 +1051,17 @@ smba_getattr (smba_file_t * f, smba_stat_t * data, int * error_ptr) else { if (f->dirent.opened && f->server->supports_E) + { + LOG(("using smb_proc_getattrE\n")); + result = smb_proc_getattrE (&f->server->server, &f->dirent, error_ptr); + } else + { + LOG(("using smb_proc_getattr_core\n")); + result = smb_proc_getattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent, error_ptr); + } } if (result < 0) @@ -1035,40 +1093,46 @@ smba_getattr (smba_file_t * f, smba_stat_t * data, int * error_ptr) /*****************************************************************************/ int -smba_setattr (smba_file_t * f, const smba_stat_t * data, const QUAD * const size, int * error_ptr) +smba_setattr (smba_file_t * f, const smba_stat_t * st, const QUAD * const size, int * error_ptr) { BOOL times_changed = FALSE; int result = 0; dword attrs; - if (data != NULL) + if (st != NULL) { - if (data->atime != (time_t)-1 && f->dirent.atime != data->atime) + if (st->atime != 0 && st->atime != (time_t)-1 && f->dirent.atime != st->atime) { - f->dirent.atime = data->atime; + LOG(("atime changed to %lu\n",st->atime)); + + f->dirent.atime = st->atime; times_changed = TRUE; } - if (data->ctime != (time_t)-1 && f->dirent.ctime != data->ctime) + if (st->ctime != 0 && st->ctime != (time_t)-1 && f->dirent.ctime != st->ctime) { - f->dirent.ctime = data->ctime; + LOG(("ctime changed to %lu\n",st->ctime)); + + f->dirent.ctime = st->ctime; times_changed = TRUE; } - if (data->mtime != (time_t)-1 && f->dirent.mtime != data->mtime) + if (st->mtime != 0 && st->mtime != (time_t)-1 && f->dirent.mtime != st->mtime) { - f->dirent.mtime = data->mtime; + LOG(("mtime changed to %lu\n",st->mtime)); + + f->dirent.mtime = st->mtime; times_changed = TRUE; } attrs = f->dirent.attr; - if (data->is_read_only) + if (st->is_read_only) attrs |= SMB_FILE_ATTRIBUTE_READONLY; else attrs &= ~SMB_FILE_ATTRIBUTE_READONLY; - if (data->is_changed_since_last_archive) + if (st->is_changed_since_last_archive) attrs |= SMB_FILE_ATTRIBUTE_ARCHIVE; else attrs &= ~SMB_FILE_ATTRIBUTE_ARCHIVE; @@ -1096,7 +1160,7 @@ smba_setattr (smba_file_t * f, const smba_stat_t * data, const QUAD * const size if(!f->server->server.prefer_core_protocol && f->server->server.protocol >= PROTOCOL_LANMAN2) result = smb_set_file_information (&f->server->server, &f->dirent, size, error_ptr); else - result = smb_proc_trunc (&f->server->server, f->dirent.fileid, size->Low, error_ptr); + result = smb_proc_trunc (&f->server->server, &f->dirent, size->Low, error_ptr); if(result < 0) goto out; diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h index 1d267a8..4812b16 100644 --- a/source_code/smbfs_rev.h +++ b/source_code/smbfs_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 155 -#define DATE "24.6.2018" -#define VERS "smbfs 1.155" -#define VSTRING "smbfs 1.155 (24.6.2018)\r\n" -#define VERSTAG "\0$VER: smbfs 1.155 (24.6.2018)" +#define REVISION 158 +#define DATE "27.6.2018" +#define VERS "smbfs 1.158" +#define VSTRING "smbfs 1.158 (27.6.2018)\r\n" +#define VERSTAG "\0$VER: smbfs 1.158 (27.6.2018)" diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev index bb79365..4c5c807 100644 --- a/source_code/smbfs_rev.rev +++ b/source_code/smbfs_rev.rev @@ -1 +1 @@ -155 +158