2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "realcalls.h"
27 static struct smbw_file *smbw_files;
28 static struct smbw_server *smbw_srvs;
30 struct bitmap *smbw_file_bmap;
31 extern pstring global_myname;
32 extern int DEBUGLEVEL;
34 fstring smbw_prefix = SMBW_PREFIX;
38 /* needs to be here because of dumb include files on some systems */
39 int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
41 /*****************************************************
43 *******************************************************/
46 extern BOOL in_client;
47 static int initialised;
48 static pstring servicesf = CONFIGFILE;
53 if (initialised) return;
61 setup_logging("smbw",True);
65 if ((p=getenv("SMBW_LOGFILE"))) {
69 smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
70 if (!smbw_file_bmap) {
80 lp_load(servicesf,True,False,False);
82 get_myname(global_myname,NULL);
84 if ((p=getenv("SMBW_DEBUG"))) {
88 if ((p=getenv("SMBW_PREFIX"))) {
89 slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p);
90 string_sub(smbw_prefix,"//", "/");
91 DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
94 if ((p=getenv(SMBW_PWD_ENV))) {
96 DEBUG(4,("Initial cwd from smbw_cwd is %s\n", smbw_cwd));
99 DEBUG(4,("Initial cwd from getwd is %s\n", smbw_cwd));
108 /*****************************************************
109 determine if a file descriptor is a smb one
110 *******************************************************/
113 if (smbw_busy) return 0;
114 return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
117 /*****************************************************
118 a crude inode number generator
119 *******************************************************/
120 ino_t smbw_inode(const char *name)
122 return (ino_t)str_checksum(name);
125 /*****************************************************
126 remove redundent stuff from a filename
127 *******************************************************/
128 void clean_fname(char *name)
139 DEBUG(5,("cleaning %s\n", name));
141 if ((p=strstr(name,"/./"))) {
149 if ((p=strstr(name,"//"))) {
157 if (strcmp(name,"/../")==0) {
162 if ((p=strstr(name,"/../"))) {
164 for (p2=(p>name?p-1:p);p2>name;p2--) {
165 if (p2[0] == '/') break;
173 if (strcmp(name,"/..")==0) {
179 p = l>=3?(name+l-3):name;
180 if (strcmp(p,"/..")==0) {
182 for (p2=p-1;p2>name;p2--) {
183 if (p2[0] == '/') break;
194 p = l>=2?(name+l-2):name;
195 if (strcmp(p,"/.")==0) {
203 if (strncmp(p=name,"./",2) == 0) {
211 if (l > 1 && p[l-1] == '/') {
219 /*****************************************************
220 parse a smb path into its components.
221 *******************************************************/
222 char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
226 int len = strlen(smbw_prefix)-1;
228 *server = *share = *path = 0;
230 if (fname[0] == '/') {
233 slprintf(s,sizeof(s)-1, "%s/%s", smbw_cwd, fname);
237 DEBUG(5,("cleaned %s (fname=%s cwd=%s)\n",
238 s, fname, smbw_cwd));
240 if (strncmp(s,smbw_prefix,len) ||
241 (s[len] != '/' && s[len] != 0)) return s;
254 len = MIN(len,sizeof(fstring)-1);
256 strncpy(server, p, len);
262 char *workgroup = getenv("SMBW_WORKGROUP");
263 if (!workgroup) workgroup = lp_workgroup();
264 slprintf(server,sizeof(fstring)-1, "%s#1D", workgroup);
266 fstrcpy(share,"IPC$");
280 len = MIN(len,sizeof(fstring)-1);
282 strncpy(share, p, len);
293 string_sub(path, "/", "\\");
296 DEBUG(5,("parsed path name=%s cwd=%s [%s] [%s] [%s]\n",
298 server, share, path));
303 /*****************************************************
304 determine if a path name (possibly relative) is in the
306 *******************************************************/
307 int smbw_path(const char *path)
309 fstring server, share;
316 len = strlen(smbw_prefix)-1;
318 if (path[0] == '/' && strncmp(path,smbw_prefix,len)) {
322 if (smbw_busy) return 0;
324 DEBUG(3,("smbw_path(%s)\n", path));
326 cwd = smbw_parse_path(path, server, share, s);
328 if (strncmp(cwd,smbw_prefix,len) == 0 &&
329 (cwd[len] == '/' || cwd[len] == 0)) {
336 /*****************************************************
337 return a unix errno from a SMB error pair
338 *******************************************************/
339 int smbw_errno(struct cli_state *c)
345 ret = cli_error(c, &eclass, &ecode);
348 DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n",
349 (int)eclass, (int)ecode, (int)ecode, ret));
354 /*****************************************************
355 return a connection to a server (existing or new)
356 *******************************************************/
357 struct smbw_server *smbw_server(char *server, char *share)
359 struct smbw_server *srv=NULL;
364 struct nmb_name called, calling;
365 char *p, *server_n = server;
370 username = getenv("SMBW_USER");
371 if (!username) username = getenv("USER");
372 if (!username) username = "guest";
374 workgroup = getenv("SMBW_WORKGROUP");
375 if (!workgroup) workgroup = lp_workgroup();
377 password = getenv("SMBW_PASSWORD");
378 if (!password) password = "";
380 /* try to use an existing connection */
381 for (srv=smbw_srvs;srv;srv=srv->next) {
382 if (strcmp(server,srv->server_name)==0 &&
383 strcmp(share,srv->share_name)==0) return srv;
386 if (server[0] == 0) {
391 make_nmb_name(&calling, global_myname, 0x0, "");
392 make_nmb_name(&called , server, 0x20, "");
394 DEBUG(5,("server_n=[%s] server=[%s]\n", server_n, server));
396 if ((p=strchr(server_n,'#')) && strcmp(p+1,"1D")==0) {
398 fstrcpy(group, server_n);
399 p = strchr(group,'#');
401 if (!find_master_ip(group, &ip)) {
405 fstrcpy(group, inet_ntoa(ip));
409 DEBUG(5,(" -> server_n=[%s] server=[%s]\n", server_n, server));
412 /* have to open a new connection */
413 if (!cli_initialise(&c) || !cli_connect(&c, server_n, NULL)) {
418 if (!cli_session_request(&c, &calling, &called)) {
420 if (strcmp(called.name, "*SMBSERVER")) {
421 make_nmb_name(&called , "*SMBSERVER", 0x20, "");
429 if (!cli_negprot(&c)) {
435 if (!cli_session_setup(&c, username,
436 password, strlen(password),
437 password, strlen(password),
439 /* try an anonymous login if it failed */
440 !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
446 if (!cli_send_tconX(&c, share, "?????",
447 password, strlen(password)+1)) {
448 errno = smbw_errno(&c);
453 srv = (struct smbw_server *)malloc(sizeof(*srv));
463 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
465 srv->server_name = strdup(server);
466 if (!srv->server_name) {
471 srv->share_name = strdup(share);
472 if (!srv->share_name) {
477 /* some programs play with file descriptors fairly intimately. We
478 try to get out of the way by duping to a high fd number */
479 if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
480 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
481 srv->cli.fd+SMBW_CLI_FD) {
483 srv->cli.fd += SMBW_CLI_FD;
487 DLIST_ADD(smbw_srvs, srv);
493 if (!srv) return NULL;
495 if (srv->server_name) free(srv->server_name);
496 if (srv->share_name) free(srv->share_name);
502 /*****************************************************
503 map a fd to a smbw_file structure
504 *******************************************************/
505 struct smbw_file *smbw_file(int fd)
507 struct smbw_file *file;
509 for (file=smbw_files;file;file=file->next) {
510 if (file->fd == fd) return file;
515 /*****************************************************
517 *******************************************************/
518 int smbw_open(const char *fname, int flags, mode_t mode)
520 fstring server, share;
522 struct smbw_server *srv=NULL;
524 struct smbw_file *file=NULL;
535 /* work out what server they are after */
536 smbw_parse_path(fname, server, share, path);
538 /* get a connection to the server */
539 srv = smbw_server(server, share);
541 /* smbw_server sets errno */
545 if (path[strlen(path)-1] == '\\') {
548 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
551 /* it might be a directory. Maybe we should use chkpath? */
552 eno = smbw_errno(&srv->cli);
553 fd = smbw_dir_open(fname);
554 if (fd == -1) errno = eno;
559 file = (struct smbw_file *)malloc(sizeof(*file));
567 file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
573 ZERO_STRUCTP(file->f);
575 file->f->cli_fd = fd;
576 file->f->fname = strdup(path);
577 if (!file->f->fname) {
582 file->fd = open(SMBW_DUMMY, O_WRONLY);
583 if (file->fd == -1) {
588 if (bitmap_query(smbw_file_bmap, file->fd)) {
589 DEBUG(0,("ERROR: fd used in smbw_open\n"));
594 file->f->ref_count=1;
596 bitmap_set(smbw_file_bmap, file->fd);
598 DLIST_ADD(smbw_files, file);
600 DEBUG(4,("opened %s\n", fname));
607 cli_close(&srv->cli, fd);
611 if (file->f->fname) {
612 free(file->f->fname);
623 /*****************************************************
624 a wrapper for pread()
625 *******************************************************/
626 ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
628 struct smbw_file *file;
633 file = smbw_file(fd);
640 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
643 errno = smbw_errno(&file->srv->cli);
652 /*****************************************************
654 *******************************************************/
655 ssize_t smbw_read(int fd, void *buf, size_t count)
657 struct smbw_file *file;
660 DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count));
664 file = smbw_file(fd);
671 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
672 file->f->offset, count);
675 errno = smbw_errno(&file->srv->cli);
680 file->f->offset += ret;
682 DEBUG(4,(" -> %d\n", ret));
690 /*****************************************************
691 a wrapper for write()
692 *******************************************************/
693 ssize_t smbw_write(int fd, void *buf, size_t count)
695 struct smbw_file *file;
700 file = smbw_file(fd);
702 DEBUG(3,("bad fd in read\n"));
708 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count);
711 errno = smbw_errno(&file->srv->cli);
716 file->f->offset += ret;
722 /*****************************************************
723 a wrapper for pwrite()
724 *******************************************************/
725 ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
727 struct smbw_file *file;
732 file = smbw_file(fd);
734 DEBUG(3,("bad fd in read\n"));
740 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count);
743 errno = smbw_errno(&file->srv->cli);
752 /*****************************************************
753 a wrapper for close()
754 *******************************************************/
755 int smbw_close(int fd)
757 struct smbw_file *file;
761 file = smbw_file(fd);
763 int ret = smbw_dir_close(fd);
768 if (file->f->ref_count == 1 &&
769 !cli_close(&file->srv->cli, file->f->cli_fd)) {
770 errno = smbw_errno(&file->srv->cli);
776 bitmap_clear(smbw_file_bmap, file->fd);
779 DLIST_REMOVE(smbw_files, file);
781 file->f->ref_count--;
782 if (file->f->ref_count == 0) {
783 free(file->f->fname);
795 /*****************************************************
796 a wrapper for fcntl()
797 *******************************************************/
798 int smbw_fcntl(int fd, int cmd, long arg)
804 /*****************************************************
805 a wrapper for access()
806 *******************************************************/
807 int smbw_access(const char *name, int mode)
811 DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode));
813 if (smbw_stat(name, &st)) return -1;
815 if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) ||
816 ((mode & W_OK) && !(st.st_mode & S_IWUSR)) ||
817 ((mode & X_OK) && !(st.st_mode & S_IXUSR))) {
825 /*****************************************************
826 a wrapper for realink() - needed for correct errno setting
827 *******************************************************/
828 int smbw_readlink(const char *path, char *buf, size_t bufsize)
833 ret = smbw_stat(path, &st);
835 DEBUG(4,("readlink(%s) failed\n", path));
839 /* it exists - say it isn't a link */
840 DEBUG(4,("readlink(%s) not a link\n", path));
847 /*****************************************************
848 a wrapper for unlink()
849 *******************************************************/
850 int smbw_unlink(const char *fname)
852 struct smbw_server *srv;
853 fstring server, share;
865 /* work out what server they are after */
866 smbw_parse_path(fname, server, share, path);
868 /* get a connection to the server */
869 srv = smbw_server(server, share);
871 /* smbw_server sets errno */
875 if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
876 int job = smbw_stat_printjob(srv, path, NULL, NULL);
880 if (cli_printjob_del(&srv->cli, job) != 0) {
883 } else if (!cli_unlink(&srv->cli, path)) {
884 errno = smbw_errno(&srv->cli);
897 /*****************************************************
898 a wrapper for rename()
899 *******************************************************/
900 int smbw_rename(const char *oldname, const char *newname)
902 struct smbw_server *srv;
903 fstring server1, share1;
905 fstring server2, share2;
908 if (!oldname || !newname) {
915 DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname));
919 /* work out what server they are after */
920 smbw_parse_path(oldname, server1, share1, path1);
921 smbw_parse_path(newname, server2, share2, path2);
923 if (strcmp(server1, server2) || strcmp(share1, share2)) {
924 /* can't cross filesystems */
929 /* get a connection to the server */
930 srv = smbw_server(server1, share1);
932 /* smbw_server sets errno */
936 if (!cli_rename(&srv->cli, path1, path2)) {
937 int eno = smbw_errno(&srv->cli);
939 !cli_unlink(&srv->cli, path2) ||
940 !cli_rename(&srv->cli, path1, path2)) {
955 /*****************************************************
956 a wrapper for utime and utimes
957 *******************************************************/
958 static int smbw_settime(const char *fname, time_t t)
960 struct smbw_server *srv;
961 fstring server, share;
974 /* work out what server they are after */
975 smbw_parse_path(fname, server, share, path);
977 /* get a connection to the server */
978 srv = smbw_server(server, share);
980 /* smbw_server sets errno */
984 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
985 errno = smbw_errno(&srv->cli);
989 if (!cli_setatr(&srv->cli, path, mode, t)) {
990 /* some servers always refuse directory changes */
991 if (!(mode & aDIR)) {
992 errno = smbw_errno(&srv->cli);
1005 /*****************************************************
1007 *******************************************************/
1008 int smbw_utime(const char *fname, void *buf)
1010 struct utimbuf *tbuf = (struct utimbuf *)buf;
1011 return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
1014 /*****************************************************
1016 *******************************************************/
1017 int smbw_utimes(const char *fname, void *buf)
1019 struct timeval *tbuf = (struct timeval *)buf;
1020 return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
1024 /*****************************************************
1025 a wrapper for chown()
1026 *******************************************************/
1027 int smbw_chown(const char *fname, uid_t owner, gid_t group)
1029 struct smbw_server *srv;
1030 fstring server, share;
1043 /* work out what server they are after */
1044 smbw_parse_path(fname, server, share, path);
1046 /* get a connection to the server */
1047 srv = smbw_server(server, share);
1049 /* smbw_server sets errno */
1053 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1054 errno = smbw_errno(&srv->cli);
1058 /* assume success */
1068 /*****************************************************
1069 a wrapper for chmod()
1070 *******************************************************/
1071 int smbw_chmod(const char *fname, mode_t newmode)
1073 struct smbw_server *srv;
1074 fstring server, share;
1087 /* work out what server they are after */
1088 smbw_parse_path(fname, server, share, path);
1090 /* get a connection to the server */
1091 srv = smbw_server(server, share);
1093 /* smbw_server sets errno */
1099 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1100 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1101 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1102 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1104 if (!cli_setatr(&srv->cli, path, mode, 0)) {
1105 errno = smbw_errno(&srv->cli);
1117 /*****************************************************
1118 a wrapper for lseek()
1119 *******************************************************/
1120 off_t smbw_lseek(int fd, off_t offset, int whence)
1122 struct smbw_file *file;
1127 file = smbw_file(fd);
1129 off_t ret = smbw_dir_lseek(fd, offset, whence);
1136 file->f->offset = offset;
1139 file->f->offset += offset;
1142 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1143 NULL, &size, NULL, NULL, NULL) &&
1144 !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1145 NULL, &size, NULL, NULL, NULL)) {
1150 file->f->offset = size + offset;
1155 return file->f->offset;
1159 /*****************************************************
1161 *******************************************************/
1162 int smbw_dup(int fd)
1165 struct smbw_file *file, *file2;
1169 file = smbw_file(fd);
1175 fd2 = dup(file->fd);
1180 if (bitmap_query(smbw_file_bmap, fd2)) {
1181 DEBUG(0,("ERROR: fd already open in dup!\n"));
1186 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1193 ZERO_STRUCTP(file2);
1198 file->f->ref_count++;
1200 bitmap_set(smbw_file_bmap, fd2);
1202 DLIST_ADD(smbw_files, file2);
1213 /*****************************************************
1214 a wrapper for dup2()
1215 *******************************************************/
1216 int smbw_dup2(int fd, int fd2)
1218 struct smbw_file *file, *file2;
1222 file = smbw_file(fd);
1228 if (bitmap_query(smbw_file_bmap, fd2)) {
1229 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1234 if (dup2(file->fd, fd2) != fd2) {
1238 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1245 ZERO_STRUCTP(file2);
1250 file->f->ref_count++;
1252 bitmap_set(smbw_file_bmap, fd2);
1254 DLIST_ADD(smbw_files, file2);
1265 /*****************************************************
1266 close a connection to a server
1267 *******************************************************/
1268 static void smbw_srv_close(struct smbw_server *srv)
1272 cli_shutdown(&srv->cli);
1274 free(srv->server_name);
1275 free(srv->share_name);
1277 DLIST_REMOVE(smbw_srvs, srv);
1286 /*****************************************************
1287 when we fork we have to close all connections and files
1289 *******************************************************/
1296 struct smbw_file *file, *next_file;
1297 struct smbw_server *srv, *next_srv;
1299 if (pipe(p)) return real_fork();
1301 child = real_fork();
1304 /* block the parent for a moment until the sockets are
1314 /* close all files */
1315 for (file=smbw_files;file;file=next_file) {
1316 next_file = file->next;
1320 /* close all server connections */
1321 for (srv=smbw_srvs;srv;srv=next_srv) {
1322 next_srv = srv->next;
1323 smbw_srv_close(srv);
1326 /* unblock the parent */
1330 /* and continue in the child */
1334 #ifndef NO_ACL_WRAPPER
1335 /*****************************************************
1337 *******************************************************/
1338 int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
1340 if (cmd == GETACL || cmd == GETACLCNT) return 0;
1346 #ifndef NO_FACL_WRAPPER
1347 /*****************************************************
1349 *******************************************************/
1350 int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
1352 if (cmd == GETACL || cmd == GETACLCNT) return 0;
1360 /* this can't be in wrapped.c because of include conflicts */
1361 void stat64_convert(struct stat *st, struct stat64 *st64)
1363 st64->st_size = st->st_size;
1364 st64->st_mode = st->st_mode;
1365 st64->st_ino = st->st_ino;
1366 st64->st_dev = st->st_dev;
1367 st64->st_rdev = st->st_rdev;
1368 st64->st_nlink = st->st_nlink;
1369 st64->st_uid = st->st_uid;
1370 st64->st_gid = st->st_gid;
1371 st64->st_atime = st->st_atime;
1372 st64->st_mtime = st->st_mtime;
1373 st64->st_ctime = st->st_ctime;
1374 st64->st_blksize = st->st_blksize;
1375 st64->st_blocks = st->st_blocks;
1379 #ifdef HAVE_READDIR64
1380 void dirent64_convert(struct dirent *d, struct dirent64 *d64)
1382 d64->d_ino = d->d_ino;
1383 d64->d_off = d->d_off;
1384 d64->d_reclen = d->d_reclen;
1385 pstrcpy(d64->d_name, d->d_name);
1391 /* Definition of `struct stat' used in the linux kernel.. */
1392 struct kernel_stat {
1393 unsigned short int st_dev;
1394 unsigned short int __pad1;
1395 unsigned long int st_ino;
1396 unsigned short int st_mode;
1397 unsigned short int st_nlink;
1398 unsigned short int st_uid;
1399 unsigned short int st_gid;
1400 unsigned short int st_rdev;
1401 unsigned short int __pad2;
1402 unsigned long int st_size;
1403 unsigned long int st_blksize;
1404 unsigned long int st_blocks;
1405 unsigned long int st_atime;
1406 unsigned long int __unused1;
1407 unsigned long int st_mtime;
1408 unsigned long int __unused2;
1409 unsigned long int st_ctime;
1410 unsigned long int __unused3;
1411 unsigned long int __unused4;
1412 unsigned long int __unused5;
1415 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf)
1417 if (vers == _STAT_VER_LINUX_OLD) {
1418 memcpy(st, kbuf, sizeof(*st));
1424 st->st_dev = kbuf->st_dev;
1425 st->st_ino = kbuf->st_ino;
1426 st->st_mode = kbuf->st_mode;
1427 st->st_nlink = kbuf->st_nlink;
1428 st->st_uid = kbuf->st_uid;
1429 st->st_gid = kbuf->st_gid;
1430 st->st_rdev = kbuf->st_rdev;
1431 st->st_size = kbuf->st_size;
1432 st->st_blksize = kbuf->st_blksize;
1433 st->st_blocks = kbuf->st_blocks;
1434 st->st_atime = kbuf->st_atime;
1435 st->st_mtime = kbuf->st_mtime;
1436 st->st_ctime = kbuf->st_ctime;