From 59e38dd7da762c29ad34f49417433427bdc02850 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 1 Nov 2015 03:49:26 +0100 Subject: [PATCH 1/3] kodi: add Bluray patches Signed-off-by: Stephan Raue --- .../patches/kodi-999.99-Bluray-fixes-1.patch | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 packages/mediacenter/kodi/patches/kodi-999.99-Bluray-fixes-1.patch diff --git a/packages/mediacenter/kodi/patches/kodi-999.99-Bluray-fixes-1.patch b/packages/mediacenter/kodi/patches/kodi-999.99-Bluray-fixes-1.patch new file mode 100644 index 0000000000..8ee06f12ca --- /dev/null +++ b/packages/mediacenter/kodi/patches/kodi-999.99-Bluray-fixes-1.patch @@ -0,0 +1,217 @@ +From f2d12c9b6fb41a1a920afa54beaae9045f11a3c5 Mon Sep 17 00:00:00 2001 +From: ace20022 +Date: Fri, 20 Mar 2015 16:38:47 +0100 +Subject: [PATCH 02/12] [curl][udf] The separator between the image path and + the file path (inside the image) must be '/'. + +--- + xbmc/URL.cpp | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/xbmc/URL.cpp b/xbmc/URL.cpp +index ac4a9c6..2ecf050 100644 +--- a/xbmc/URL.cpp ++++ b/xbmc/URL.cpp +@@ -160,6 +160,17 @@ void CURL::Parse(const std::string& strURL1) + return; + } + ++ if (IsProtocol("udf")) ++ { ++ std::string lower(strURL); ++ StringUtils::ToLower(lower); ++ size_t isoPos = lower.find(".iso\\", iPos); ++ if (isoPos != std::string::npos) ++ { ++ strURL = strURL.replace(isoPos + 4, 1, "/"); ++ } ++ } ++ + // check for username/password - should occur before first / + if (iPos == std::string::npos) iPos = 0; + + +From 4e38b5c178e089adc30c6f31d7a52b388c6e73f7 Mon Sep 17 00:00:00 2001 +From: ace20022 +Date: Tue, 9 Sep 2014 14:45:04 +0200 +Subject: [PATCH 03/12] [bluray] Add PLAYMARK event. + +--- + xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +index 544261c..ccbdbad 100644 +--- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp ++++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +@@ -586,6 +586,8 @@ void CDVDInputStreamBluray::ProcessEvent() { + case BD_EVENT_SECONDARY_VIDEO: + case BD_EVENT_SECONDARY_VIDEO_SIZE: + case BD_EVENT_SECONDARY_VIDEO_STREAM: ++ case BD_EVENT_PLAYMARK: ++ break; + + case BD_EVENT_NONE: + break; + +From 24e1fa5424ef73c8951f21081c95cb79df5e686f Mon Sep 17 00:00:00 2001 +From: ace20022 +Date: Thu, 6 Nov 2014 11:54:29 +0100 +Subject: [PATCH 04/12] [bluray] Move player setup to an own method and + refactor it. + +--- + .../DVDInputStreams/DVDInputStreamBluray.cpp | 32 +++++++++++++--------- + .../DVDInputStreams/DVDInputStreamBluray.h | 3 ++ + 2 files changed, 22 insertions(+), 13 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +index ccbdbad..cb8fff4 100644 +--- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp ++++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +@@ -384,19 +384,8 @@ bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content + + if(m_navmode) + { +- int region = CSettings::Get().GetInt("dvds.playerregion"); +- if(region == 0) +- { +- CLog::Log(LOGWARNING, "CDVDInputStreamBluray::Open - region dvd must be set in setting, assuming region 1"); +- region = 1; +- } +- m_dll->bd_set_player_setting (m_bd, BLURAY_PLAYER_SETTING_REGION_CODE, region); +- m_dll->bd_set_player_setting (m_bd, BLURAY_PLAYER_SETTING_PARENTAL, 0); +- m_dll->bd_set_player_setting (m_bd, BLURAY_PLAYER_SETTING_PLAYER_PROFILE, 0); +- m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_AUDIO_LANG, g_langInfo.GetDVDAudioLanguage().c_str()); +- m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_PG_LANG, g_langInfo.GetDVDSubtitleLanguage().c_str()); +- m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_MENU_LANG, g_langInfo.GetDVDMenuLanguage().c_str()); +- m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_COUNTRY_CODE, "us"); ++ SetupPlayerSettings(); ++ + m_dll->bd_register_overlay_proc (m_bd, this, bluray_overlay_cb); + #ifdef HAVE_LIBBLURAY_BDJ + m_dll->bd_register_argb_overlay_proc (m_bd, this, bluray_overlay_argb_cb, NULL); +@@ -1130,4 +1119,21 @@ bool CDVDInputStreamBluray::HasMenu() + return m_navmode; + } + ++void CDVDInputStreamBluray::SetupPlayerSettings() ++{ ++ int region = CSettings::Get().GetInt("dvds.playerregion"); ++ if (region == 0) ++ { ++ CLog::Log(LOGWARNING, "CDVDInputStreamBluray::Open - region dvd must be set in setting, assuming region 1"); ++ region = 1; ++ } ++ m_dll->bd_set_player_setting(m_bd, BLURAY_PLAYER_SETTING_REGION_CODE, region); ++ m_dll->bd_set_player_setting(m_bd, BLURAY_PLAYER_SETTING_PARENTAL, 0); ++ m_dll->bd_set_player_setting(m_bd, BLURAY_PLAYER_SETTING_PLAYER_PROFILE, 0); ++ m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_AUDIO_LANG, g_langInfo.GetDVDAudioLanguage().c_str()); ++ m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_PG_LANG, g_langInfo.GetDVDSubtitleLanguage().c_str()); ++ m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_MENU_LANG, g_langInfo.GetDVDMenuLanguage().c_str()); ++ m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_COUNTRY_CODE, "us"); ++} ++ + #endif +diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h +index f05c406..19a6f65 100644 +--- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h ++++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h +@@ -161,4 +161,7 @@ class CDVDInputStreamBluray + #ifdef HAVE_LIBBLURAY_BDJ + struct bd_argb_buffer_s m_argb; + #endif ++ ++ private: ++ void SetupPlayerSettings(); + }; + +From 0c3cb1e2deffd63a779fe58b586f3d34b077e854 Mon Sep 17 00:00:00 2001 +From: ace20022 +Date: Sun, 16 Nov 2014 16:53:43 +0100 +Subject: [PATCH 10/12] [bluray] Initialize m_angle. + +--- + xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +index 5031799..17a7318 100644 +--- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp ++++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +@@ -189,6 +189,7 @@ CDVDInputStreamBluray::CDVDInputStreamBluray(IDVDPlayer* player) : + { + m_title = NULL; + m_clip = (uint32_t)-1; ++ m_angle = 0; + m_playlist = (uint32_t)-1; + m_menu = false; + m_bd = NULL; + +From 10ea7cc8057604d960fd505c854cb7d745880dc3 Mon Sep 17 00:00:00 2001 +From: ace20022 +Date: Sat, 13 Sep 2014 14:13:34 +0200 +Subject: [PATCH 11/12] [bluray] Add Abort implementation. + +--- + xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp | 10 ++++++++-- + xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h | 4 +++- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +index 17a7318..c8abbc1 100644 +--- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp ++++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +@@ -216,6 +216,11 @@ CDVDInputStreamBluray::~CDVDInputStreamBluray() + delete m_dll; + } + ++void CDVDInputStreamBluray::Abort() ++{ ++ m_hold = HOLD_EXIT; ++} ++ + bool CDVDInputStreamBluray::IsEOF() + { + return false; +@@ -605,7 +610,8 @@ int CDVDInputStreamBluray::Read(uint8_t* buf, int buf_size) + if(m_hold == HOLD_HELD) + return 0; + +- if(m_hold == HOLD_ERROR) ++ if( m_hold == HOLD_ERROR ++ || m_hold == HOLD_EXIT) + return -1; + + result = m_dll->bd_read_ext (m_bd, buf, buf_size, &m_event); +@@ -1011,7 +1017,7 @@ void CDVDInputStreamBluray::GetStreamInfo(int pid, char* language) + + CDVDInputStream::ENextStream CDVDInputStreamBluray::NextStream() + { +- if(!m_navmode) ++ if(!m_navmode || m_hold == HOLD_EXIT) + return NEXTSTREAM_NONE; + + if (m_hold == HOLD_ERROR) +diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h +index af06e82..b41f64c 100644 +--- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h ++++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h +@@ -54,6 +54,7 @@ class CDVDInputStreamBluray + virtual int Read(uint8_t* buf, int buf_size); + virtual int64_t Seek(int64_t offset, int whence); + virtual bool Pause(double dTime) { return false; }; ++ void Abort(); + virtual bool IsEOF(); + virtual int64_t GetLength(); + virtual int GetBlockSize() { return 6144; } +@@ -156,7 +157,8 @@ class CDVDInputStreamBluray + HOLD_HELD, + HOLD_DATA, + HOLD_STILL, +- HOLD_ERROR ++ HOLD_ERROR, ++ HOLD_EXIT + } m_hold; + BD_EVENT m_event; + #ifdef HAVE_LIBBLURAY_BDJ From 257e39416b82874feffbb8f04aac484c59f7da38 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 1 Nov 2015 03:50:01 +0100 Subject: [PATCH 2/3] libbluray: update to libbluray-0.9.0 Signed-off-by: Stephan Raue --- packages/multimedia/libbluray/package.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multimedia/libbluray/package.mk b/packages/multimedia/libbluray/package.mk index 8ae12c4427..ffec405df8 100644 --- a/packages/multimedia/libbluray/package.mk +++ b/packages/multimedia/libbluray/package.mk @@ -17,7 +17,7 @@ ################################################################################ PKG_NAME="libbluray" -PKG_VERSION="0.8.1" +PKG_VERSION="0.9.0" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" From 5a506f85774078b0ae1a983834ae38d4ee6802dc Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 1 Nov 2015 03:50:26 +0100 Subject: [PATCH 3/3] libnfs: add libnfs upstream patches Signed-off-by: Stephan Raue --- .../libnfs/patches/libnfs-master.patch | 1262 +++++++++++++++++ 1 file changed, 1262 insertions(+) create mode 100644 packages/network/libnfs/patches/libnfs-master.patch diff --git a/packages/network/libnfs/patches/libnfs-master.patch b/packages/network/libnfs/patches/libnfs-master.patch new file mode 100644 index 0000000000..a11f6cb4a7 --- /dev/null +++ b/packages/network/libnfs/patches/libnfs-master.patch @@ -0,0 +1,1262 @@ +From b319b976dc9d02c894daed35a8bd056ca56b1328 Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Tue, 4 Aug 2015 14:55:28 +0200 +Subject: [PATCH 02/22] socket: handle count == 0 in rpc_read_from_socket + +An EOF is signalled through a POLLIN event and subsequen recvs return +always 0. Handle this condition and reconnect. Otherwise we might +deadlock here. + +Signed-off-by: Peter Lieven +--- + lib/socket.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/lib/socket.c b/lib/socket.c +index 3937e2f..9de580e 100644 +--- a/lib/socket.c ++++ b/lib/socket.c +@@ -249,6 +249,12 @@ static int rpc_read_from_socket(struct rpc_context *rpc) + rpc_set_error(rpc, "Read from socket failed, errno:%d. Closing socket.", errno); + return -1; + } ++ ++ if (count == 0) { ++ /* remote side has closed the socket. Reconnect. */ ++ return -1; ++ } ++ + rpc->inpos += count; + + while (rpc->inpos >= 4) { + +From aacee393caf013ead4e76906b881e77b229109bd Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Thu, 6 Aug 2015 09:53:49 +0200 +Subject: [PATCH 03/22] socket: also reconnect on write errors + +This also return -1 for rpc_service if rpc_reconnect_requeue fails. + +Signed-off-by: Peter Lieven +--- + lib/socket.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/lib/socket.c b/lib/socket.c +index 9de580e..f0ba682 100644 +--- a/lib/socket.c ++++ b/lib/socket.c +@@ -345,15 +345,13 @@ int rpc_service(struct rpc_context *rpc, int revents) + + if (revents & POLLIN) { + if (rpc_read_from_socket(rpc) != 0) { +- rpc_reconnect_requeue(rpc); +- return 0; ++ return rpc_reconnect_requeue(rpc); + } + } + + if (revents & POLLOUT && rpc_has_queue(&rpc->outqueue)) { + if (rpc_write_to_socket(rpc) != 0) { +- rpc_set_error(rpc, "write to socket failed"); +- return -1; ++ return rpc_reconnect_requeue(rpc); + } + } + + +From 29ab169d2bf29b8f9487d070571c1c751aa2567e Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Thu, 6 Aug 2015 10:10:45 +0200 +Subject: [PATCH 04/22] init: do not write to stderr in rpc_set_error + +only log error if debug >= 1. + +Signed-off-by: Peter Lieven +--- + lib/init.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/init.c b/lib/init.c +index b898c39..874b027 100644 +--- a/lib/init.c ++++ b/lib/init.c +@@ -168,7 +168,7 @@ void rpc_set_error(struct rpc_context *rpc, const char *error_string, ...) + vsnprintf(rpc->error_string, 1024, error_string, ap); + va_end(ap); + +- fprintf(stderr, "libnfs error: %s\n", rpc->error_string); ++ RPC_LOG(rpc, 1, "error: %s", rpc->error_string); + + if (old_error_string != NULL) { + free(old_error_string); + +From 5c7a0f04e68e9c186ede5ee11e1944e66f85c528 Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Fri, 28 Aug 2015 21:13:37 +0200 +Subject: [PATCH 06/22] socket: fix deadlock in rpc_reconnect_requeue + +the requeueing code is broken because we access pdu->next +after we mangled it in rpc_return_to_queue. + +This leads to losing of waitqueue elements and more severe +a deadlock as soon as more than one waitpdu queue has elements. + +Reason for that is that the first elements of the first +two queues are linked to each other. + +Example: +waitpdu[0]->head = pduA ; pduA->next = pduB; pduB->next = NULL; +waitpdu[1]->head = pduC ; pduC->next = NULL; +outqueue->head = NULL; + +After the for loop for waitpdu[0] queue the outqueue looks like + +outqueue->head = pduA; pduA->next = NULL; + +At this point pduB is lost! + +In the for loop for waitpdu[1] queue the outqueue looks like this +after the first iteration: + +outqueue->head = pduC; pduC->next = pduA; pduA->next = NULL; + +We now fetch pdu->next of pduC which is pduA. + +In the next iteration we put pduA in front of pduC. pduA->next +is then pduC and pduC->next is pduA. => Deadlock. + +Signed-off-by: Peter Lieven +--- + lib/socket.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/lib/socket.c b/lib/socket.c +index 9de580e..a9d675d 100644 +--- a/lib/socket.c ++++ b/lib/socket.c +@@ -585,7 +585,7 @@ static void reconnect_cb(struct rpc_context *rpc, int status, void *data _U_, vo + /* disconnect but do not error all PDUs, just move pdus in-flight back to the outqueue and reconnect */ + static int rpc_reconnect_requeue(struct rpc_context *rpc) + { +- struct rpc_pdu *pdu; ++ struct rpc_pdu *pdu, *next; + unsigned int i; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); +@@ -606,8 +606,8 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc) + */ + for (i = 0; i < HASHES; i++) { + struct rpc_queue *q = &rpc->waitpdu[i]; +- +- for (pdu=q->head; pdu; pdu=pdu->next) { ++ for (pdu = q->head; pdu; pdu = next) { ++ next = pdu->next; + rpc_return_to_queue(&rpc->outqueue, pdu); + /* we have to re-send the whole pdu again */ + pdu->written = 0; + +From c078a42353fbc3f182256b62af80e185034de337 Mon Sep 17 00:00:00 2001 +From: Ronnie Sahlberg +Date: Sun, 6 Sep 2015 06:50:22 -0700 +Subject: [PATCH 07/22] Fix OSX build. + +Signed-off-by: Ronnie Sahlberg +--- + utils/nfs-cp.c | 6 +++--- + utils/nfs-ls.c | 3 ++- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/utils/nfs-cp.c b/utils/nfs-cp.c +index d862e46..582fe3c 100644 +--- a/utils/nfs-cp.c ++++ b/utils/nfs-cp.c +@@ -104,9 +104,9 @@ fstat_file(struct file_context *fc, struct stat *st) + st->st_size = nfs_st.nfs_size; + st->st_blksize = nfs_st.nfs_blksize; + st->st_blocks = nfs_st.nfs_blocks; +- st->st_atim.tv_sec = nfs_st.nfs_atime; +- st->st_mtim.tv_sec = nfs_st.nfs_mtime; +- st->st_ctim.tv_sec = nfs_st.nfs_ctime; ++ st->st_atime = nfs_st.nfs_atime; ++ st->st_mtime = nfs_st.nfs_mtime; ++ st->st_ctime = nfs_st.nfs_ctime; + + return res; + } +diff --git a/utils/nfs-ls.c b/utils/nfs-ls.c +index a989891..a854dfc 100644 +--- a/utils/nfs-ls.c ++++ b/utils/nfs-ls.c +@@ -255,7 +255,8 @@ int main(int argc, char *argv[]) + goto finished; + } + printf("\n%12" PRId64 " of %12" PRId64 " bytes free.\n", +- stvfs.f_frsize * stvfs.f_bfree, stvfs.f_frsize * stvfs.f_blocks); ++ (uint64_t)(stvfs.f_frsize * stvfs.f_bfree), ++ (uint64_t)(stvfs.f_frsize * stvfs.f_blocks)); + } + + ret = 0; + +From e81f9e23ab220d7770523d0ec559d74ad5eab4c4 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 00:22:07 +0200 +Subject: [PATCH 08/22] fuse_nfs: Consider st_.tim as struct timespec + +At least in my version of glibc the members st_mtim, st_ctim and st_atim +are defined as struct timespec rather than struct timeval, thus +containing a tv_nsec field rather than tv_usec. + +Use the proper struct fields instead, fixing compilation on Linux. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index 635cca1..fd4b8ee 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -51,11 +51,11 @@ static int fuse_nfs_getattr(const char *path, struct stat *stbuf) + stbuf->st_blksize = nfs_st.nfs_blksize; + stbuf->st_blocks = nfs_st.nfs_blocks; + stbuf->st_atim.tv_sec = nfs_st.nfs_atime; +- stbuf->st_atim.tv_usec = nfs_st.nfs_atime_nsec / 1000; ++ stbuf->st_atim.tv_nsec = nfs_st.nfs_atime_nsec; + stbuf->st_mtim.tv_sec = nfs_st.nfs_mtime; +- stbuf->st_mtim.tv_usec = nfs_st.nfs_mtime_nsec / 1000; ++ stbuf->st_mtim.tv_nsec = nfs_st.nfs_mtime_nsec; + stbuf->st_ctim.tv_sec = nfs_st.nfs_ctime; +- stbuf->st_ctim.tv_usec = nfs_st.nfs_ctime_nsec / 1000; ++ stbuf->st_ctim.tv_nsec = nfs_st.nfs_ctime_nsec; + + return ret; + } + +From 39d1f3693cdb3d779f2a39286daf3a3f0d327bbd Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 00:23:46 +0200 +Subject: [PATCH 09/22] fuse_nfs: Add symlink support + +The fuse framework allows us to directly expose symlinks from NFS to the user, +just like a real NFS mount would. All we need to do is call lstat rather +than stat and implement a readlink function. + +With this patch I can successfully chroot into a rootfs mounted using +fuse_nfs. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index fd4b8ee..5d82b69 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -38,7 +38,7 @@ static int fuse_nfs_getattr(const char *path, struct stat *stbuf) + int ret = 0; + struct nfs_stat_64 nfs_st; + +- ret = nfs_stat64(nfs, path, &nfs_st); ++ ret = nfs_lstat64(nfs, path, &nfs_st); + + stbuf->st_dev = nfs_st.nfs_dev; + stbuf->st_ino = nfs_st.nfs_ino; +@@ -79,6 +79,11 @@ static int fuse_nfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + return ret; + } + ++static int fuse_nfs_readlink(const char *path, char *buf, size_t size) ++{ ++ return nfs_readlink(nfs, path, buf, size); ++} ++ + static int fuse_nfs_open(const char *path, struct fuse_file_info *fi) + { + int ret = 0; +@@ -199,6 +204,7 @@ static struct fuse_operations nfs_oper = { + .open = fuse_nfs_open, + .read = fuse_nfs_read, + .readdir = fuse_nfs_readdir, ++ .readlink = fuse_nfs_readlink, + .release = fuse_nfs_release, + .rmdir = fuse_nfs_rmdir, + .unlink = fuse_nfs_unlink, + +From 618b6ea03057da666319ff346382f353ff6641b3 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 11:19:50 +0200 +Subject: [PATCH 10/22] fuse_nfs: Add mknod + +Libnfs already has exports for mknod, hook them up to the fuse example. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index 5d82b69..3c0e553 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -197,10 +197,16 @@ static int fuse_nfs_mkdir(const char *path, mode_t mode) + return ret; + } + ++static int fuse_nfs_mknod(const char *path, mode_t mode, dev_t rdev) ++{ ++ return nfs_mknod(nfs, path, mode, rdev); ++} ++ + static struct fuse_operations nfs_oper = { + .create = fuse_nfs_create, + .getattr = fuse_nfs_getattr, + .mkdir = fuse_nfs_mkdir, ++ .mknod = fuse_nfs_mknod, + .open = fuse_nfs_open, + .read = fuse_nfs_read, + .readdir = fuse_nfs_readdir, + +From 50aabd0729e9e443bf61dbd550e48f4d23fba26e Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 11:20:42 +0200 +Subject: [PATCH 11/22] fuse_nfs: Add symlink + +Libnfs already has exports for symlink, hook them up to the fuse example. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index 3c0e553..759f35b 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -202,6 +202,11 @@ static int fuse_nfs_mknod(const char *path, mode_t mode, dev_t rdev) + return nfs_mknod(nfs, path, mode, rdev); + } + ++static int fuse_nfs_symlink(const char *from, const char *to) ++{ ++ return nfs_symlink(nfs, from, to); ++} ++ + static struct fuse_operations nfs_oper = { + .create = fuse_nfs_create, + .getattr = fuse_nfs_getattr, +@@ -215,6 +220,7 @@ static struct fuse_operations nfs_oper = { + .rmdir = fuse_nfs_rmdir, + .unlink = fuse_nfs_unlink, + .utime = fuse_nfs_utime, ++ .symlink = fuse_nfs_symlink, + .write = fuse_nfs_write, + }; + + +From 37fd16ee087472dbbdb7bc7c10781a7ff91a3764 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 11:21:30 +0200 +Subject: [PATCH 12/22] fuse_nfs: Add rename + +Libnfs already has exports for rename, hook them up to the fuse example. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index 759f35b..647de2e 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -207,6 +207,11 @@ static int fuse_nfs_symlink(const char *from, const char *to) + return nfs_symlink(nfs, from, to); + } + ++static int fuse_nfs_rename(const char *from, const char *to) ++{ ++ return nfs_rename(nfs, from, to); ++} ++ + static struct fuse_operations nfs_oper = { + .create = fuse_nfs_create, + .getattr = fuse_nfs_getattr, +@@ -220,6 +225,7 @@ static struct fuse_operations nfs_oper = { + .rmdir = fuse_nfs_rmdir, + .unlink = fuse_nfs_unlink, + .utime = fuse_nfs_utime, ++ .rename = fuse_nfs_rename, + .symlink = fuse_nfs_symlink, + .write = fuse_nfs_write, + }; + +From d1709ab57371080ed699667b7bed13abfca6154c Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 11:22:27 +0200 +Subject: [PATCH 13/22] fuse_nfs: Add link + +Libnfs already has exports for link, hook them up to the fuse example. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index 647de2e..b40fa73 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -212,9 +212,15 @@ static int fuse_nfs_rename(const char *from, const char *to) + return nfs_rename(nfs, from, to); + } + ++static int fuse_nfs_link(const char *from, const char *to) ++{ ++ return nfs_link(nfs, from, to); ++} ++ + static struct fuse_operations nfs_oper = { + .create = fuse_nfs_create, + .getattr = fuse_nfs_getattr, ++ .link = fuse_nfs_link, + .mkdir = fuse_nfs_mkdir, + .mknod = fuse_nfs_mknod, + .open = fuse_nfs_open, + +From 315112b923cd7845ce9703e60e0c30e582e93c39 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 11:23:02 +0200 +Subject: [PATCH 14/22] fuse_nfs: Add chmod + +Libnfs already has exports for chmod, hook them up to the fuse example. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index b40fa73..ad15579 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -217,7 +217,13 @@ static int fuse_nfs_link(const char *from, const char *to) + return nfs_link(nfs, from, to); + } + ++static int fuse_nfs_chmod(const char *path, mode_t mode) ++{ ++ return nfs_chmod(nfs, path, mode); ++} ++ + static struct fuse_operations nfs_oper = { ++ .chmod = fuse_nfs_chmod, + .create = fuse_nfs_create, + .getattr = fuse_nfs_getattr, + .link = fuse_nfs_link, + +From b66121610d21e8e5187dd16691d15e159e0cfcd8 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 11:23:34 +0200 +Subject: [PATCH 15/22] fuse_nfs: Add chown + +Libnfs already has exports for chown, hook them up to the fuse example. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index ad15579..d84b590 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -222,8 +222,14 @@ static int fuse_nfs_chmod(const char *path, mode_t mode) + return nfs_chmod(nfs, path, mode); + } + ++static int fuse_nfs_chown(const char *path, uid_t uid, gid_t gid) ++{ ++ return nfs_chown(nfs, path, uid, gid); ++} ++ + static struct fuse_operations nfs_oper = { + .chmod = fuse_nfs_chmod, ++ .chown = fuse_nfs_chown, + .create = fuse_nfs_create, + .getattr = fuse_nfs_getattr, + .link = fuse_nfs_link, + +From 9439361243c7e35a2cfcb66fad21a107e5e64609 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 11:24:07 +0200 +Subject: [PATCH 16/22] fuse_nfs: Add truncate + +Libnfs already has exports for truncate, hook them up to the fuse example. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index d84b590..acc8806 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -227,6 +227,11 @@ static int fuse_nfs_chown(const char *path, uid_t uid, gid_t gid) + return nfs_chown(nfs, path, uid, gid); + } + ++static int fuse_nfs_truncate(const char *path, off_t size) ++{ ++ return nfs_truncate(nfs, path, size); ++} ++ + static struct fuse_operations nfs_oper = { + .chmod = fuse_nfs_chmod, + .chown = fuse_nfs_chown, +@@ -245,6 +250,7 @@ static struct fuse_operations nfs_oper = { + .utime = fuse_nfs_utime, + .rename = fuse_nfs_rename, + .symlink = fuse_nfs_symlink, ++ .truncate = fuse_nfs_truncate, + .write = fuse_nfs_write, + }; + + +From 883f660430f1be1f7796c275f4ae0d85101ed478 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Fri, 11 Sep 2015 11:24:45 +0200 +Subject: [PATCH 17/22] fuse_nfs: Add fsync + +Libnfs already has exports for fsync, hook them up to the fuse example. + +Signed-off-by: Alexander Graf +--- + examples/fuse_nfs.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +index acc8806..5f7eb7b 100644 +--- a/examples/fuse_nfs.c ++++ b/examples/fuse_nfs.c +@@ -232,10 +232,19 @@ static int fuse_nfs_truncate(const char *path, off_t size) + return nfs_truncate(nfs, path, size); + } + ++static int fuse_nfs_fsync(const char *path, int isdatasync, ++ struct fuse_file_info *fi) ++{ ++ struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; ++ ++ return nfs_fsync(nfs, nfsfh); ++} ++ + static struct fuse_operations nfs_oper = { + .chmod = fuse_nfs_chmod, + .chown = fuse_nfs_chown, + .create = fuse_nfs_create, ++ .fsync = fuse_nfs_fsync, + .getattr = fuse_nfs_getattr, + .link = fuse_nfs_link, + .mkdir = fuse_nfs_mkdir, + +From 7b7aef6b6d48c5403f939449aa0f88cd82c54c7d Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Tue, 22 Sep 2015 14:40:59 +0200 +Subject: [PATCH 18/22] socket: keep reconnecting if a reconnect fails + +otherwise we end up eating up all socket errors in rpc_service and then +believe we are connected, but the next call to rpc_read_from_socket +fails because the socket is closed. we then reconnect anyway. + +Signed-off-by: Peter Lieven +--- + lib/socket.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/socket.c b/lib/socket.c +index d578cc2..091d195 100644 +--- a/lib/socket.c ++++ b/lib/socket.c +@@ -336,7 +336,7 @@ int rpc_service(struct rpc_context *rpc, int revents) + } + + rpc->is_connected = 1; +- RPC_LOG(rpc, 2, "connection established"); ++ RPC_LOG(rpc, 2, "connection established on fd %d", rpc->fd); + if (rpc->connect_cb != NULL) { + rpc->connect_cb(rpc, RPC_STATUS_SUCCESS, NULL, rpc->connect_data); + } +@@ -572,7 +572,8 @@ static void reconnect_cb(struct rpc_context *rpc, int status, void *data _U_, vo + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (status != RPC_STATUS_SUCCESS) { +- rpc_error_all_pdus(rpc, "RPC ERROR: Failed to reconnect async"); ++ rpc_set_error(rpc, "Failed to reconnect async"); ++ rpc_reconnect_requeue(rpc); + return; + } + + +From ddd9e2f7e9b14248da45fbe9d02e188751206950 Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Tue, 22 Sep 2015 14:54:48 +0200 +Subject: [PATCH 19/22] socket: keep fd the same across reconnects + +There is no guarantee that we get the same fd again when +reestablishing a session. But if the fd changes during a +reconnect we might up with a client application busy polling +on the old fd. + +Qemu registers a read handler on the current fd, but is +not realizing fd changes. So we busy poll on the old fd for good. +Things are working (except for the busy polling) until +a drain all is issued. At this point Qemu deadlocks. + +Signed-off-by: Peter Lieven +--- + include/libnfs-private.h | 1 + + lib/socket.c | 15 ++++++++++++++- + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/include/libnfs-private.h b/include/libnfs-private.h +index bc84f53..6d778c6 100644 +--- a/include/libnfs-private.h ++++ b/include/libnfs-private.h +@@ -79,6 +79,7 @@ struct rpc_queue { + struct rpc_context { + uint32_t magic; + int fd; ++ int old_fd; + int is_connected; + + char *error_string; +diff --git a/lib/socket.c b/lib/socket.c +index 091d195..b409cf6 100644 +--- a/lib/socket.c ++++ b/lib/socket.c +@@ -132,6 +132,10 @@ int rpc_get_fd(struct rpc_context *rpc) + { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + ++ if (rpc->old_fd) { ++ return rpc->old_fd; ++ } ++ + return rpc->fd; + } + +@@ -418,6 +422,14 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s + return -1; + } + ++ if (rpc->old_fd) { ++ if (dup2(rpc->fd, rpc->old_fd) == -1) { ++ return -1; ++ } ++ close(rpc->fd); ++ rpc->fd = rpc->old_fd; ++ } ++ + /* Some systems allow you to set capabilities on an executable + * to allow the file to be executed with privilege to bind to + * privileged system ports, even if the user is not root. +@@ -579,6 +591,7 @@ static void reconnect_cb(struct rpc_context *rpc, int status, void *data _U_, vo + + rpc->is_connected = 1; + rpc->connect_cb = NULL; ++ rpc->old_fd = 0; + } + + /* disconnect but do not error all PDUs, just move pdus in-flight back to the outqueue and reconnect */ +@@ -590,7 +603,7 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc) + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (rpc->fd != -1) { +- close(rpc->fd); ++ rpc->old_fd = rpc->fd; + } + rpc->fd = -1; + rpc->is_connected = 0; + +From d73d4f3305aaf962635abb9f5b5233cc23dd4747 Mon Sep 17 00:00:00 2001 +From: Ronnie Sahlberg +Date: Wed, 14 Oct 2015 06:44:22 -0700 +Subject: [PATCH 20/22] rpc_reconnect_requeue: return -1 if autoreconnect is + not enabled + +This funciton is called from rpc_service when it has detected that +a socket has errored out during reading/writing. +However, since this fucntion returns 0 (==success) for the case where +autoreconnect is not enabled, this means that for an errored socket we +will return 0 (==success) from rpc_service() back to the application. + +Change rpc_reconnect_requeue to return -1 when invoked and autoreconnect +is disabled so that applications will receive an error back from rpc_service. + +Signed-off-by: Ronnie Sahlberg +--- + lib/socket.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/socket.c b/lib/socket.c +index b409cf6..72ffe92 100644 +--- a/lib/socket.c ++++ b/lib/socket.c +@@ -636,6 +636,7 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc) + } + } else { + RPC_LOG(rpc, 1, "reconnect NOT initiated, auto-reconnect is disabled"); ++ return -1; + } + + return 0; + +From 4d102bd24dc2b48f67db055251bf6763faeaa8a4 Mon Sep 17 00:00:00 2001 +From: Ronnie Sahlberg +Date: Wed, 14 Oct 2015 07:01:10 -0700 +Subject: [PATCH 21/22] Improve the documentation for + *_get_fd/*_which_events/*_service + +Signed-off-by: Ronnie Sahlberg +--- + include/nfsc/libnfs-raw.h | 33 +++++++++++++++++++++++++++++++-- + include/nfsc/libnfs.h | 25 ++++++++++++++++++++++++- + 2 files changed, 55 insertions(+), 3 deletions(-) + +diff --git a/include/nfsc/libnfs-raw.h b/include/nfsc/libnfs-raw.h +index 1556f54..ce88dd2 100644 +--- a/include/nfsc/libnfs-raw.h ++++ b/include/nfsc/libnfs-raw.h +@@ -40,13 +40,42 @@ void rpc_destroy_context(struct rpc_context *rpc); + + void rpc_set_auth(struct rpc_context *rpc, struct AUTH *auth); + ++/* ++ * Used for interfacing the api into an external eventsystem. ++ * ++ * rpc_get_fd() returns the file descriptor for the context we need to ++ * listen for events from. ++ * ++ * rpc_which_events() returns which events that we need to poll for. ++ * This is a combination of the POLLIN and POLLOUT flags. ++ * ++ * rpc_service() This function should be called once there are events triggered ++ * for the filedescriptor. This function takes POLLIN/POLLOUT/POLLHUP/POLLERR ++ * as arguments. ++ * This function returns 0 on success or -1 on error. If it returns -1 it ++ * means that the socket is in an unrecoverable error state (disconnected?) ++ * and that no further commands can be used. ++ * When this happens the application should destroy the now errored context ++ * re-create a new context and reconnect. ++ * ++ */ + int rpc_get_fd(struct rpc_context *rpc); + int rpc_which_events(struct rpc_context *rpc); + int rpc_service(struct rpc_context *rpc, int revents); +-char *rpc_get_error(struct rpc_context *rpc); ++ ++/* ++ * Returns the number of commands in-flight. Can be used by the application ++ * to check if there are any more responses we are awaiting for the server ++ * or if the connection is completely idle. ++ */ + int rpc_queue_length(struct rpc_context *rpc); + +-/* Utility function to get an RPC context from a NFS context. Useful for doing low level NFSACL ++/* ++ * When an operation failed, this function can extract a detailed error string. ++ */ ++char *rpc_get_error(struct rpc_context *rpc); ++ ++ /* Utility function to get an RPC context from a NFS context. Useful for doing low level NFSACL + * calls on a NFS context. + */ + struct rpc_context *nfs_get_rpc_context(struct nfs_context *nfs); +diff --git a/include/nfsc/libnfs.h b/include/nfsc/libnfs.h +index 356263c..55cec1d 100644 +--- a/include/nfsc/libnfs.h ++++ b/include/nfsc/libnfs.h +@@ -79,11 +79,34 @@ struct utimbuf { + #endif + + /* +- * Used for interfacing the async version of the api into an external eventsystem ++ * Used for interfacing the async version of the api into an external ++ * eventsystem. ++ * ++ * nfs_get_fd() returns the file descriptor for the context we need to ++ * listen for events from. ++ * ++ * nfs_which_events() returns which events that we need to poll for. ++ * This is a combination of the POLLIN and POLLOUT flags. ++ * ++ * nfs_service() This function should be called once there are events triggered ++ * for the filedescriptor. This function takes POLLIN/POLLOUT/POLLHUP/POLLERR ++ * as arguments. ++ * This function returns 0 on success or -1 on error. If it returns -1 it ++ * means that the socket is in an unrecoverable error state (disconnected?) ++ * and that no further commands can be used. ++ * When this happens the application should destroy the now errored context ++ * re-create a new context and reconnect. ++ * + */ + EXTERN int nfs_get_fd(struct nfs_context *nfs); + EXTERN int nfs_which_events(struct nfs_context *nfs); + EXTERN int nfs_service(struct nfs_context *nfs, int revents); ++ ++/* ++ * Returns the number of commands in-flight. Can be used by the application ++ * to check if there are any more responses we are awaiting for the server ++ * or if the connection is completely idle. ++ */ + EXTERN int nfs_queue_length(struct nfs_context *nfs); + + /* + +From dc8d86628d2f67cb4b7a9e5e5d7a1259f065b3c7 Mon Sep 17 00:00:00 2001 +From: Ronnie Sahlberg +Date: Mon, 19 Oct 2015 18:59:38 -0700 +Subject: [PATCH 22/22] Remove FUSE NFS filesystem + +Remove the fuse module from the examples subdirectory. +This module is now a standalone repo : +https://github.com/sahlberg/fuse-nfs + +And it comes with proper build rules, documentation etc etc. +It is a useful module and it has now graduated to become its own +repo. + +Signed-off-by: Ronnie Sahlberg +--- + README | 8 -- + examples/fuse_nfs.c | 397 ---------------------------------------------------- + 2 files changed, 405 deletions(-) + delete mode 100644 examples/fuse_nfs.c + +diff --git a/README b/README +index 01c0654..34715f4 100644 +--- a/README ++++ b/README +@@ -90,14 +90,6 @@ manpages by running + cd doc + make doc + +-FUSE +-==== +-A simple FUSE filesystem built on libnfs can be found in +-examples/fuse_nfs.c +- +-Compile using : gcc fuse_nfs.c -o fuse_nfs -lfuse -lnfs +-Mount using : sudo ./fuse_nfs -n nfs:/// -m +- + + PLATFORM support + ================= +diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c +deleted file mode 100644 +index 5f7eb7b..0000000 +--- a/examples/fuse_nfs.c ++++ /dev/null +@@ -1,397 +0,0 @@ +-/* +- Copyright (C) by Ronnie Sahlberg 2013 +- +- This program is free software; you can redistribute it and/or modify +- it under the terms of the GNU General Public License as published by +- the Free Software Foundation; either version 3 of the License, or +- (at your option) any later version. +- +- This program is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- GNU General Public License for more details. +- +- You should have received a copy of the GNU General Public License +- along with this program; if not, see . +-*/ +-/* A FUSE filesystem based on libnfs. */ +- +-#define FUSE_USE_VERSION 26 +-#define _FILE_OFFSET_BITS 64 +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-#define discard_const(ptr) ((void *)((intptr_t)(ptr))) +- +-struct nfs_context *nfs = NULL; +- +-static int fuse_nfs_getattr(const char *path, struct stat *stbuf) +-{ +- int ret = 0; +- struct nfs_stat_64 nfs_st; +- +- ret = nfs_lstat64(nfs, path, &nfs_st); +- +- stbuf->st_dev = nfs_st.nfs_dev; +- stbuf->st_ino = nfs_st.nfs_ino; +- stbuf->st_mode = nfs_st.nfs_mode; +- stbuf->st_nlink = nfs_st.nfs_nlink; +- stbuf->st_uid = nfs_st.nfs_uid; +- stbuf->st_gid = nfs_st.nfs_gid; +- stbuf->st_rdev = nfs_st.nfs_rdev; +- stbuf->st_size = nfs_st.nfs_size; +- stbuf->st_blksize = nfs_st.nfs_blksize; +- stbuf->st_blocks = nfs_st.nfs_blocks; +- stbuf->st_atim.tv_sec = nfs_st.nfs_atime; +- stbuf->st_atim.tv_nsec = nfs_st.nfs_atime_nsec; +- stbuf->st_mtim.tv_sec = nfs_st.nfs_mtime; +- stbuf->st_mtim.tv_nsec = nfs_st.nfs_mtime_nsec; +- stbuf->st_ctim.tv_sec = nfs_st.nfs_ctime; +- stbuf->st_ctim.tv_nsec = nfs_st.nfs_ctime_nsec; +- +- return ret; +-} +- +-static int fuse_nfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, +- off_t offset, struct fuse_file_info *fi) +-{ +- struct nfsdir *nfsdir; +- struct nfsdirent *nfsdirent; +- +- int ret = 0; +- +- ret = nfs_opendir(nfs, path, &nfsdir); +- if (ret < 0) { +- return ret; +- } +- while ((nfsdirent = nfs_readdir(nfs, nfsdir)) != NULL) { +- filler(buf, nfsdirent->name, NULL, 0); +- } +- +- return ret; +-} +- +-static int fuse_nfs_readlink(const char *path, char *buf, size_t size) +-{ +- return nfs_readlink(nfs, path, buf, size); +-} +- +-static int fuse_nfs_open(const char *path, struct fuse_file_info *fi) +-{ +- int ret = 0; +- struct nfsfh *nfsfh; +- +- fi->fh = 0; +- ret = nfs_open(nfs, path, fi->flags, &nfsfh); +- if (ret < 0) { +- return ret; +- } +- +- fi->fh = (uint64_t)nfsfh; +- +- return ret; +-} +- +-static int fuse_nfs_release(const char *path, struct fuse_file_info *fi) +-{ +- struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; +- +- nfs_close(nfs, nfsfh); +- return 0; +-} +- +-static int fuse_nfs_read(const char *path, char *buf, size_t size, +- off_t offset, struct fuse_file_info *fi) +-{ +- int ret = 0; +- struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; +- +- ret = nfs_pread(nfs, nfsfh, offset, size, buf); +- +- return ret; +-} +- +-static int fuse_nfs_write(const char *path, const char *buf, size_t size, +- off_t offset, struct fuse_file_info *fi) +-{ +- int ret = 0; +- struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; +- +- ret = nfs_pwrite(nfs, nfsfh, offset, size, discard_const(buf)); +- +- return ret; +-} +- +-static int fuse_nfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) +-{ +- int ret = 0; +- struct nfsfh *nfsfh; +- +- ret = nfs_creat(nfs, path, mode, &nfsfh); +- if (ret < 0) { +- return ret; +- } +- +- fi->fh = (uint64_t)nfsfh; +- +- return ret; +-} +- +-static int fuse_nfs_utime(const char *path, struct utimbuf *times) +-{ +- int ret = 0; +- +- ret = nfs_utime(nfs, path, times); +- if (ret < 0) { +- return ret; +- } +- +- return ret; +-} +- +-static int fuse_nfs_unlink(const char *path) +-{ +- int ret = 0; +- +- ret = nfs_unlink(nfs, path); +- if (ret < 0) { +- return ret; +- } +- +- return ret; +-} +- +-static int fuse_nfs_rmdir(const char *path) +-{ +- int ret = 0; +- +- ret = nfs_rmdir(nfs, path); +- if (ret < 0) { +- return ret; +- } +- +- return ret; +-} +- +-static int fuse_nfs_mkdir(const char *path, mode_t mode) +-{ +- int ret = 0; +- +- ret = nfs_mkdir(nfs, path); +- if (ret < 0) { +- return ret; +- } +- ret = nfs_chmod(nfs, path, mode); +- if (ret < 0) { +- return ret; +- } +- +- return ret; +-} +- +-static int fuse_nfs_mknod(const char *path, mode_t mode, dev_t rdev) +-{ +- return nfs_mknod(nfs, path, mode, rdev); +-} +- +-static int fuse_nfs_symlink(const char *from, const char *to) +-{ +- return nfs_symlink(nfs, from, to); +-} +- +-static int fuse_nfs_rename(const char *from, const char *to) +-{ +- return nfs_rename(nfs, from, to); +-} +- +-static int fuse_nfs_link(const char *from, const char *to) +-{ +- return nfs_link(nfs, from, to); +-} +- +-static int fuse_nfs_chmod(const char *path, mode_t mode) +-{ +- return nfs_chmod(nfs, path, mode); +-} +- +-static int fuse_nfs_chown(const char *path, uid_t uid, gid_t gid) +-{ +- return nfs_chown(nfs, path, uid, gid); +-} +- +-static int fuse_nfs_truncate(const char *path, off_t size) +-{ +- return nfs_truncate(nfs, path, size); +-} +- +-static int fuse_nfs_fsync(const char *path, int isdatasync, +- struct fuse_file_info *fi) +-{ +- struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; +- +- return nfs_fsync(nfs, nfsfh); +-} +- +-static struct fuse_operations nfs_oper = { +- .chmod = fuse_nfs_chmod, +- .chown = fuse_nfs_chown, +- .create = fuse_nfs_create, +- .fsync = fuse_nfs_fsync, +- .getattr = fuse_nfs_getattr, +- .link = fuse_nfs_link, +- .mkdir = fuse_nfs_mkdir, +- .mknod = fuse_nfs_mknod, +- .open = fuse_nfs_open, +- .read = fuse_nfs_read, +- .readdir = fuse_nfs_readdir, +- .readlink = fuse_nfs_readlink, +- .release = fuse_nfs_release, +- .rmdir = fuse_nfs_rmdir, +- .unlink = fuse_nfs_unlink, +- .utime = fuse_nfs_utime, +- .rename = fuse_nfs_rename, +- .symlink = fuse_nfs_symlink, +- .truncate = fuse_nfs_truncate, +- .write = fuse_nfs_write, +-}; +- +-void print_usage(char *name) +-{ +- printf("Usage: %s [-?|--help] [-n|--nfs-share=nfs-url] [-m|--mountpoint=mountpoint]\n", +- name); +- exit(0); +-} +- +-int main(int argc, char *argv[]) +-{ +- int ret = 0; +- static struct option long_opts[] = { +- { "help", no_argument, 0, '?' }, +- { "nfs-share", required_argument, 0, 'n' }, +- { "mountpoint", required_argument, 0, 'm' }, +- { NULL, 0, 0, 0 } +- }; +- int c; +- int opt_idx = 0; +- char *url = NULL; +- char *mnt = NULL; +- char *server = NULL, *export = NULL, *strp; +- int fuse_nfs_argc = 6; +- char *fuse_nfs_argv[16] = { +- "fuse-nfs", +- "", +- "-oallow_other", +- "-odefault_permissions", +- "-omax_write=32768", +- "-s", +- NULL, +- NULL, +- NULL, +- NULL, +- NULL, +- NULL, +- NULL, +- NULL, +- NULL, +- NULL, +- }; +- +- while ((c = getopt_long(argc, argv, "?hm:n:", long_opts, +- &opt_idx)) > 0) { +- switch (c) { +- case 'h': +- case '?': +- print_usage(argv[0]); +- return 0; +- case 'm': +- mnt = strdup(optarg); +- break; +- case 'n': +- url = strdup(optarg); +- break; +- } +- } +- +- if (url == NULL) { +- fprintf(stderr, "-n was not specified.\n"); +- print_usage(argv[0]); +- ret = 10; +- goto finished; +- } +- if (mnt == NULL) { +- fprintf(stderr, "-m was not specified.\n"); +- print_usage(argv[0]); +- ret = 10; +- goto finished; +- } +- +- +- if (strncmp(url, "nfs://", 6)) { +- fprintf(stderr, "Invalid URL specified.\n"); +- ret = 10; +- goto finished; +- } +- server = strdup(url + 6); +- if (server == NULL) { +- fprintf(stderr, "Failed to strdup server string\n"); +- ret = 10; +- goto finished; +- } +- if (server[0] == '/' || server[0] == '\0') { +- fprintf(stderr, "Invalid server string.\n"); +- ret = 10; +- goto finished; +- } +- strp = strchr(server, '/'); +- if (strp == NULL) { +- fprintf(stderr, "Invalid URL specified.\n"); +- ret = 10; +- goto finished; +- } +- export = strdup(strp); +- if (export == NULL) { +- fprintf(stderr, "Failed to strdup server string\n"); +- ret = 10; +- goto finished; +- } +- if (export[0] != '/') { +- fprintf(stderr, "Invalid export.\n"); +- ret = 10; +- goto finished; +- } +- *strp = 0; +- +- nfs = nfs_init_context(); +- if (nfs == NULL) { +- printf("failed to init context\n"); +- goto finished; +- } +- +- ret = nfs_mount(nfs, server, export); +- if (ret != 0) { +- printf("Failed to mount nfs share : %s\n", nfs_get_error(nfs)); +- goto finished; +- } +- +- +- fuse_nfs_argv[1] = mnt; +- return fuse_main(fuse_nfs_argc, fuse_nfs_argv, &nfs_oper, NULL); +- +-finished: +- if (nfs != NULL) { +- nfs_destroy_context(nfs); +- } +- free(server); +- free(export); +- free(url); +- free(mnt); +- return ret; +-}