1 /* usmb - mount SMB shares via FUSE and Samba
2 * Copyright (C) 2006-2009 Geoff Johnstone
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <sys/time.h> // struct timeval needed by libsmbclient.h
19 #include <libsmbclient.h>
20 #include "samba3x-compat.h"
30 #include "usmb_file.h"
35 // Samba gets st_nlink wrong for directories.
36 static bool fix_nlink (const char *url
, struct stat
*st
)
41 if (!S_ISDIR (st
->st_mode
))
44 SMBCFILE
*file
= smbc_getFunctionOpendir (ctx
) (ctx
, url
);
52 struct smbc_dirent
*dirent
;
54 while (NULL
!= (dirent
= smbc_getFunctionReaddir (ctx
) (ctx
, file
)))
55 if (SMBC_DIR
== dirent
->smbc_type
)
56 if (INT_MAX
== st
->st_nlink
++)
59 (void)smbc_getFunctionClosedir (ctx
) (ctx
, file
);
60 return (NULL
== dirent
);
64 int usmb_getattr (const char *filename
, struct stat
*st
)
66 char *url
= make_url (filename
);
70 DEBUG (fprintf (stderr
, "stat (%s)\n", url
));
72 int ret
= smbc_getFunctionStat (ctx
) (ctx
, url
, st
);
74 if ((0 > ret
) || !fix_nlink (url
, st
))
82 int usmb_fgetattr (const char *filename UNUSED
, struct stat
*st
,
83 struct fuse_file_info
*fi
)
85 SMBCFILE
*file
= fd_to_smbcfile (fi
->fh
);
86 DEBUG (fprintf (stderr
, "fgetattr (%s, %p)\n", filename
, (void *)file
));
88 if (0 > smbc_getFunctionFstat (ctx
) (ctx
, file
, st
))
91 if (S_ISDIR (st
->st_mode
))
93 char *url
= make_url (filename
);
97 bool ok
= fix_nlink (url
, st
);
108 int usmb_unlink (const char *filename
)
110 char *url
= make_url (filename
);
114 DEBUG (fprintf (stderr
, "unlink (%s)\n", url
));
115 int ret
= (0 > smbc_getFunctionUnlink (ctx
) (ctx
, url
)) ? -errno
: 0;
121 int usmb_open (const char *filename
, struct fuse_file_info
*fi
)
123 char *url
= make_url (filename
);
127 DEBUG (fprintf (stderr
, "open (%s, %d)", url
, fi
->flags
));
128 SMBCFILE
*file
= smbc_getFunctionOpen (ctx
) (ctx
, url
, fi
->flags
, 0);
129 DEBUG (fprintf (stderr
, " = %p\n", (void *)file
));
131 int ret
= (NULL
== file
) ? -errno
: 0;
133 fi
->fh
= smbcfile_to_fd (file
);
139 int usmb_release (const char *filename UNUSED
, struct fuse_file_info
*fi
)
141 SMBCFILE
*file
= fd_to_smbcfile (fi
->fh
);
142 DEBUG (fprintf (stderr
, "release (%s, %p)\n", filename
, (void *)file
));
143 return (0 > smbc_getFunctionClose (ctx
) (ctx
, file
)) ? -errno
: 0;
147 int usmb_read (const char *filename UNUSED
, char *buff
, size_t len
, off_t off
,
148 struct fuse_file_info
*fi
)
150 assert (32768 >= len
);
152 SMBCFILE
*file
= fd_to_smbcfile (fi
->fh
);
153 DEBUG (fprintf (stderr
, "read (%p, %p, %llu, %lld) ",
154 (void *)file
, buff
, (unsigned long long)len
, (long long)off
));
156 if (0 > smbc_getFunctionLseek (ctx
) (ctx
, file
, off
, SEEK_SET
))
158 fprintf (stderr
, "- seek failed: %d\n", -errno
);
162 int bytes
= smbc_getFunctionRead (ctx
) (ctx
, file
, buff
, len
);
163 DEBUG (fprintf (stderr
, "= %d\n", bytes
));
164 return (0 > bytes
) ? -errno
: (int)bytes
;
168 int usmb_write (const char *filename UNUSED
, const char *buff
, size_t len
,
169 off_t off
, struct fuse_file_info
*fi
)
171 SMBCFILE
*file
= fd_to_smbcfile (fi
->fh
);
172 DEBUG (fprintf (stderr
, "write (%p, %p, len=%llu, off=%lld) ",
173 (void *)file
, buff
, (unsigned long long)len
, (long long)off
));
175 if (0 > smbc_getFunctionLseek (ctx
) (ctx
, file
, off
, SEEK_SET
))
181 // No idea whether Windows servers don't like > 32768 byte writes
182 // (cf. usmb_read), but taking no chances...
184 const smbc_write_fn write_fn
= smbc_getFunctionWrite (ctx
);
186 while (written
< len
)
188 bytes
= write_fn (ctx
, file
, (char *)buff
, (len
> 32768) ? 32768 : len
);
195 // avoids infinite loops
200 DEBUG (fprintf (stderr
, "= %d\n", (0 > bytes
) ? -errno
: (int)written
));
201 return (0 > bytes
) ? -errno
: (int)written
;
205 int usmb_create (const char *filename
, mode_t mode
, struct fuse_file_info
*fi
)
207 char *url
= make_url (filename
);
211 DEBUG (fprintf (stderr
, "creat (%s)", url
));
213 SMBCFILE
*file
= smbc_getFunctionCreat (ctx
) (ctx
, url
, mode
);
214 DEBUG (fprintf (stderr
, " = %p\n", (void *)file
));
215 int ret
= (NULL
== file
) ? -errno
: 0;
216 fi
->fh
= smbcfile_to_fd (file
);
223 int usmb_rename (const char *from
, const char *to
)
225 char *fromurl
= make_url (from
);
229 char *tourl
= make_url (to
);
236 DEBUG (fprintf (stderr
, "rename (%s, %s)\n", fromurl
, tourl
));
238 (0 > smbc_getFunctionRename (ctx
) (ctx
, fromurl
, ctx
, tourl
)) ? -errno
: 0;
245 int usmb_utime (const char *filename
, struct utimbuf
*utb
)
247 struct utimbuf tmp_utb
;
253 time_t now
= time (NULL
);
254 if ((time_t)-1 != now
)
256 tmp_utb
.actime
= tmp_utb
.modtime
= now
;
267 char *url
= make_url (filename
);
271 struct timeval tv
[2] = {
272 { .tv_sec
= utb
->actime
, .tv_usec
= 0 },
273 { .tv_sec
= utb
->modtime
, .tv_usec
= 0 },
276 DEBUG (fprintf (stderr
, "utime (%s)\n", url
));
277 int ret
= (0 > smbc_getFunctionUtimes (ctx
) (ctx
, url
, tv
)) ? -errno
: 0;
284 Samba defines utimes as taking
struct timevals rather than timespecs
.
285 int usmb_utimes (const char *filename
, const struct timespec ts
[2])
287 char *url
= make_url (filename
);
291 DEBUG (fprintf (stderr
, "utimes (%s)\n", url
));
292 int ret
= (0 > ctx
->utimes (ctx
, url
, ts
)) ? -errno
: 0;
299 int usmb_chmod (const char *filename
, mode_t mode
)
301 char *url
= make_url (filename
);
305 DEBUG (fprintf (stderr
, "chmod (%s, %u)\n", url
, mode
));
306 int ret
= (0 > smbc_getFunctionChmod (ctx
) (ctx
, url
, mode
)) ? -errno
: 0;
312 int usmb_truncate (const char *filename
, off_t offset
)
314 char *url
= make_url (filename
);
318 SMBCFILE
*file
= smbc_getFunctionOpen (ctx
) (ctx
, url
, O_WRONLY
, 0);
326 int ret
= compat_truncate (filename
, file
, offset
);
328 smbc_getFunctionClose (ctx
) (ctx
, file
);
334 int usmb_ftruncate (const char *path
, off_t size
,
335 struct fuse_file_info
*fi
)
337 return compat_truncate (path
, fd_to_smbcfile (fi
->fh
), size
);