diff --git a/src/nwfile.c b/src/nwfile.c index b511b44..93de96b 100644 --- a/src/nwfile.c +++ b/src/nwfile.c @@ -1280,6 +1280,8 @@ int nw_log_logical_record(int lock_flag, static char *path_share_lock_files=NULL; uint8 fn[256]; uint8 fullpath[400]; + int original_len = len; + uint8 *original_data = data; uint32 offset; LOCK_FILE *lf = NULL; LOCK_AREA *la = NULL; @@ -1287,7 +1289,7 @@ int nw_log_logical_record(int lock_flag, flockd.l_whence = SEEK_SET; flockd.l_len = 1; - if (lock_flag != -1) { + if (lock_flag > -1) { if (share_set_logrec_add_rm(lock_flag, timeout, len, data)) return (-0xff); } @@ -1319,16 +1321,16 @@ int nw_log_logical_record(int lock_flag, if (len > 0) { int i=-1; if (len > sizeof(fn)) - len = sizeof(fn-1); + len = sizeof(fn)-1; memcpy(fn, data+4, len); while (++i < len) { if (fn[i]=='/') { fn[i] = '-'; - if (len < sizeof(fn-1)) + if (len < sizeof(fn)-1) fn[len++] = '_'; } else if (fn[i] == '\0') { fn[i] = '_'; - if (len < sizeof(fn-1)) + if (len < sizeof(fn)-1) fn[len++] = '_'; } } @@ -1354,8 +1356,10 @@ int nw_log_logical_record(int lock_flag, if (!lf) { int fd; - if (lock_flag < 0) /* unlock */ - return(-0xff); + if (lock_flag < 0) { /* unlock */ + share_set_logrec_add_rm(lock_flag, timeout, original_len, original_data); + return(0); + } if (seteuid(0)) {} fd = open(fullpath, O_RDWR|O_CREAT, 0600); @@ -1377,8 +1381,10 @@ int nw_log_logical_record(int lock_flag, la = find_lockarea(lf, offset); if (!la) { - if (lock_flag < 0) /* unlock */ - return (-0xff); + if (lock_flag < 0) { /* unlock */ + share_set_logrec_add_rm(lock_flag, timeout, original_len, original_data); + return(0); + } if (fcntl(lf->fd, F_SETLK, &flockd)) /* already locked by other process */ @@ -1427,6 +1433,7 @@ int nw_log_logical_record(int lock_flag, root_lf = lf->next; xfree(lf); } + share_set_logrec_add_rm(lock_flag, timeout, original_len, original_data); } return(0); } diff --git a/src/nwshare.c b/src/nwshare.c index f1014bb..63035b8 100644 --- a/src/nwshare.c +++ b/src/nwshare.c @@ -765,7 +765,19 @@ int share_set_file_add_rm(int lock_flag, dev_t dev, ino_t inode) int share_set_logrec_add_rm(int lock_flag, int timeout, int len, char *data) { if (lock_flag > -1) { - SHARESET *ps = (SHARESET*)xcmalloc(sizeof(SHARESET)); + SHARESET *ps; + for (ps = first_set; ps; ps = ps->next) { + if (ps->type == 2 && + ps->datalen == len && + !memcmp(ps->data, data, len)) { + if (lock_flag) { + ps->lock_flag = lock_flag; + ps->timeout = timeout; + } + return(0); + } + } + ps = (SHARESET*)xcmalloc(sizeof(SHARESET)); ps->next = first_set; first_set = ps; ps->type = 2; @@ -773,15 +785,25 @@ int share_set_logrec_add_rm(int lock_flag, int timeout, int len, char *data) ps->data = xcmalloc(len+1); memcpy(ps->data, data, len); ps->lock_flag = lock_flag; - } else if (lock_flag == -2) { + ps->timeout = timeout; + } else if (lock_flag == -1 || lock_flag == -2) { SHARESET **pset = &first_set; while (*pset) { SHARESET *ps = *pset; - *pset = (*pset)->next; - if (2 == ps->type) { + if (ps->type == 2 && + ps->datalen == len && + !memcmp(ps->data, data, len)) { + if (lock_flag == -1) { + ps->locked = 0; + pset = &ps->next; + continue; + } + *pset = ps->next; xfree(ps->data); xfree(ps); - } + continue; + } + pset = &ps->next; } } return(0); @@ -861,6 +883,3 @@ int share_handle_lock_sets(int type, int lock_flag, int timeout) } return(0); } - - - diff --git a/tests/ncp/ncp_pre22_smoke.c b/tests/ncp/ncp_pre22_smoke.c index dc973c7..9bd8072 100644 --- a/tests/ncp/ncp_pre22_smoke.c +++ b/tests/ncp/ncp_pre22_smoke.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -35,6 +37,8 @@ static void usage(const char *prog) " 21/00 Send Broadcast Message (old)\n" " 21/01 Get Broadcast Message (old)\n" " 21/02 Disable Broadcasts, 21/03 Enable Broadcasts\n" + " 03-08 old file log/lock/release/clear set\n" + " 09-0E old logical-record log/lock/release/clear set\n" "\n" "Example:\n" " %s -S MARS -U SUPERVISOR -P secret SYS:PUBLIC\n", @@ -46,6 +50,32 @@ static uint16_t be16_to_cpu(const uint8_t p[2]) return ((uint16_t)p[0] << 8) | (uint16_t)p[1]; } +static void cpu_to_be16(uint8_t p[2], uint16_t v) +{ + p[0] = (uint8_t)(v >> 8); + p[1] = (uint8_t)v; +} + +static int join_path(char *out, size_t out_size, const char *parent, + const char *leaf) +{ + const char *sep = ""; + size_t len = strlen(parent); + + if (len && parent[len - 1] != ':' && parent[len - 1] != '/' && + parent[len - 1] != '\\') + sep = "/"; + return snprintf(out, out_size, "%s%s%s", parent, sep, leaf) < (int)out_size + ? 0 : -1; +} + +static void generated_name(char *out, size_t out_size, const char *prefix) +{ + unsigned long seed = (unsigned long)time(NULL) ^ (unsigned long)getpid(); + + snprintf(out, out_size, "%s%06lu", prefix, seed % 1000000UL); +} + static long get_station_number(NWCONN_HANDLE conn, uint8_t *station) { uint8_t reply_buf[3]; @@ -120,6 +150,136 @@ static long check_volume_info(NWCONN_HANDLE conn, const char *path) return 0; } +static long request_no_reply(NWCONN_HANDLE conn, unsigned int function, + const uint8_t *request, size_t request_len) +{ + return NWRequestSimple(conn, function, (void *)request, request_len, NULL); +} + +static long check_old_file_locks(NWCONN_HANDLE conn, const char *parent_path) +{ + struct ncp_file_info finfo; + char leaf[16]; + char full_path[512]; + uint8_t request[5 + 255]; + uint8_t timeout[2]; + size_t path_len; + long err; + + generated_name(leaf, sizeof(leaf), "P22F"); + if (join_path(full_path, sizeof(full_path), parent_path, leaf)) + return NWE_INVALID_PATH; + + memset(&finfo, 0, sizeof(finfo)); + err = ncp_create_file(conn, 0, full_path, 0, &finfo); + if (err) + return err; + + path_len = strlen(full_path); + if (!path_len || path_len > 255) { + (void)ncp_erase_file(conn, 0, full_path, 0); + return NWE_INVALID_PATH; + } + + request[0] = 0; /* base directory handle; full volume path follows */ + request[1] = 0; /* log only */ + cpu_to_be16(request + 2, 0); + cpu_to_be16(timeout, 0); + request[4] = (uint8_t)path_len; + memcpy(request + 5, full_path, path_len); + + err = request_no_reply(conn, 0x03, request, 5 + path_len); + if (!err) + err = request_no_reply(conn, 0x04, timeout, sizeof(timeout)); + if (!err) { + request[0] = 0; + err = request_no_reply(conn, 0x06, request, 1); + } + if (!err) + err = request_no_reply(conn, 0x04, timeout, sizeof(timeout)); + if (!err) { + request[0] = 0; + request[1] = (uint8_t)path_len; + memcpy(request + 2, full_path, path_len); + err = request_no_reply(conn, 0x05, request, 2 + path_len); + } + if (!err) + err = request_no_reply(conn, 0x04, timeout, sizeof(timeout)); + if (!err) { + request[0] = 0; + request[1] = (uint8_t)path_len; + memcpy(request + 2, full_path, path_len); + err = request_no_reply(conn, 0x07, request, 2 + path_len); + } + if (!err) { + request[0] = 0; + err = request_no_reply(conn, 0x08, request, 1); + } + + (void)ncp_erase_file(conn, 0, full_path, 0); + if (err) + return err; + + printf("NCP 03-08 old file log/lock/release/clear path=%s\n", full_path); + return 0; +} + +static long check_old_logical_record_locks(NWCONN_HANDLE conn) +{ + char name[32]; + uint8_t request[4 + 128]; + size_t name_len; + long err; + + generated_name(name, sizeof(name), "P22L"); + name_len = strlen(name); + if (!name_len || name_len > 128) + return NWE_INVALID_PATH; + + request[0] = 0; /* log only */ + cpu_to_be16(request + 1, 0); + request[3] = (uint8_t)name_len; + memcpy(request + 4, name, name_len); + + err = request_no_reply(conn, 0x09, request, 4 + name_len); + if (!err) { + request[0] = 1; /* exclusive lock */ + err = request_no_reply(conn, 0x0a, request, 3); + } + if (!err) { + request[0] = 0; + err = request_no_reply(conn, 0x0d, request, 1); + } + if (!err) { + request[0] = 3; /* shared lock */ + err = request_no_reply(conn, 0x0a, request, 3); + } + if (!err) { + request[0] = (uint8_t)name_len; + memcpy(request + 1, name, name_len); + err = request_no_reply(conn, 0x0c, request, 1 + name_len); + } + if (!err) { + request[0] = 1; + err = request_no_reply(conn, 0x0a, request, 3); + } + if (!err) { + request[0] = (uint8_t)name_len; + memcpy(request + 1, name, name_len); + err = request_no_reply(conn, 0x0b, request, 1 + name_len); + } + if (!err) { + request[0] = 0; + err = request_no_reply(conn, 0x0e, request, 1); + } + if (err) + return err; + + printf("NCP 09-0E old logical-record log/lock/release/clear name=%s\n", + name); + return 0; +} + static long check_datetime(NWCONN_HANDLE conn) { uint8_t reply_buf[7]; @@ -271,6 +431,23 @@ int main(int argc, char **argv) return 1; } + err = check_old_file_locks(conn, path); + if (err) { + fprintf(stderr, "NCP 03-08 old file lock check failed: error=0x%04x\n", + (unsigned int)err); + ncp_close(conn); + return 1; + } + + err = check_old_logical_record_locks(conn); + if (err) { + fprintf(stderr, + "NCP 09-0E old logical-record lock check failed: error=0x%04x\n", + (unsigned int)err); + ncp_close(conn); + return 1; + } + ncp_close(conn); return 0; }