static int filesystem_copy(const char *name, const char *destname) { void *in, *out; ssize_t ret; size_t size; struct stat st; int in_fd, out_fd, err; in = filesystem_open(name, O_RDONLY, 0, NULL, &size, &err); if (in == NULL) { error("open(%s): %s (%d)", name, strerror(-err), -err); return -err; } in_fd = GPOINTER_TO_INT(in); ret = fstat(in_fd, &st); if (ret < 0) { error("stat(%s): %s (%d)", name, strerror(errno), errno); return -errno; } out = filesystem_open(destname, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode, NULL, &size, &err); if (out == NULL) { error("open(%s): %s (%d)", destname, strerror(-err), -err); filesystem_close(in); return -errno; } out_fd = GPOINTER_TO_INT(out); /* Check if sendfile is supported */ ret = sendfile(out_fd, in_fd, NULL, 0); if (ret < 0) { ret = -errno; error("sendfile: %s (%zd)", strerror(-ret), -ret); goto done; } ret = sendfile_async(out_fd, in_fd, NULL, st.st_size); if (ret < 0) goto done; return 0; done: filesystem_close(in); filesystem_close(out); return ret; }
static void handle_filesystem_request(int so) { int error; int operation; char key[(NAME_MAX + 1) + sizeof(union webdav_request)]; size_t num_bytes; char *bytes; union webdav_reply reply; /* get the request from the socket */ error = get_request(so, &operation, key, sizeof(key)); if ( !error ) { #if DEBUG LogMessage(kTrace, "handle_filesystem_request: %s(%d)\n", (operation==WEBDAV_LOOKUP) ? "LOOKUP" : (operation==WEBDAV_CREATE) ? "CREATE" : (operation==WEBDAV_OPEN) ? "OPEN" : (operation==WEBDAV_CLOSE) ? "CLOSE" : (operation==WEBDAV_GETATTR) ? "GETATTR" : (operation==WEBDAV_SETATTR) ? "SETATTR" : (operation==WEBDAV_READ) ? "READ" : (operation==WEBDAV_WRITE) ? "WRITE" : (operation==WEBDAV_FSYNC) ? "FSYNC" : (operation==WEBDAV_REMOVE) ? "REMOVE" : (operation==WEBDAV_RENAME) ? "RENAME" : (operation==WEBDAV_MKDIR) ? "MKDIR" : (operation==WEBDAV_RMDIR) ? "RMDIR" : (operation==WEBDAV_READDIR) ? "READDIR" : (operation==WEBDAV_STATFS) ? "STATFS" : (operation==WEBDAV_UNMOUNT) ? "UNMOUNT" : (operation==WEBDAV_INVALCACHES) ? "INVALCACHES" : "???", operation ); #endif bzero((void *)&reply, sizeof(union webdav_reply)); /* If the connection is down just return EBUSY, but always let UNMOUNT and INVALCACHES requests */ /* go through regardless of the state of the connection. */ if ( (get_connectionstate() == WEBDAV_CONNECTION_DOWN) && (operation != WEBDAV_UNMOUNT) && (operation != WEBDAV_INVALCACHES) ) { error = ETIMEDOUT; send_reply(so, (void *)&reply, sizeof(union webdav_reply), error); } else { /* call the function to handle the request */ switch ( operation ) { case WEBDAV_LOOKUP: error = filesystem_lookup((struct webdav_request_lookup *)key, (struct webdav_reply_lookup *)&reply); send_reply(so, (void *)&reply, sizeof(struct webdav_reply_lookup), error); break; case WEBDAV_CREATE: error = filesystem_create((struct webdav_request_create *)key, (struct webdav_reply_create *)&reply); send_reply(so, (void *)&reply, sizeof(struct webdav_reply_create), error); break; case WEBDAV_OPEN: error = filesystem_open((struct webdav_request_open *)key, (struct webdav_reply_open *)&reply); send_reply(so, (void *)&reply, sizeof(struct webdav_reply_open), error); break; case WEBDAV_CLOSE: error = filesystem_close((struct webdav_request_close *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_GETATTR: error = filesystem_getattr((struct webdav_request_getattr *)key, (struct webdav_reply_getattr *)&reply); send_reply(so, (void *)&reply, sizeof(struct webdav_reply_getattr), error); break; case WEBDAV_READ: bytes = NULL; num_bytes = 0; error = filesystem_read((struct webdav_request_read *)key, &bytes, &num_bytes); send_reply(so, (void *)bytes, (int)num_bytes, error); if (bytes) { free(bytes); } break; case WEBDAV_FSYNC: error = filesystem_fsync((struct webdav_request_fsync *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_REMOVE: error = filesystem_remove((struct webdav_request_remove *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_RENAME: error = filesystem_rename((struct webdav_request_rename *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_MKDIR: error = filesystem_mkdir((struct webdav_request_mkdir *)key, (struct webdav_reply_mkdir *)&reply); send_reply(so, (void *)&reply, sizeof(struct webdav_reply_mkdir), error); break; case WEBDAV_RMDIR: error = filesystem_rmdir((struct webdav_request_rmdir *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_READDIR: error = filesystem_readdir((struct webdav_request_readdir *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_STATFS: error = filesystem_statfs((struct webdav_request_statfs *)key, (struct webdav_reply_statfs *)&reply); send_reply(so, (void *)&reply, sizeof(struct webdav_reply_statfs), error); break; case WEBDAV_UNMOUNT: webdav_kill(-2); /* tell the main select loop to exit */ send_reply(so, (void *)0, 0, error); break; case WEBDAV_INVALCACHES: error = filesystem_invalidate_caches((struct webdav_request_invalcaches *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_WRITESEQ: error = filesystem_write_seq((struct webdav_request_writeseq *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_DUMP_COOKIES: dump_cookies((struct webdav_request_cookies *)key); send_reply(so, (void *)0, 0, error); break; case WEBDAV_CLEAR_COOKIES: reset_cookies((struct webdav_request_cookies *)key); send_reply(so, (void *)0, 0, error); break; default: error = ENOTSUP; break; } } #if DEBUG LogMessage(kError, "handle_filesystem_request: error %d, %s(%d)\n", error, (operation==WEBDAV_LOOKUP) ? "LOOKUP" : (operation==WEBDAV_CREATE) ? "CREATE" : (operation==WEBDAV_OPEN) ? "OPEN" : (operation==WEBDAV_CLOSE) ? "CLOSE" : (operation==WEBDAV_GETATTR) ? "GETATTR" : (operation==WEBDAV_SETATTR) ? "SETATTR" : (operation==WEBDAV_READ) ? "READ" : (operation==WEBDAV_WRITE) ? "WRITE" : (operation==WEBDAV_FSYNC) ? "FSYNC" : (operation==WEBDAV_REMOVE) ? "REMOVE" : (operation==WEBDAV_RENAME) ? "RENAME" : (operation==WEBDAV_MKDIR) ? "MKDIR" : (operation==WEBDAV_RMDIR) ? "RMDIR" : (operation==WEBDAV_READDIR) ? "READDIR" : (operation==WEBDAV_STATFS) ? "STATFS" : (operation==WEBDAV_UNMOUNT) ? "UNMOUNT" : (operation==WEBDAV_INVALCACHES) ? "INVALCACHES" : "???", operation ); #endif } else { LogMessage(kError, "handle_filesystem_request: get_request failed %d\n", error); send_reply(so, NULL, 0, error); } close(so); }